diff --git a/src/components/Card/Card.jsx b/src/components/Card/Card.jsx index 26cf3cded4..26900778a3 100644 --- a/src/components/Card/Card.jsx +++ b/src/components/Card/Card.jsx @@ -35,6 +35,7 @@ const OptimizedSkeletonText = React.memo(SkeletonText); /** Full card */ const CardWrapper = ({ + isSelected, children, dimensions, id, @@ -54,6 +55,7 @@ const CardWrapper = ({ ...others }) => { const validOthers = filterValidAttributes(others); + return (
{children}
@@ -114,6 +118,10 @@ const EmptyMessageWrapper = (props) => { }; CardWrapper.propTypes = { + /** + * Is given the event as argument. Should return true or false if event should trigger selection + */ + isSelected: PropTypes.bool, children: PropTypes.node.isRequired, dimensions: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }) .isRequired, @@ -131,6 +139,7 @@ CardWrapper.propTypes = { tabIndex: PropTypes.number, }; CardWrapper.defaultProps = { + isSelected: false, id: undefined, style: undefined, testID: 'Card', diff --git a/src/components/Card/Card.story.jsx b/src/components/Card/Card.story.jsx index 8821d4b73c..deccb8e21f 100644 --- a/src/components/Card/Card.story.jsx +++ b/src/components/Card/Card.story.jsx @@ -40,26 +40,44 @@ export default { }; export const Basic = () => { - const size = select('size', Object.keys(CARD_SIZES), CARD_SIZES.MEDIUM); - return ( -
- -
- ); + const StatefulExample = () => { + const [selected, setSelected] = React.useState(false); + const size = select('size', Object.keys(CARD_SIZES), CARD_SIZES.MEDIUM); + const handleClick = () => { + setSelected(true); + }; + const handleBlur = (e) => { + if ( + !e.currentTarget.contains(e.relatedTarget) || + (e.target === e.currentTarget && e.relatedTarget === null) + ) { + setSelected(false); + } + action('onBlur'); + }; + return ( +
+ +
+ ); + }; + return ; }; Basic.story = { @@ -445,11 +463,11 @@ ImplementingACustomCard.story = { - If you want to hide the title/toolbar, do not pass a title prop - (Optionally, if you want to use the card in a Dashboard) Extend the Card Renderer so the Dashboard knows how to render your card type - (Optionally, if you want to use the card in a Dashboard) Create a validator for this card type within "utils/schemas/validators" and add it to the validateDashboardJSON function used to validate dashboards on import. - + ## Data flow for a card in the dashboard All data loading for a card goes through the dashboard's onFetchData function. There are two ways to trigger a refetch of data for a card. The first is to directly interact with the Card's range controls. The second is for the Dashboard to trigger that all of the cards need a reload by updating it's isLoading bit. The CardRenderer component will call the onSetupCard function of the dashboard first - for each card (if it exists), then will call the onFetchData function for the dashboard. + for each card (if it exists), then will call the onFetchData function for the dashboard. `, }, }, diff --git a/src/components/Card/__snapshots__/Card.story.storyshot b/src/components/Card/__snapshots__/Card.story.storyshot index 4f701131ff..8dc9069669 100644 --- a/src/components/Card/__snapshots__/Card.story.storyshot +++ b/src/components/Card/__snapshots__/Card.story.storyshot @@ -25,6 +25,7 @@ exports[`Storybook Snapshot tests and console checks Storyshots Watson IoT/Card data-testid="Card" id="facilitycard-basic" onBlur={[Function]} + onClick={[Function]} onFocus={[Function]} role="presentation" style={ diff --git a/src/components/Card/_card.scss b/src/components/Card/_card.scss index 1a900b5459..34280c8ca1 100644 --- a/src/components/Card/_card.scss +++ b/src/components/Card/_card.scss @@ -8,22 +8,26 @@ $iot-header-padding: $spacing-05; .#{$iot-prefix}--card--wrapper { background: white; + border: solid $spacing-01 transparent; height: var(--card-default-height); display: flex; flex-direction: column; overflow: hidden; + + &__selected { + border: solid $spacing-01 $interactive-02; + box-sizing: content-box; + } } .#{$iot-prefix}--card__selected { border: $spacing-01 solid $interactive-02; box-sizing: content-box; - margin: -$spacing-01; } .#{$iot-prefix}--card--resizing { border: $spacing-01 solid $interactive-02; box-sizing: content-box; - margin: -$spacing-01; } .#{$iot-prefix}--card--title {