diff --git a/.nx/version-plans/version-plan-1780519770858.md b/.nx/version-plans/version-plan-1780519770858.md new file mode 100644 index 00000000000..dddf677ff1e --- /dev/null +++ b/.nx/version-plans/version-plan-1780519770858.md @@ -0,0 +1,5 @@ +--- +gamut: patch +--- + +fix a11y errors and enable SB addon-a11y to error diff --git a/packages/gamut/src/ConnectedForm/ConnectedFormGroup.tsx b/packages/gamut/src/ConnectedForm/ConnectedFormGroup.tsx index 4e7ede387b2..30ac79123a1 100644 --- a/packages/gamut/src/ConnectedForm/ConnectedFormGroup.tsx +++ b/packages/gamut/src/ConnectedForm/ConnectedFormGroup.tsx @@ -1,6 +1,6 @@ import { css } from '@codecademy/gamut-styles'; import styled from '@emotion/styled'; -import { useEffect } from 'react'; +import { useEffect, useId } from 'react'; import * as React from 'react'; import { FormError, FormGroup, FormGroupLabel, FormGroupProps } from '..'; @@ -65,6 +65,8 @@ export function ConnectedFormGroup({ disabled, }); const { component: Component, ...rest } = field; + const uniqueIdSuffix = useId(); + const htmlForId = `${name}-${uniqueIdSuffix}`; useEffect(() => { if (customError) { @@ -78,7 +80,7 @@ export function ConnectedFormGroup({ const renderedLabel = ( ({ aria-describedby={errorId} aria-invalid={showError} disabled={disabled} + htmlFor={htmlForId} name={name} /> {children} diff --git a/packages/gamut/src/ConnectedForm/ConnectedInputs/ConnectedCheckbox.tsx b/packages/gamut/src/ConnectedForm/ConnectedInputs/ConnectedCheckbox.tsx index d5f25212aec..052c320645e 100644 --- a/packages/gamut/src/ConnectedForm/ConnectedInputs/ConnectedCheckbox.tsx +++ b/packages/gamut/src/ConnectedForm/ConnectedInputs/ConnectedCheckbox.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { useId } from 'react'; import { Controller } from 'react-hook-form'; import { Checkbox } from '../..'; @@ -21,6 +22,7 @@ export const ConnectedCheckbox: React.FC = ({ name, disabled, }); + const uniqueIdSuffix = useId(); return ( = ({ checked={value} className={className} disabled={isDisabled} - htmlFor={name} + htmlFor={`${name}-${uniqueIdSuffix}`} id={id} infotip={infotip} label={label} diff --git a/packages/gamut/src/ConnectedForm/__tests__/ConnectedForm.test.tsx b/packages/gamut/src/ConnectedForm/__tests__/ConnectedForm.test.tsx index 7e6dcc4cd9c..532edb4f455 100644 --- a/packages/gamut/src/ConnectedForm/__tests__/ConnectedForm.test.tsx +++ b/packages/gamut/src/ConnectedForm/__tests__/ConnectedForm.test.tsx @@ -27,10 +27,10 @@ const getBaseCases = (view: RenderResult) => { name: 'cool-checkbox', }) as HTMLInputElement; const selectField = view.getByRole('combobox', { - name: '', + name: /cool-select/, }) as HTMLInputElement; const textField = view.getByRole('textbox', { - name: '', + name: /cool-input/, }) as HTMLInputElement; const radioGroup = view.getByRole('radiogroup'); const radioOption = view.getByLabelText('two') as HTMLInputElement; diff --git a/packages/gamut/src/DataList/Tables/Rows/TableRow.tsx b/packages/gamut/src/DataList/Tables/Rows/TableRow.tsx index 776618f9fd5..599e85ff86c 100644 --- a/packages/gamut/src/DataList/Tables/Rows/TableRow.tsx +++ b/packages/gamut/src/DataList/Tables/Rows/TableRow.tsx @@ -142,6 +142,11 @@ export const TableRow: DataRow = ({ if (loading) { return ( + {type === 'header' && ( + + Loading data + + )} { } ); + describe('Loading state', () => { + it('renders screenreader loading text for header type columns when loading', () => { + const { view } = renderView({ + loading: true, + rows: [], + columns: [{ key: 'name', type: 'header' }, { key: 'sin' }], + }); + + expect(view.getAllByText('Loading data')).toHaveLength(5); + }); + }); + describe('Container query control', () => { it('applies container query styles by default', () => { const { view } = renderView(); diff --git a/packages/gamut/src/List/ListRow.tsx b/packages/gamut/src/List/ListRow.tsx index a682da3a112..686508c5989 100644 --- a/packages/gamut/src/List/ListRow.tsx +++ b/packages/gamut/src/List/ListRow.tsx @@ -114,6 +114,7 @@ export const ListRow = forwardRef( return ( = (props) => { return ( - - + + ); }; diff --git a/packages/gamut/src/Tabs/TabNavLink.tsx b/packages/gamut/src/Tabs/TabNavLink.tsx index 520714f4184..d0e401d9027 100644 --- a/packages/gamut/src/Tabs/TabNavLink.tsx +++ b/packages/gamut/src/Tabs/TabNavLink.tsx @@ -7,7 +7,7 @@ const StyledTabNavLink = styled(TabButton)(); export const TabNavLink: React.FC> = ({ variant = 'standard', - role = 'tab', + role = 'button', ...rest }) => { return ; diff --git a/packages/gamut/src/Tabs/__tests__/TabNavLink.test.tsx b/packages/gamut/src/Tabs/__tests__/TabNavLink.test.tsx new file mode 100644 index 00000000000..779de99f595 --- /dev/null +++ b/packages/gamut/src/Tabs/__tests__/TabNavLink.test.tsx @@ -0,0 +1,16 @@ +import { setupRtl } from '@codecademy/gamut-tests'; + +import { TabNavLink } from '../TabNavLink'; + +const renderView = setupRtl(TabNavLink, { + href: '/', + children: 'Tab Link', +}); + +describe('TabNavLink', () => { + it('renders with role button by default', () => { + const { view } = renderView(); + + view.getByRole('button', { name: 'Tab Link' }); + }); +}); diff --git a/packages/gamut/src/Tag/index.tsx b/packages/gamut/src/Tag/index.tsx index 29626f3dbe5..686478ff325 100644 --- a/packages/gamut/src/Tag/index.tsx +++ b/packages/gamut/src/Tag/index.tsx @@ -89,7 +89,7 @@ export const Tag: React.FC = ({ {isSelection && ( = ({ images = [], showControls = true, @@ -111,10 +119,9 @@ export const ImageGallery: React.FC = ({ {showControls && ( - - Columns: - + Columns: = ({ onChange={handleColumnsChange} size="small" /> - - {imageType} size: - + {imageType} size: = ({ /> - - Filter: - + Filter: > = (args) => { }, [args.rotated]); return ( - setRotated(!isRotated)}> + setRotated(!isRotated)} + > diff --git a/packages/styleguide/src/lib/Atoms/Badge/Badge.stories.tsx b/packages/styleguide/src/lib/Atoms/Badge/Badge.stories.tsx index 30cf84cfd4d..bef7f28dfec 100644 --- a/packages/styleguide/src/lib/Atoms/Badge/Badge.stories.tsx +++ b/packages/styleguide/src/lib/Atoms/Badge/Badge.stories.tsx @@ -55,7 +55,7 @@ export const Custom: Story = { variant="custom" {...args} /> - + { - return ( - - - - ); -}; - export const FormGroupHtmlFor: Story = { - render: () => , -}; - -const FormGroupDivExample = () => { - return ( - - + render: () => ( + + - ); + ), }; export const FormGroupDiv: Story = { - render: () => , + render: () => ( + + + + ), }; export const DefaultState: Story = { @@ -49,7 +44,7 @@ export const DefaultState: Story = { required: true, description: 'You can tell by the asterisk.', htmlFor: 'required1', - children: , + children: , }, }; @@ -60,7 +55,7 @@ export const Error: Story = { description: 'You can tell by the asterisk.', error: 'You messed up dude.', htmlFor: 'required-error', - children: , + children: , }, }; @@ -69,35 +64,37 @@ export const Valid: Story = { required: true, label: 'I am also required!!', htmlFor: 'required-valid', - children: , + children: , }, }; export const LowEmphasisInfoTip: Story = { args: { label: 'Low emphasis', + htmlFor: 'low-emphasis-input', infotip: { alignment: 'bottom-left', info: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', }, - children: , + children: , }, }; export const HighEmphasisInfoTip: Story = { args: { label: 'High emphasis', + htmlFor: 'high-emphasis-input', infotip: { emphasis: 'high', alignment: 'bottom-left', info: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', }, - children: , + children: , }, }; -const InfoTipLabellingExamples = () => { - return ( +export const InfoTipAutoLabelling: Story = { + render: () => ( { }} label="Auto-labelling (default)" > - + { }} label="With ariaLabel" > - + { label="With ariaLabelledBy" > Custom label for InfoTip button - + - ); -}; - -export const InfoTipAutoLabelling: Story = { - render: () => , + ), }; diff --git a/packages/styleguide/src/lib/Atoms/FormInputs/Checkbox/Checkbox.stories.tsx b/packages/styleguide/src/lib/Atoms/FormInputs/Checkbox/Checkbox.stories.tsx index e89556cd626..be3199debcc 100644 --- a/packages/styleguide/src/lib/Atoms/FormInputs/Checkbox/Checkbox.stories.tsx +++ b/packages/styleguide/src/lib/Atoms/FormInputs/Checkbox/Checkbox.stories.tsx @@ -43,7 +43,7 @@ export const Unchecked: Story = { htmlFor: 'example-unchecked', label: 'unchecked', name: 'example-unchecked', - checked: true, + checked: false, }, }; diff --git a/packages/styleguide/src/lib/Atoms/FormInputs/Input/Input.mdx b/packages/styleguide/src/lib/Atoms/FormInputs/Input/Input.mdx index c2a3cb004e7..1c02343d3bc 100644 --- a/packages/styleguide/src/lib/Atoms/FormInputs/Input/Input.mdx +++ b/packages/styleguide/src/lib/Atoms/FormInputs/Input/Input.mdx @@ -68,7 +68,7 @@ You can use a custom icon (from gamut-icons) in your Input elements. The error a ## FormGroup + Input -`Input` formats nicely in FormGroups and reflects error states. Make sure you provide an htmlFor to the `FormGroup` and a `name` to the `Input` for maximum accessibility. See FormGroup story for the customizations available. +`Input` formats nicely in FormGroups and reflects error states. Make sure you provide an `htmlFor` to the `FormGroup` and an `id` to the `Input` for maximum accessibility. See FormGroup story for the customizations available. diff --git a/packages/styleguide/src/lib/Atoms/FormInputs/Input/Input.stories.tsx b/packages/styleguide/src/lib/Atoms/FormInputs/Input/Input.stories.tsx index 563ab7d4e99..25777f03830 100644 --- a/packages/styleguide/src/lib/Atoms/FormInputs/Input/Input.stories.tsx +++ b/packages/styleguide/src/lib/Atoms/FormInputs/Input/Input.stories.tsx @@ -5,8 +5,7 @@ import type { Meta, StoryObj } from '@storybook/react'; const meta: Meta = { component: Input, args: { - htmlFor: 'example-input', - name: 'example-input', + id: 'example-input', placeholder: 'Placeholder', type: 'text', size: 'base', @@ -29,9 +28,8 @@ export const Default: Story = { export const Text: Story = { args: { - htmlFor: 'example-text', + id: 'example-text', defaultValue: 'Text', - name: 'example-text', type: 'text', required: true, }, @@ -39,8 +37,7 @@ export const Text: Story = { export const Number: Story = { args: { - htmlFor: 'example-number', - name: 'example-number', + id: 'example-number', type: 'number', defaultValue: 1, }, @@ -48,8 +45,7 @@ export const Number: Story = { export const File: Story = { args: { - htmlFor: 'example-file', - name: 'example-file', + id: 'example-file', type: 'file', value: '', onChange: () => {}, @@ -58,17 +54,15 @@ export const File: Story = { export const Error: Story = { args: { - htmlFor: 'example-error', + id: 'example-error', defaultValue: 'Error', - name: 'example-error', error: true, }, }; export const Validated: Story = { args: { - htmlFor: 'example-valid', - name: 'example-placeholder', + id: 'example-valid', placeholder: 'Placeholder', defaultValue: 'Verified Text', valid: true, @@ -77,8 +71,7 @@ export const Validated: Story = { export const Placeholder: Story = { args: { - htmlFor: 'example-placeholder', - name: 'example-placeholder', + id: 'example-placeholder', placeholder: 'Placeholder', defaultValue: undefined, }, @@ -86,8 +79,7 @@ export const Placeholder: Story = { export const Disabled: Story = { args: { - htmlFor: 'example-disabled', - name: 'example-disabled', + id: 'example-disabled', placeholder: 'Disabled', disabled: true, defaultValue: undefined, @@ -96,8 +88,7 @@ export const Disabled: Story = { export const CustomIcon: Story = { args: { - htmlFor: 'example-icon', - name: 'example-icon', + id: 'example-icon', defaultValue: 'Hello...', icon: icons.ViewIcon, }, @@ -106,10 +97,10 @@ export const CustomIcon: Story = { export const FormGroupDefault: Story = { args: { defaultValue: '123', - name: 'example-123', + id: 'example-123', }, render: (args) => ( - + ), @@ -118,7 +109,7 @@ export const FormGroupDefault: Story = { export const FormGroupError: Story = { args: { defaultValue: '123', - name: 'example-123', + id: 'example-123', error: true, }, render: (args) => ( @@ -136,7 +127,7 @@ export const FormGroupError: Story = { export const FormGroupLarge: Story = { args: { defaultValue: '123', - name: 'example-123', + id: 'example-123', placeholder: 'Placeholder', }, render: (args) => ( @@ -155,7 +146,7 @@ export const FormGroupLarge: Story = { export const FormGroupErrorLarge: Story = { args: { defaultValue: '123', - name: 'example-123', + id: 'example-123', error: true, }, render: (args) => ( @@ -173,9 +164,8 @@ export const FormGroupErrorLarge: Story = { export const TextSmall: Story = { args: { - htmlFor: 'example-text', + id: 'example-text', defaultValue: 'This input has less padding!', - name: 'example-text', type: 'text', required: true, size: 'small', @@ -184,9 +174,8 @@ export const TextSmall: Story = { export const TextSmallError: Story = { args: { - htmlFor: 'example-text', + id: 'example-text', defaultValue: 'Still works like a charm!', - name: 'example-text', type: 'text', required: true, size: 'small', @@ -196,8 +185,7 @@ export const TextSmallError: Story = { export const NumberSmall: Story = { args: { - htmlFor: 'example-number', - name: 'example-number', + id: 'example-number', type: 'number', defaultValue: 1, size: 'small', @@ -207,8 +195,7 @@ export const NumberSmall: Story = { export const FileSmall: Story = { args: { - htmlFor: 'example-file', - name: 'example-file', + id: 'example-file', type: 'file', value: '', onChange: () => {}, @@ -219,8 +206,7 @@ export const FileSmall: Story = { export const DisabledSmall: Story = { args: { - htmlFor: 'example-disabled', - name: 'example-disabled', + id: 'example-disabled', placeholder: 'Disabled', disabled: true, defaultValue: undefined, diff --git a/packages/styleguide/src/lib/Atoms/FormInputs/Select/Select.mdx b/packages/styleguide/src/lib/Atoms/FormInputs/Select/Select.mdx index e353202bd82..21db07765c1 100644 --- a/packages/styleguide/src/lib/Atoms/FormInputs/Select/Select.mdx +++ b/packages/styleguide/src/lib/Atoms/FormInputs/Select/Select.mdx @@ -49,7 +49,7 @@ Use Select to handle single selection within a group of options. ## FormGroup + Select -`Select` formats nicely in FormGroups and reflects error states. Make sure you provide an htmlFor to the `FormGroup` and a `name` to the `Select` for maximum accessibility. See FormGroup story for the customizations available. +`Select` formats nicely in FormGroups and reflects error states. Make sure you provide an `htmlFor` to the `FormGroup` and an `id` to the `Select` for maximum accessibility. See FormGroup story for the customizations available. diff --git a/packages/styleguide/src/lib/Atoms/FormInputs/Select/Select.stories.tsx b/packages/styleguide/src/lib/Atoms/FormInputs/Select/Select.stories.tsx index 952b725f532..9926a497b61 100644 --- a/packages/styleguide/src/lib/Atoms/FormInputs/Select/Select.stories.tsx +++ b/packages/styleguide/src/lib/Atoms/FormInputs/Select/Select.stories.tsx @@ -6,9 +6,9 @@ const fruitOptions = ['Apple', 'Banana', 'Cherry', 'Dragonfruit', 'Eggplant']; const meta: Meta = { component: Select, args: { - htmlFor: 'example-select', - name: 'example-select', + id: 'example-select', options: fruitOptions, + 'aria-label': 'Select an option', }, argTypes: { value: { @@ -61,7 +61,7 @@ export const FormGroupBase: Story = { args: { options: ['Error', 'oh no', ':('], defaultValue: 'oh no', - name: 'form-group-base', + id: 'form-group-base', }, render: (args) => ( ( FormGroup story for the customizations available. +`SelectDropdown` formats nicely in FormGroups and reflects error states. Make sure you provide an `htmlFor` to the `FormGroup` and an `id` to the `SelectDropdown` for maximum accessibility. See FormGroup story for the customizations available. diff --git a/packages/styleguide/src/lib/Atoms/FormInputs/SelectDropdown/SelectDropdown.stories.tsx b/packages/styleguide/src/lib/Atoms/FormInputs/SelectDropdown/SelectDropdown.stories.tsx index 8576c849958..18de7e7873a 100644 --- a/packages/styleguide/src/lib/Atoms/FormInputs/SelectDropdown/SelectDropdown.stories.tsx +++ b/packages/styleguide/src/lib/Atoms/FormInputs/SelectDropdown/SelectDropdown.stories.tsx @@ -14,11 +14,13 @@ const fruitOptions = ['Apple', 'Banana', 'Cherry', 'Dragonfruit', 'Eggplant']; const meta: Meta = { component: SelectDropdown, args: { - htmlFor: 'example-select', + id: 'example-select', + name: 'example-select', options: fruitOptions, disabled: false, isSearchable: false, value: '', + 'aria-label': 'Select an option', }, argTypes: { value: { @@ -147,6 +149,7 @@ export const ShownOptionsDefault: Story = { 'asdfsadf', ], name: 'shownOptionsLimit01', + id: 'shownOptionsLimit01', placeholder: 'six is the magic number', }, render: (args) => ( @@ -177,6 +180,7 @@ export const ShownOptionsThree: Story = { 'hi', 'asdfsadf', ], + id: 'shownOptionsLimit02', name: 'shownOptionsLimit02', placeholder: 'three is the magic number', shownOptionsLimit: 3, @@ -196,6 +200,7 @@ export const ShownOptionsThree: Story = { export const DisabledOptions: Story = { args: { + id: 'disabled-dropdown', name: 'disabled-dropdown', options: [ { @@ -229,6 +234,7 @@ export const DisabledOptions: Story = { export const Subtitles: Story = { args: { + id: 'subtitles-dropdown', name: 'subtitles-dropdown', options: [ { @@ -264,6 +270,7 @@ export const Subtitles: Story = { export const RightLabels: Story = { args: { + id: 'right-labels-dropdown', name: 'right-labels-dropdown', options: [ { @@ -299,6 +306,7 @@ export const RightLabels: Story = { export const GroupDividers: Story = { args: { + id: 'dividers-dropdown', name: 'dividers-dropdown', options: [ { @@ -357,8 +365,9 @@ export const GroupDividers: Story = { export const GroupLabels: Story = { args: { - name: 'group-labels-dropdown', + id: 'group-labels-dropdown', multiple: true, + name: 'group-labels-dropdown', options: [ { label: 'Group 1', @@ -417,6 +426,7 @@ export const GroupLabels: Story = { export const Icons: Story = { args: { + id: 'pizzaz-dropdown', name: 'pizzaz-dropdown', options: [ { @@ -455,6 +465,7 @@ export const CustomInputProps: Story = { 'data-cy': 'custom-dropdown', }, }, + id: 'what', name: 'what', }, render: (args) => ( @@ -468,6 +479,7 @@ export const CustomInputProps: Story = { export const MultipleSelect: Story = { args: { + id: 'multi-dropdown', name: 'multi-dropdown', multiple: true, options: [ @@ -502,6 +514,7 @@ export const FormGroupSelectDropdown: Story = { args: { options: ['hello', 'hi', 'howdy'], value: 'oh no', + id: 'big-label', name: 'big-label', }, render: (args) => ( @@ -521,6 +534,7 @@ export const FormGroupSelectDropdown: Story = { export const FormGroupError: Story = { args: { options: ['Error', 'oh no', ':('], + id: 'error-example-unique', name: 'error-example-unique', placeholder: 'cry cry cry', }, @@ -540,6 +554,7 @@ export const FormGroupError: Story = { export const AbbreviatedInput: Story = { args: { + id: 'abbreviated-dropdown', name: 'abbreviated-dropdown', options: [ { @@ -588,6 +603,7 @@ export const AbbreviatedInput: Story = { export const IndependentWidths: Story = { args: { + id: 'width-dropdown', name: 'width-dropdown', options: [ { @@ -638,6 +654,7 @@ export const IndependentWidths: Story = { export const SmallWithAbbreviations: Story = { args: { + id: 'small-abbreviated-dropdown', name: 'small-abbreviated-dropdown', options: [ { @@ -690,6 +707,7 @@ export const SmallWithAbbreviations: Story = { export const ComplexAbbreviatedOptions: Story = { args: { + id: 'complex-abbreviated-dropdown', name: 'complex-abbreviated-dropdown', options: [ { @@ -743,6 +761,7 @@ export const ComplexAbbreviatedOptions: Story = { export const AbbreviatedWithSubtitleAndRightLabel: Story = { args: { + id: 'abbreviated-detailed', name: 'abbreviated-detailed', options: [ { @@ -783,6 +802,7 @@ export const AbbreviatedWithSubtitleAndRightLabel: Story = { export const AbbreviatedSmallSize: Story = { args: { + id: 'abbreviated-small', name: 'abbreviated-small', options: [ { @@ -824,6 +844,7 @@ export const AbbreviatedSmallSize: Story = { }; export const MenuAlignmentRight: Story = { args: { + id: 'menu-alignment-right', name: 'menu-alignment-right', options: [ { @@ -876,6 +897,7 @@ export const MenuAlignmentRight: Story = { export const DisabledMultiValue: Story = { args: { + id: 'disabled-small-multi', name: 'disabled-small-multi', options: [ { @@ -910,7 +932,7 @@ export const DisabledMultiValue: Story = { render: (args) => ( @@ -922,6 +944,7 @@ export const DisabledMultiValue: Story = { export const LongPlaceholder: Story = { args: { + id: 'long-placeholder', name: 'long-placeholder', options: [ { @@ -966,6 +989,7 @@ export const LongPlaceholder: Story = { }; export const LongPlaceholderAgain: Story = { args: { + id: 'long-placeholder-again', name: 'long-placeholder-again', options: [ { @@ -1020,6 +1044,7 @@ export const zIndexOnMenu: Story = { label="This menu is rendered behind the header" > = { component: TextArea, args: { - htmlFor: 'example-input', - name: 'example-input', + id: 'example-input', defaultValue: 'Some text', rows: 4, }, + decorators: [ + (Story) => ( + + + + ), + ], }; export default meta; diff --git a/packages/styleguide/src/lib/Atoms/Toggle/Toggle.stories.tsx b/packages/styleguide/src/lib/Atoms/Toggle/Toggle.stories.tsx index 38a31c6ba03..45782717780 100644 --- a/packages/styleguide/src/lib/Atoms/Toggle/Toggle.stories.tsx +++ b/packages/styleguide/src/lib/Atoms/Toggle/Toggle.stories.tsx @@ -5,7 +5,9 @@ import { expect } from 'storybook/test'; const meta: Meta = { component: Toggle, - args: {}, + args: { + label: 'Toggle me', + }, }; export default meta; diff --git a/packages/styleguide/src/lib/Foundations/System/Props/Layout.stories.tsx b/packages/styleguide/src/lib/Foundations/System/Props/Layout.stories.tsx index 50e021f8338..9f89301cf63 100644 --- a/packages/styleguide/src/lib/Foundations/System/Props/Layout.stories.tsx +++ b/packages/styleguide/src/lib/Foundations/System/Props/Layout.stories.tsx @@ -15,6 +15,7 @@ export const OverflowXExample: Story = { bg="background-selected" overflowX="scroll" p={16} + tabIndex={0} whiteSpace="nowrap" width="200px" > @@ -34,7 +35,13 @@ export const OverflowXExample: Story = { export const OverflowYExample: Story = { render: () => ( - + This content is taller than its container and has{' '} Inspect the example to see diff --git a/packages/styleguide/src/lib/Molecules/AccordionButtonDeprecated/AccordionButtonDeprecated.stories.tsx b/packages/styleguide/src/lib/Molecules/AccordionButtonDeprecated/AccordionButtonDeprecated.stories.tsx index c29f132462a..6ec3b315392 100644 --- a/packages/styleguide/src/lib/Molecules/AccordionButtonDeprecated/AccordionButtonDeprecated.stories.tsx +++ b/packages/styleguide/src/lib/Molecules/AccordionButtonDeprecated/AccordionButtonDeprecated.stories.tsx @@ -1,4 +1,4 @@ -import { AccordionButtonDeprecated } from '@codecademy/gamut'; +import { AccordionButtonDeprecated, Box } from '@codecademy/gamut'; import type { Meta, StoryObj } from '@storybook/react'; const meta: Meta = { @@ -33,4 +33,11 @@ export const Blue: Story = { args: { theme: 'blue', }, + decorators: [ + (Story) => ( + + + + ), + ], }; diff --git a/packages/styleguide/src/lib/Molecules/Tabs/Tabs.stories.tsx b/packages/styleguide/src/lib/Molecules/Tabs/Tabs.stories.tsx index 82fb462de95..9f307750170 100644 --- a/packages/styleguide/src/lib/Molecules/Tabs/Tabs.stories.tsx +++ b/packages/styleguide/src/lib/Molecules/Tabs/Tabs.stories.tsx @@ -106,8 +106,7 @@ export const Controlled = () => { { return ( diff --git a/packages/styleguide/src/lib/Molecules/Toasts/Toaster/Toaster.stories.tsx b/packages/styleguide/src/lib/Molecules/Toasts/Toaster/Toaster.stories.tsx index 6a68bf27579..729c8b0354f 100644 --- a/packages/styleguide/src/lib/Molecules/Toasts/Toaster/Toaster.stories.tsx +++ b/packages/styleguide/src/lib/Molecules/Toasts/Toaster/Toaster.stories.tsx @@ -1,8 +1,9 @@ import { FillButton, GridBox, Toast, Toaster } from '@codecademy/gamut'; import { AddIcon, TrashIcon } from '@codecademy/gamut-icons'; import { Target } from '@codecademy/gamut-illustrations'; -import type { Meta } from '@storybook/react'; -import { ComponentProps, useState } from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { useState } from 'react'; +import { expect, waitFor } from 'storybook/test'; const exampleToasts = [ { @@ -37,36 +38,52 @@ const meta: Meta = { export default meta; -export const Default: React.FC> = (args) => { - const [toasts, setToasts] = useState(args.toasts || []); +type Story = StoryObj; - const removeToasts = () => { - setToasts([]); - }; +export const Default: Story = { + parameters: { + interactions: { + disable: false, + }, + }, + render: function DefaultStory(args) { + const [toasts, setToasts] = useState(args.toasts || []); + + const removeToasts = () => { + setToasts([]); + }; - const addToasts = () => { - if (!toasts.length) { - setTimeout(() => setToasts(args.toasts || []), 1000); - } - }; + const addToasts = () => { + if (!toasts.length) { + setTimeout(() => setToasts(args.toasts || []), 1000); + } + }; - const removeOne = (id: string) => { - const filteredToasts = toasts.filter((toast) => toast.id !== id); + const removeOne = (id: string) => { + const filteredToasts = toasts.filter((toast) => toast.id !== id); - setToasts(filteredToasts); - }; + setToasts(filteredToasts); + }; - return ( - <> - - - Click me to remove all the Toasts - - - Click me to reveal all the Toasts - - - - - ); + return ( + <> + + + Click me to remove all the Toasts + + + Click me to reveal all the Toasts + + + + + ); + }, + play: async () => { + await waitFor(async () => { + await expect( + document.body.querySelectorAll('[role="status"]').length + ).toEqual(4); + }); + }, }; diff --git a/packages/styleguide/src/lib/Organisms/ConnectedForm/ConnectedForm/ConnectedForm.stories.tsx b/packages/styleguide/src/lib/Organisms/ConnectedForm/ConnectedForm/ConnectedForm.stories.tsx index 112f4e5279c..773d9d9f2e4 100644 --- a/packages/styleguide/src/lib/Organisms/ConnectedForm/ConnectedForm/ConnectedForm.stories.tsx +++ b/packages/styleguide/src/lib/Organisms/ConnectedForm/ConnectedForm/ConnectedForm.stories.tsx @@ -32,7 +32,7 @@ export const Default = () => { inputField: '', radioGroupField: undefined, textAreaField: '', - nestedCheckboxesField: ['react', 'typescript', 'backend'], + nestedCheckboxesField: ['angular', 'typescript', 'backend'], }, validationRules: { checkboxField: { required: 'you need to check this.' }, diff --git a/packages/styleguide/src/lib/Organisms/ConnectedForm/ConnectedFormGroup/ConnectedFormGroup.stories.tsx b/packages/styleguide/src/lib/Organisms/ConnectedForm/ConnectedFormGroup/ConnectedFormGroup.stories.tsx index fabd2a64c0e..1b8aa5090cd 100644 --- a/packages/styleguide/src/lib/Organisms/ConnectedForm/ConnectedFormGroup/ConnectedFormGroup.stories.tsx +++ b/packages/styleguide/src/lib/Organisms/ConnectedForm/ConnectedFormGroup/ConnectedFormGroup.stories.tsx @@ -125,7 +125,7 @@ export const States = () => { export const InfoTipAutoLabelling: Story = { render: () => ( action('Form Submitted')(values)} > ), diff --git a/packages/styleguide/src/lib/Organisms/GridForm/Fields.stories.tsx b/packages/styleguide/src/lib/Organisms/GridForm/Fields.stories.tsx index 657a0be6d6d..46bb7e22052 100644 --- a/packages/styleguide/src/lib/Organisms/GridForm/Fields.stories.tsx +++ b/packages/styleguide/src/lib/Organisms/GridForm/Fields.stories.tsx @@ -255,7 +255,7 @@ export const CustomInputs: Story = { ), label: 'Gimme two more swags', - name: 'custom-input', + name: 'custom-text-input', size: 12, validation: { required: true, @@ -268,7 +268,11 @@ export const CustomInputs: Story = { }, { render: ({ error, setValue }) => ( - + ), size: 12, - label: 'Gimme two more swags', - name: 'custom-input-group', + name: 'custom-group-input', validation: { required: true, pattern: {