diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 01c63d6419..bfd31c15eb 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -66,5 +66,17 @@ export const parameters = { ...createPaperReleaseConfig('1.2'), ...createPaperReleaseConfig('1.1'), ...createPaperReleaseConfig('1.0'), + implementationExample: { + styles: { + backgroundColor: '#ffffff', + borderColor: '#000000', + color: '#000000', + }, + title: 'Implementation Example', + tooltip: { + title: `About Implementation Examples`, + desc: 'Implementation examples show how you might combine existing EDS components to create custom recipes.', + }, + }, }, }; diff --git a/.storybook/recipes/Filters/Filters.stories.tsx b/.storybook/recipes/Filters/Filters.stories.tsx deleted file mode 100644 index 4528ce9b82..0000000000 --- a/.storybook/recipes/Filters/Filters.stories.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { StoryObj, Meta } from '@storybook/react'; -import React from 'react'; -import { Filters } from './Filters'; - -export default { - title: 'Recipes/Filters', - component: Filters, - decorators: [ - (Story) => ( -
-

Filters are popover when larger screen size and drawer when not

- {Story()} -
- ), - ], -} as Meta; - -type Args = React.ComponentProps; - -export const Default: StoryObj = {}; diff --git a/.storybook/recipes/Filters/index.ts b/.storybook/recipes/Filters/index.ts deleted file mode 100644 index 0c494b93ff..0000000000 --- a/.storybook/recipes/Filters/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { Filters as default } from './Filters'; diff --git a/.storybook/recipes/LoadingProfileCard.stories.tsx b/.storybook/recipes/LoadingProfileCard.stories.tsx deleted file mode 100644 index 2ad3a18ca9..0000000000 --- a/.storybook/recipes/LoadingProfileCard.stories.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import type { StoryObj, Meta } from '@storybook/react'; -import React from 'react'; -import { Avatar, Card, Hr, Skeleton, Text } from '../../src'; - -export default { - title: 'Recipes/LoadingProfileCard', - component: Card, - decorators: [(Story) =>
{Story()}
], - args: { - isLoading: false, - className: 'm-2 p-3', - }, - render: ({ isLoading, ...cardProps }) => { - return ( -
- - - {isLoading && ( - <> - - -
- - - - - )} - {!isLoading && ( - <> - - - Example Job Title - - - Example Company Name - -
- - Lorem ipsum dolor sit amet consectetur adipisicing elit. - Mollitia dolorem doloribus laudantium magnam. Laboriosam! - - - Lorem ipsum dolor sit amet consectetur adipisicing elit. - - - Lorem ipsum dolor sit amet. - - - )} -
-
-
- ); - }, -} as Meta; - -type Args = React.ComponentProps & { - isLoading: boolean; -}; - -export const Default: StoryObj = {}; - -export const Loading: StoryObj = { - args: { - isLoading: true, - }, -}; diff --git a/.storybook/recipes/MenuWithAvatarButton.stories.tsx b/.storybook/recipes/MenuWithAvatarButton.stories.tsx deleted file mode 100644 index 0e2915c0b8..0000000000 --- a/.storybook/recipes/MenuWithAvatarButton.stories.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { BADGE } from '@geometricpanda/storybook-addon-badges'; -import type { StoryObj, Meta } from '@storybook/react'; -import { userEvent } from '@storybook/testing-library'; -import React from 'react'; - -import { Avatar } from '../../src'; -import { Menu } from '../../src/components/Menu/Menu'; - -export default { - title: 'Recipes/MenuWithAvatarButton', - component: Menu, - parameters: { - badges: [BADGE.BETA], - layout: 'centered', - }, - decorators: [(Story) =>
{Story()}
], - args: { - children: ( - <> - - - - - - Headless UI Docs - - - MDN: Menu - - {/* eslint-disable-next-line no-alert */} - alert('Item clicked')}> - Trigger Action - - - Not Possible (disabled) - - - - ), - }, -} as Meta; - -type Args = React.ComponentProps; - -export const WithAvatarButton: StoryObj = {}; - -export const Focused: StoryObj = { - play: () => { - userEvent.tab(); - }, -}; - -export const Opened: StoryObj = { - play: () => { - userEvent.tab(); - userEvent.keyboard(' '); - }, -}; diff --git a/.storybook/recipes/MenuWithIconButton.stories.tsx b/.storybook/recipes/MenuWithIconButton.stories.tsx deleted file mode 100644 index f246e4286f..0000000000 --- a/.storybook/recipes/MenuWithIconButton.stories.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { BADGE } from '@geometricpanda/storybook-addon-badges'; -import type { StoryObj, Meta } from '@storybook/react'; -import { userEvent } from '@storybook/testing-library'; -import React from 'react'; - -import { Icon, type IconName } from '../../src'; -import { Menu } from '../../src/components/Menu/Menu'; -import icons from '../../src/icons/spritemap'; - -export default { - title: 'Recipes/MenuWithIconButton', - component: Menu, - parameters: { - badges: [BADGE.BETA], - layout: 'centered', - }, - args: { - iconName: 'dots-vertical', - }, - argTypes: { - iconName: { - control: 'radio', - options: Object.keys(icons), - }, - }, - decorators: [(Story) =>
{Story()}
], - render: ({ iconName }) => ( - - - - - - - Headless UI Docs - - - MDN: Menu - - {/* eslint-disable-next-line no-alert */} - alert('Item clicked')}> - Trigger Action - - - Not Possible (disabled) - - - - ), -} as Meta<{ iconName: IconName }>; - -export const WithVerticalDotsButton: StoryObj = {}; - -export const Focused: StoryObj = { - play: () => { - userEvent.tab(); - }, -}; - -export const Opened: StoryObj = { - play: () => { - userEvent.tab(); - userEvent.keyboard(' '); - }, -}; diff --git a/.storybook/recipes/RaiseCardOnHover.stories.tsx b/.storybook/recipes/RaiseCardOnHover.stories.tsx deleted file mode 100644 index ca5736fc57..0000000000 --- a/.storybook/recipes/RaiseCardOnHover.stories.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import type { StoryObj, Meta } from '@storybook/react'; -import { userEvent, within } from '@storybook/testing-library'; -import React, { useState } from 'react'; -import { Card } from '../../src/'; - -export default { - title: 'Recipes/RaiseCardOnHover', - component: Card, - decorators: [(Story) =>
{Story()}
], -} as Meta; - -type Args = React.ComponentProps; - -const InteractiveCard = () => { - const [isGrabbing, setIsGrabbing] = useState(false); - const [isHovering, setIsHovering] = useState(false); - - return ( - setIsGrabbing(true)} - onMouseEnter={() => setIsHovering(true)} - onMouseLeave={() => setIsHovering(false)} - onMouseUp={() => setIsGrabbing(false)} - > - -
Card Contents
-
-
- ); -}; - -export const Default: StoryObj = { - render: (args) => , -}; - -export const OnHover: StoryObj = { - render: (args) => , - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - const cardContents = await canvas.findByText('Card Contents'); - - userEvent.hover(cardContents); - }, -}; diff --git a/.storybook/recipes/Sliders.stories.tsx b/.storybook/recipes/Sliders.stories.tsx deleted file mode 100644 index 1149300106..0000000000 --- a/.storybook/recipes/Sliders.stories.tsx +++ /dev/null @@ -1,225 +0,0 @@ -import type { StoryObj, Meta } from '@storybook/react'; -import React, { useState } from 'react'; -import { Slider, InputField, Text, Button, Label } from '../../src'; - -/** - * React is confused about what `render` is, preventing hooks: - * - `render` gets used in a hidden Story component, which follows the rules - */ -/* eslint-disable react-hooks/rules-of-hooks */ - -export default { - title: 'Recipes/Sliders', - component: Slider, - decorators: [(Story) =>
{Story()}
], - argTypes: { - fieldNote: { - type: 'string', - }, - }, -} as Meta; - -type Args = React.ComponentProps; - -const moodData = [ - { emoji: '😡', value: 0, description: 'Very Upset' }, - { emoji: '🙁', value: 25, description: 'Upset' }, - { emoji: '😐', value: 50, description: 'Neutral' }, - { emoji: '🙂', value: 75, description: 'Happy' }, - { emoji: '😍', value: 100, description: 'Very Happy' }, -]; - -export const UsingInputDisplay: StoryObj = { - parameters: { - axe: { - disabledRules: ['color-contrast'], // adding for disabled field example - }, - }, - render: ({ min = 0, max = 100, step = 1, value = 50, ...rest }) => { - const [sliderValue, setSliderValue] = useState(value); - - return ( -
- {min} - setSliderValue(Number(target.value))} - value={sliderValue} - /> - {max} - -
- ); - }, -}; - -export const UsingControlButtons: StoryObj = { - render: ({ min = 0, max = 100, step = 1, value = 50, ...rest }) => { - const [sliderValue, setSliderValue] = useState(value); - - return ( -
- - {min} - setSliderValue(Number(target.value))} - tooltip={`Slider: ${sliderValue}`} - value={sliderValue} - /> - {max} - -
- ); - }, -}; - -export const WithHighlightedContent: StoryObj = { - render: ({ min = 0, max = 100, step = 25, value = 50, ...rest }) => { - const [sliderValue, setSliderValue] = useState(value); - - return ( -
-
- mood.description)} - max={max} - min={min} - step={step} - {...rest} - onChange={({ target }) => setSliderValue(Number(target.value))} - value={sliderValue} - /> -
- {moodData.map((mood) => { - return sliderValue === mood.value && <>{mood.emoji}; - })} -
-
- - Current mood:{' '} - - {moodData.map((mood) => { - return sliderValue === mood.value && <>{mood.description}; - })} - - -
- ); - }, -}; - -export const WithVisualLabel: StoryObj = { - render: ({ min = 0, max = 100, step = 25, value = 50, ...rest }) => { - const [sliderValue, setSliderValue] = useState(value); - - return ( -
-
-
-
- ); - }, -}; - -export const WithMultipleVisualLabels: StoryObj = { - render: ({ min = 0, max = 100, step = 25, value = 50, ...rest }) => { - const [sliderValue, setSliderValue] = useState(value); - - return ( -
-
-
-
- ); - }, -}; diff --git a/.storybook/recipes/StackedCardsToTable/StackedCardsToTable.stories.tsx b/.storybook/recipes/StackedCardsToTable/StackedCardsToTable.stories.tsx deleted file mode 100644 index bbd102b3fd..0000000000 --- a/.storybook/recipes/StackedCardsToTable/StackedCardsToTable.stories.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { StoryObj, Meta } from '@storybook/react'; -import React from 'react'; -import { StackedCardsToTable } from './StackedCardsToTable'; -import { chromaticViewports } from '../../../src/util/viewports'; - -export default { - title: 'Recipes/StackedCardsToTable', - component: StackedCardsToTable, -} as Meta; - -type Args = React.ComponentProps; - -export const Default: StoryObj = { - decorators: [(Story) =>
{Story()}
], - parameters: { - chromatic: { - viewports: [ - chromaticViewports.googlePixel2, - chromaticViewports.ipadMini, - chromaticViewports.chromebook, - ], - }, - }, -}; diff --git a/.storybook/recipes/StackedCardsToTable/index.ts b/.storybook/recipes/StackedCardsToTable/index.ts deleted file mode 100644 index 3a80a53ed4..0000000000 --- a/.storybook/recipes/StackedCardsToTable/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { StackedCardsToTable as default } from './StackedCardsToTable'; diff --git a/.storybook/recipes/TabularInputs.stories.tsx b/.storybook/recipes/TabularInputs.stories.tsx deleted file mode 100644 index e3d9e81e69..0000000000 --- a/.storybook/recipes/TabularInputs.stories.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { StoryObj, Meta } from '@storybook/react'; -import React from 'react'; -import { Table, InputField, Label } from '../../src/'; - -export default { - title: 'Recipes/TabularInput', - component: Table, - decorators: [(Story) =>
{Story()}
], -} as Meta; - -type Args = React.ComponentProps; - -export const Default: StoryObj = { - render: (args) => ( - - - - Label - Field - - - - - - - - - - - -
- ), -}; diff --git a/src/components/Card/ButtonActionCalloutCard.module.css b/src/components/Card/ButtonActionCalloutCard.module.css new file mode 100644 index 0000000000..6b769f6423 --- /dev/null +++ b/src/components/Card/ButtonActionCalloutCard.module.css @@ -0,0 +1,28 @@ +@import '../../../src/design-tokens/mixins.css'; + +/*------------------------------------*\ + # BUTTON ACTION CALLOUT CARD +\*------------------------------------*/ + +/** + * Card elevated to drive attention and give an action. + */ + +/** + * Button action callout card body inner + * + * Wrapper around the description and button. + */ +.button-action-callout-card__body-inner { + display: flex; + align-items: flex-start; + flex-direction: column; + gap: var(--eds-size-2); + margin-top: var(--eds-size-half); + + @media all and (min-width: $eds-bp-md) { + flex-direction: row; + align-items: center; + justify-content: space-between; + } +} diff --git a/src/components/Card/Card.stories.tsx b/src/components/Card/Card.stories.tsx index b1f7774b39..4008de1277 100644 --- a/src/components/Card/Card.stories.tsx +++ b/src/components/Card/Card.stories.tsx @@ -1,6 +1,18 @@ import type { StoryObj, Meta } from '@storybook/react'; -import React from 'react'; +import { userEvent, within } from '@storybook/testing-library'; +import React, { useState } from 'react'; + import { Card } from './Card'; +import { Avatar } from '../Avatar/Avatar'; +import { Button } from '../Button/Button'; +import { Heading } from '../Heading/Heading'; +import { Hr } from '../Hr/Hr'; +import { InlineNotification } from '../InlineNotification/InlineNotification'; +import { Skeleton } from '../Skeleton/Skeleton'; +import { Text } from '../Text/Text'; + +import buttonActionCalloutStyles from './ButtonActionCalloutCard.module.css'; +import cardWithNotificationStyles from './CardWithNotification.module.css'; export default { title: 'Components/Card', @@ -13,7 +25,7 @@ export default { parameters: { badges: ['1.0'], }, - decorators: [(Story) =>
{Story()}
], + decorators: [(Story) =>
{Story()}
], args: { children: ( <> @@ -38,7 +50,10 @@ export default { }, } as Meta; -type Args = React.ComponentProps; +type Args = React.ComponentProps & { + // Added to support implementation example below + isLoading: boolean; +}; export const Default: StoryObj = {}; @@ -59,3 +74,181 @@ export const Dragging: StoryObj = { elevation: 'dragging', }, }; + +export const ButtonActionCalloutCard: StoryObj = { + args: { + elevation: 'raised', + }, + parameters: { + badges: ['1.0', 'implementationExample'], + }, + render: (args) => ( + + + + Do This Checkpoint + +
+ Develop the text of your Body Book, crafting evidence-supported + explanations on how the body is organized and its functions. +
+ +
+
+
+
+ ), +}; + +export const CardWithNotification: StoryObj = { + args: { + elevation: 'raised', + }, + parameters: { + badges: ['1.0', 'implementationExample'], + }, + render: (args) => ( +
+ + +
Card Header
+
+ +
Card Body
+
+ +
Card Footer
+
+
+ +
+ ), +}; + +export const LoadingProfileCard: StoryObj = { + args: { + isLoading: true, + }, + parameters: { + badges: ['1.3', 'implementationExample'], + }, + render: ({ isLoading, ...cardProps }) => { + return ( +
+ + + {isLoading && ( + <> + + +
+ + + + + )} + {!isLoading && ( + <> + + + Example Job Title + + + Example Company Name + +
+ + Lorem ipsum dolor sit amet consectetur adipisicing elit. + Mollitia dolorem doloribus laudantium magnam. Laboriosam! + + + Lorem ipsum dolor sit amet consectetur adipisicing elit. + + + Lorem ipsum dolor sit amet. + + + )} +
+
+
+ ); + }, +}; + +const InteractiveCard = () => { + const [isGrabbing, setIsGrabbing] = useState(false); + const [isHovering, setIsHovering] = useState(false); + + return ( + setIsGrabbing(true)} + onMouseEnter={() => setIsHovering(true)} + onMouseLeave={() => setIsHovering(false)} + onMouseUp={() => setIsGrabbing(false)} + > + +
Card Contents
+
+
+ ); +}; + +export const InteractiveOnHover: StoryObj = { + render: (args) => , +}; + +// Add visual regression test simulating hover +export const StaticOnHover: StoryObj = { + render: (args) => , + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const cardContents = await canvas.findByText('Card Contents'); + + userEvent.hover(cardContents); + }, +}; diff --git a/src/components/Card/CardWithNotification.module.css b/src/components/Card/CardWithNotification.module.css new file mode 100644 index 0000000000..55977448af --- /dev/null +++ b/src/components/Card/CardWithNotification.module.css @@ -0,0 +1,24 @@ +@import '../../../src/design-tokens/mixins.css'; + +/*------------------------------------*\ + # CARD WITH NOTIFICATION +\*------------------------------------*/ + +/** + * Card recipe with a bottom notification. + */ +.card-with-notification { + /** + * Add a border around the entire card and notification. + */ + border-radius: var(--eds-border-radius-md); + border: var(--eds-theme-color-border-neutral-subtle) solid + var(--eds-theme-border-width); +} +.card-with-notification__card { + /** + * Remove the redundant border that existed on the card component. + */ + border: 0; + border-radius: 0; +} diff --git a/src/components/Card/__snapshots__/Card.test.ts.snap b/src/components/Card/__snapshots__/Card.test.ts.snap index 8956d7f9e6..b2cd4c7236 100644 --- a/src/components/Card/__snapshots__/Card.test.ts.snap +++ b/src/components/Card/__snapshots__/Card.test.ts.snap @@ -1,8 +1,109 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[` ButtonActionCalloutCard story renders snapshot 1`] = ` +
+
+
+

+ Do This Checkpoint +

+
+ Develop the text of your Body Book, crafting evidence-supported explanations on how the body is organized and its functions. +
+ +
+
+
+
+
+`; + +exports[` CardWithNotification story renders snapshot 1`] = ` +
+
+
+
+
+ Card Header +
+
+
+
+ Card Body +
+
+
+
+ Card Footer +
+
+
+
+ + + success + + + + + Lorem ipsum dolor sit amet + +
+
+
+`; + exports[` Default story renders snapshot 1`] = `
Default story renders snapshot 1`] = ` exports[` Dragging story renders snapshot 1`] = `
Dragging story renders snapshot 1`] = ` exports[` Horizontal story renders snapshot 1`] = `
Horizontal story renders snapshot 1`] = `
`; +exports[` InteractiveOnHover story renders snapshot 1`] = ` +
+
+
+
+ Card Contents +
+
+
+
+`; + +exports[` LoadingProfileCard story renders snapshot 1`] = ` +
+
+
+
+
+
+
+`; + exports[` Raised story renders snapshot 1`] = `
Raised story renders snapshot 1`] = `
`; + +exports[` StaticOnHover story renders snapshot 1`] = ` +
+
+
+
+ Card Contents +
+
+
+
+`; diff --git a/src/components/InlineNotification/InlineNotification.tsx b/src/components/InlineNotification/InlineNotification.tsx index 62819b67f7..c909ea522d 100644 --- a/src/components/InlineNotification/InlineNotification.tsx +++ b/src/components/InlineNotification/InlineNotification.tsx @@ -46,7 +46,6 @@ type Props = { inactive?: boolean; /** * Toggles notification that fills the full width of its container. - * Used for CardWithNotification recipe. */ isFullWidth?: boolean; /** diff --git a/src/components/InputField/InputField.stories.tsx b/src/components/InputField/InputField.stories.tsx index 3c7aa0f5da..086052c70c 100644 --- a/src/components/InputField/InputField.stories.tsx +++ b/src/components/InputField/InputField.stories.tsx @@ -3,6 +3,8 @@ import React from 'react'; import { InputField } from './InputField'; import Button from '../Button'; +import { Label } from '../Label/Label'; +import { Table } from '../Table/Table'; export default { title: 'Components/InputField', @@ -228,3 +230,39 @@ export const RequiredVariants: StoryObj = { }, }, }; + +export const TabularInput: StoryObj = { + parameters: { + badges: ['1.1', 'implementationExample'], + }, + render: (args) => ( + + + + Label + Field + + + + + + + + + + + +
+ ), +}; diff --git a/src/components/InputField/__snapshots__/InputField.test.ts.snap b/src/components/InputField/__snapshots__/InputField.test.ts.snap index 2ce0e80b9d..8abacbad6a 100644 --- a/src/components/InputField/__snapshots__/InputField.test.ts.snap +++ b/src/components/InputField/__snapshots__/InputField.test.ts.snap @@ -1404,3 +1404,67 @@ exports[` RequiredVariants story renders snapshot 1`] = `
`; + +exports[` TabularInput story renders snapshot 1`] = ` +
+ + + + + + + + + + + + + +
+ Label + + Field +
+ + +
+
+ +
+
+
+
+`; diff --git a/src/components/Menu/Menu.stories.tsx b/src/components/Menu/Menu.stories.tsx index 8d4674398c..c6974b6d98 100644 --- a/src/components/Menu/Menu.stories.tsx +++ b/src/components/Menu/Menu.stories.tsx @@ -1,9 +1,14 @@ import type { StoryObj, Meta } from '@storybook/react'; +import { userEvent } from '@storybook/testing-library'; import React from 'react'; import { Menu } from './Menu'; import type { MenuProps } from './Menu'; +import icons from '../../icons/spritemap'; +import type { IconName } from '../../icons/spritemap'; +import { Avatar } from '../Avatar/Avatar'; +import { Icon } from '../Icon/Icon'; export default { title: 'Components/Menu', component: Menu, @@ -25,7 +30,7 @@ export default { }, decorators: [ (Story) => ( -
+
), @@ -159,3 +164,96 @@ export const WithCustomButton: StoryObj = { ), }, }; + +export const MenuWithAvatarButton: StoryObj = { + parameters: { + badges: ['1.3', 'implementationExample'], + }, + args: { + children: ( + <> + + + + + + Headless UI Docs + + + MDN: Menu + + {/* eslint-disable-next-line no-alert */} + alert('Item clicked')}> + Trigger Action + + + Not Possible (disabled) + + + + ), + }, +}; + +export const Opened: StoryObj = { + ...Default, + play: () => { + userEvent.tab(); + userEvent.keyboard(' '); + }, +}; + +export const MenuWithIconButton: StoryObj = + { + argTypes: { + iconName: { + control: 'radio', + options: Object.keys(icons), + }, + }, + args: { + iconName: 'dots-vertical', + }, + parameters: { + badges: ['1.2', 'implementationExample'], + }, + render: ({ iconName }) => ( + + + + + + + Headless UI Docs + + + MDN: Menu + + {/* eslint-disable-next-line no-alert */} + alert('Item clicked')}> + Trigger Action + + + Not Possible (disabled) + + + + ), + }; diff --git a/src/components/Menu/__snapshots__/Menu.test.tsx.snap b/src/components/Menu/__snapshots__/Menu.test.tsx.snap index 69a2e4aa07..e2f93be83b 100644 --- a/src/components/Menu/__snapshots__/Menu.test.tsx.snap +++ b/src/components/Menu/__snapshots__/Menu.test.tsx.snap @@ -33,6 +33,98 @@ exports[` Default story renders snapshot 1`] = `
`; +exports[` MenuWithAvatarButton story renders snapshot 1`] = ` + +`; + +exports[` MenuWithIconButton story renders snapshot 1`] = ` + +`; + +exports[` Opened story renders snapshot 1`] = ` + +`; + exports[` WithCustomButton story renders snapshot 1`] = ` ), }; + +export const NumberIconList: StoryObj = { + parameters: { + badges: ['1.0', 'implementationExample'], + }, + render: () => ( +
+ + + + + + +
+ ), +}; diff --git a/src/components/NumberIcon/__snapshots__/NumberIcon.test.ts.snap b/src/components/NumberIcon/__snapshots__/NumberIcon.test.ts.snap index f6a865afb1..03c4c3f363 100644 --- a/src/components/NumberIcon/__snapshots__/NumberIcon.test.ts.snap +++ b/src/components/NumberIcon/__snapshots__/NumberIcon.test.ts.snap @@ -1,24 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` Default story renders snapshot 1`] = ` - - 1 - -`; - -exports[` DifferentNumbers story renders snapshot 1`] = ` -
- - 0 - DifferentNumbers story renders snapshot 1`] = ` > 1 - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 8 - - - 9 - - - 10 - - - 21 - - - 32 - - - 43 - - - 54 - - - 65 - - - 76 - - - 87 - - +`; + +exports[` DifferentNumbers story renders snapshot 1`] = ` +
+
+ + 0 + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + + + 8 + + + 9 + + + 10 + + + 21 + + + 32 + + + 43 + + + 54 + + + 65 + + + 76 + + + 87 + + + 98 + +
+
+`; + +exports[` NumberIconList story renders snapshot 1`] = ` +
+
- 98 - + + 1 + + + + + incomplete step 2 + + + + + + 3 + + + + + incomplete step 4 + + + + + + + + incomplete step 5 + + + + + + + + incomplete step 6 + + + + +
`; exports[` Small story renders snapshot 1`] = ` - - 1 - + + 1 + +
`; exports[` Success story renders snapshot 1`] = ` - - 1 - + + 1 + + `; exports[` SuccessSmall story renders snapshot 1`] = ` - - 1 - + + 1 + + `; diff --git a/src/components/Slider/Slider.stories.tsx b/src/components/Slider/Slider.stories.tsx index cba8045eef..918037ee43 100644 --- a/src/components/Slider/Slider.stories.tsx +++ b/src/components/Slider/Slider.stories.tsx @@ -5,14 +5,18 @@ import React, { useState } from 'react'; import { Slider } from './Slider'; +import { Button } from '../Button/Button'; +import { InputField } from '../InputField/InputField'; +import { Label } from '../Label/Label'; +import { Text } from '../Text/Text'; + export default { title: 'Components/Slider', component: Slider, parameters: { - layout: 'centered', badges: ['1.3'], }, - decorators: [(Story) =>
{Story()}
], + decorators: [(Story) =>
{Story()}
], argTypes: { fieldNote: { type: 'string', @@ -174,3 +178,224 @@ export const Focus: StoryObj = { userEvent.tab(); }, }; + +const moodData = [ + { emoji: '😡', value: 0, description: 'Very Upset' }, + { emoji: '🙁', value: 25, description: 'Upset' }, + { emoji: '😐', value: 50, description: 'Neutral' }, + { emoji: '🙂', value: 75, description: 'Happy' }, + { emoji: '😍', value: 100, description: 'Very Happy' }, +]; + +export const UsingInputDisplay: StoryObj = { + parameters: { + badges: ['1.3', 'implementationExample'], + axe: { + disabledRules: ['color-contrast'], // adding for disabled field example + }, + }, + render: ({ min = 0, max = 100, step = 1, value = 50, ...rest }) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [sliderValue, setSliderValue] = useState(value); + + return ( +
+ {min} + setSliderValue(Number(target.value))} + value={sliderValue} + /> + {max} + +
+ ); + }, +}; + +export const UsingControlButtons: StoryObj = { + parameters: { + badges: ['1.3', 'implementationExample'], + }, + render: ({ min = 0, max = 100, step = 1, value = 50, ...rest }) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [sliderValue, setSliderValue] = useState(value); + + return ( +
+ + {min} + setSliderValue(Number(target.value))} + tooltip={`Slider: ${sliderValue}`} + value={sliderValue} + /> + {max} + +
+ ); + }, +}; + +export const WithHighlightedContent: StoryObj = { + parameters: { + badges: ['1.3', 'implementationExample'], + }, + render: ({ min = 0, max = 100, step = 25, value = 50, ...rest }) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [sliderValue, setSliderValue] = useState(value); + + return ( +
+
+ mood.description)} + max={max} + min={min} + step={step} + {...rest} + onChange={({ target }) => setSliderValue(Number(target.value))} + value={sliderValue} + /> +
+ {moodData.map((mood) => { + return sliderValue === mood.value && <>{mood.emoji}; + })} +
+
+ + Current mood:{' '} + + {moodData.map((mood) => { + return sliderValue === mood.value && <>{mood.description}; + })} + + +
+ ); + }, +}; + +export const WithVisualLabel: StoryObj = { + parameters: { + badges: ['1.3', 'implementationExample'], + }, + render: ({ min = 0, max = 100, step = 25, value = 50, ...rest }) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [sliderValue, setSliderValue] = useState(value); + + return ( +
+
+
+
+ ); + }, +}; + +export const WithMultipleVisualLabels: StoryObj = { + parameters: { + badges: ['1.3', 'implementationExample'], + }, + render: ({ min = 0, max = 100, step = 25, value = 50, ...rest }) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [sliderValue, setSliderValue] = useState(value); + + return ( +
+
+
+
+ ); + }, +}; diff --git a/src/components/Slider/__snapshots__/Slider.test.tsx.snap b/src/components/Slider/__snapshots__/Slider.test.tsx.snap index df784dcb53..6381b6639e 100644 --- a/src/components/Slider/__snapshots__/Slider.test.tsx.snap +++ b/src/components/Slider/__snapshots__/Slider.test.tsx.snap @@ -2,7 +2,7 @@ exports[` Default story renders snapshot 1`] = `
Default story renders snapshot 1`] = ` exports[` Disabled story renders snapshot 1`] = `
Disabled story renders snapshot 1`] = ` exports[` FieldNote story renders snapshot 1`] = `
FieldNote story renders snapshot 1`] = ` exports[` GeneratedMarkers story renders snapshot 1`] = `
GeneratedMarkers story renders snapshot 1`] = ` exports[` MarkersLargeValues story renders snapshot 1`] = `
MarkersLargeValues story renders snapshot 1`] = ` exports[` MarkersSmallValues story renders snapshot 1`] = `
MarkersSmallValues story renders snapshot 1`] = ` exports[` NegativeNonIntegerMarkers story renders snapshot 1`] = `
NegativeNonIntegerMarkers story renders snapshot 1`] = ` exports[` NoVisibleLabel story renders snapshot 1`] = `
NoVisibleLabel story renders snapshot 1`] = `
`; + +exports[` UsingControlButtons story renders snapshot 1`] = ` +
+
+ +

+ 0 +

+
+ +
+
+

+ 100 +

+ +
+
+`; + +exports[` UsingInputDisplay story renders snapshot 1`] = ` +
+
+

+ 0 +

+
+ +
+
+

+ 100 +

+
+
+ +
+
+
+
+`; + +exports[` WithHighlightedContent story renders snapshot 1`] = ` +
+
+
+
+ + +
+
+
+ 😐 +
+
+

+ Current mood: + + + Neutral + +

+
+
+`; + +exports[` WithMultipleVisualLabels story renders snapshot 1`] = ` +
+
+
+ +
+
+ 😡 +
+
+ 🙁 +
+
+ 😐 +
+
+ 🙂 +
+
+ 😍 +
+
+
+ + +
+
+
+
+
+`; + +exports[` WithVisualLabel story renders snapshot 1`] = ` +
+
+
+ +
+ 😐 +
+
+ + +
+
+
+
+
+`; diff --git a/.storybook/recipes/Filters/Filters.tsx b/src/components/Table/Filters.tsx similarity index 100% rename from .storybook/recipes/Filters/Filters.tsx rename to src/components/Table/Filters.tsx diff --git a/.storybook/recipes/StackedCardsToTable/StackedCardsToTable.tsx b/src/components/Table/StackedCardsToTable.tsx similarity index 100% rename from .storybook/recipes/StackedCardsToTable/StackedCardsToTable.tsx rename to src/components/Table/StackedCardsToTable.tsx diff --git a/src/components/Table/Table.stories.tsx b/src/components/Table/Table.stories.tsx index 6eaa25033a..d2b506b9f8 100644 --- a/src/components/Table/Table.stories.tsx +++ b/src/components/Table/Table.stories.tsx @@ -1,7 +1,11 @@ import type { StoryObj, Meta } from '@storybook/react'; import React, { useState } from 'react'; +import { Filters } from './Filters'; +import { StackedCardsToTable } from './StackedCardsToTable'; import { Table, type SortDirectionsType } from './Table'; +import { chromaticViewports } from '../../../src/util/viewports'; + import styles from './Table.stories.module.css'; export default { @@ -347,3 +351,24 @@ const SortableExample = () => { export const SortableInteractive: StoryObj = { render: () => , }; + +export const FiltersInteractive: StoryObj = { + parameters: { + badges: ['1.1', 'implementationExample'], + }, + render: () => , +}; + +export const StackedCardsExample: StoryObj = { + parameters: { + badges: ['1.1', 'implementationExample'], + chromatic: { + viewports: [ + chromaticViewports.googlePixel2, + chromaticViewports.ipadMini, + chromaticViewports.chromebook, + ], + }, + }, + render: () => , +}; diff --git a/src/components/Table/__snapshots__/Table.test.ts.snap b/src/components/Table/__snapshots__/Table.test.ts.snap index 704baefbaf..156bf06977 100644 --- a/src/components/Table/__snapshots__/Table.test.ts.snap +++ b/src/components/Table/__snapshots__/Table.test.ts.snap @@ -480,6 +480,456 @@ exports[` Default story renders snapshot 1`] = ` `; +exports[`
FiltersInteractive story renders snapshot 1`] = ` +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Food + + Soup + + Salad + + Sandwich +
+ Cereal + + + + is soup + + + + + + + is salad + + + + +
+ Fried Rice + + + + + is salad + + + + +
+ Hot Dog + + + + + + is sandwich + + + +
+ Mashed Potatoes + + + + is soup + + + + + + + is salad + + + + +
+ Nigiri + + + + + is salad + + + + + + + is sandwich + + + +
+ Oatmeal + + + + is soup + + + + + +
+ Soup in Bread Bowl + + + + is soup + + + + + + + + is sandwich + + + +
+ Sloppy Joe + + + + is soup + + + + + + + is salad + + + + + + + is sandwich + + + +
+ Vanilla Soy Latte + + + + is soup + + + + + +
+
+
+`; + exports[` SortableInteractive story renders snapshot 1`] = `
SortableInteractive story renders snapshot 1`] = `
`; +exports[`
StackedCardsExample story renders snapshot 1`] = ` +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Students + + Status + + Cog skill + + Time submitted +
+ Araya, Raquel + + Stop and Revise + + 3 + + 2 hours ago +
+ Jesse Banet + + Stop and Revise + + 1 + + 3 days ago +
+ Julie Davis + + Working + + 0 + + 3 days ago +
+ Hussain, Adnan + + Review Feedback + + 0 + + 3 days ago +
+ Ilango, Megha + + Needs Feedback + + 3 + + 3 days ago +
+ Jaffer, Arman + + Needs Feedback + + 1 + + 3 days ago +
+ Kang, Michelle + + Review Feedback + + 1 + + 3 days ago +
+ Lewine, Chris + + Continue Working + + 2 + + 3 days ago +
+ Luo, Celia + + Review Feedback + + 1 + + 3 days ago +
+
+
+`; + exports[` TableWithCaption story renders snapshot 1`] = `