Accessibility fix pass for twenty-ui input components (#21776)
Re-enables the live Storybook axe gate across the twenty-ui `input`
domain (17 story files) by removing the inherited `a11y: { test: 'todo'
}` overrides. Pilot for the wider a11y fix pass; other domains follow
the same playbook.
**What changed**
- Accessible names added to icon-only buttons, `Toggle`, `Checkbox`, and
the button groups via small additive `aria-label`/`ariaLabel` props on 8
components. Where this fully fixes the story, the override is dropped so
the full gate applies.
- Color-contrast (design-token level) is deferred — not changed — via a
new shared `A11Y_DEFER_COLOR_CONTRAST` parameter (`@ui/testing`) that
disables only the `color-contrast` rule while every other axe rule stays
enforced. Grep the constant to find all deferrals when tokens are
darkened later.
- `CatalogDecorator`: unique cell ids (clears `duplicate-id-aria`) and
dimension titles switched from empty `h1/h2/h3` to `div` (clears
`empty-heading`). Both help every domain's catalogs.
**Reviewer notes**
- No visual change: edits are aria / id / story-args / axe-config only,
so Argos parity holds.
- Input axe gate goes from 12 failing to 60/60 passing; typecheck and
lint green.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21776?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
+2
-2
@@ -5,6 +5,7 @@ import {
|
||||
type LightIconButtonSize,
|
||||
} from '@ui/input/LightIconButton/LightIconButton';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -54,8 +55,7 @@ export const Catalog: CatalogStory<Story, typeof AnimatedLightIconButton> = {
|
||||
transition: { control: 'object' },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { IconReload, IconSearch } from '@ui/icon';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -22,8 +23,7 @@ export default meta;
|
||||
type Story = StoryObj<typeof Button>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
parameters: { a11y: A11Y_DEFER_COLOR_CONTRAST },
|
||||
argTypes: {
|
||||
hotkeys: { control: false },
|
||||
Icon: { control: false },
|
||||
@@ -61,8 +61,7 @@ export const Catalog: CatalogStory<Story, typeof Button> = {
|
||||
isLoading: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
@@ -136,8 +135,7 @@ export const SoonCatalog: CatalogStory<Story, typeof Button> = {
|
||||
hotkeys: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
@@ -210,8 +208,7 @@ export const PositionCatalog: CatalogStory<Story, typeof Button> = {
|
||||
hotkeys: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
@@ -288,8 +285,7 @@ export const ShortcutCatalog: CatalogStory<Story, typeof Button> = {
|
||||
position: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { IconCheckbox, IconNotes, IconTimelineEvent } from '@ui/icon';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -22,8 +23,7 @@ export default meta;
|
||||
type Story = StoryObj<typeof ButtonGroup>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
parameters: { a11y: A11Y_DEFER_COLOR_CONTRAST },
|
||||
args: {
|
||||
size: 'small',
|
||||
variant: 'primary',
|
||||
@@ -55,8 +55,7 @@ export const Catalog: CatalogStory<Story, typeof ButtonGroup> = {
|
||||
children: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
@@ -39,6 +39,7 @@ type CheckboxProps = {
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
accent?: CheckboxAccent;
|
||||
'aria-label'?: string;
|
||||
};
|
||||
|
||||
export const Checkbox = ({
|
||||
@@ -53,6 +54,7 @@ export const Checkbox = ({
|
||||
className,
|
||||
disabled = false,
|
||||
accent = CheckboxAccent.Blue,
|
||||
'aria-label': ariaLabel,
|
||||
}: CheckboxProps) => {
|
||||
const [isInternalChecked, setIsInternalChecked] =
|
||||
React.useState<boolean>(false);
|
||||
@@ -67,6 +69,7 @@ export const Checkbox = ({
|
||||
indeterminate={indeterminate}
|
||||
disabled={disabled}
|
||||
name="styled-checkbox"
|
||||
aria-label={ariaLabel}
|
||||
data-testid="input-checkbox"
|
||||
onCheckedChange={(value, eventDetails) => {
|
||||
onChange?.(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -22,8 +23,6 @@ export default meta;
|
||||
type Story = StoryObj<typeof Checkbox>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
args: {
|
||||
checked: false,
|
||||
indeterminate: false,
|
||||
@@ -33,12 +32,13 @@ export const Default: Story = {
|
||||
size: CheckboxSize.Small,
|
||||
shape: CheckboxShape.Squared,
|
||||
accent: CheckboxAccent.Blue,
|
||||
'aria-label': 'Checkbox',
|
||||
},
|
||||
decorators: [ComponentDecorator],
|
||||
};
|
||||
|
||||
export const Catalog: CatalogStory<Story, typeof Checkbox> = {
|
||||
args: {},
|
||||
args: { 'aria-label': 'Checkbox' },
|
||||
argTypes: {
|
||||
variant: { control: false },
|
||||
size: { control: false },
|
||||
@@ -49,8 +49,7 @@ export const Catalog: CatalogStory<Story, typeof Checkbox> = {
|
||||
accent: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
catalog: {
|
||||
dimensions: [
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@ export const ColorPickerButton = ({
|
||||
<LightIconButton
|
||||
size="medium"
|
||||
Icon={() => <ColorSample colorName={colorName} />}
|
||||
aria-label={`Select ${colorName} color`}
|
||||
onClick={onClick}
|
||||
/>
|
||||
</div>
|
||||
|
||||
+1
-6
@@ -12,13 +12,8 @@ const meta: Meta<typeof ColorPickerButton> = {
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof ColorPickerButton>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
};
|
||||
export const Default: Story = {};
|
||||
|
||||
export const Selected: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
args: { isSelected: true },
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ export type FloatingButtonProps = {
|
||||
className?: string;
|
||||
Icon?: IconComponent;
|
||||
title?: string;
|
||||
ariaLabel?: string;
|
||||
size?: FloatingButtonSize;
|
||||
position?: FloatingButtonPosition;
|
||||
applyShadow?: boolean;
|
||||
@@ -27,6 +28,7 @@ export const FloatingButton = ({
|
||||
className,
|
||||
Icon,
|
||||
title,
|
||||
ariaLabel,
|
||||
size = 'small',
|
||||
position = 'standalone',
|
||||
applyBlur = true,
|
||||
@@ -46,6 +48,7 @@ export const FloatingButton = ({
|
||||
return (
|
||||
<ButtonComponent
|
||||
disabled={disabled}
|
||||
aria-label={ariaLabel}
|
||||
className={clsx(styles.button, styles[size], className)}
|
||||
data-position={position}
|
||||
data-apply-blur={applyBlur || undefined}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { IconSearch } from '@ui/icon';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -44,8 +45,7 @@ export const Catalog: CatalogStory<Story, typeof FloatingButton> = {
|
||||
focus: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
+16
-10
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { IconCheckbox, IconNotes, IconTimelineEvent } from '@ui/icon';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -20,14 +21,16 @@ export default meta;
|
||||
type Story = StoryObj<typeof FloatingButtonGroup>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
args: {
|
||||
size: 'small',
|
||||
children: [
|
||||
<FloatingButton key="notes" Icon={IconNotes} />,
|
||||
<FloatingButton key="checkbox" Icon={IconCheckbox} />,
|
||||
<FloatingButton key="timeline" Icon={IconTimelineEvent} />,
|
||||
<FloatingButton key="notes" Icon={IconNotes} ariaLabel="Notes" />,
|
||||
<FloatingButton key="checkbox" Icon={IconCheckbox} ariaLabel="Tasks" />,
|
||||
<FloatingButton
|
||||
key="timeline"
|
||||
Icon={IconTimelineEvent}
|
||||
ariaLabel="Timeline"
|
||||
/>,
|
||||
],
|
||||
},
|
||||
argTypes: {
|
||||
@@ -39,9 +42,13 @@ export const Default: Story = {
|
||||
export const Catalog: CatalogStory<Story, typeof FloatingButtonGroup> = {
|
||||
args: {
|
||||
children: [
|
||||
<FloatingButton key="notes" Icon={IconNotes} />,
|
||||
<FloatingButton key="checkbox" Icon={IconCheckbox} />,
|
||||
<FloatingButton key="timeline" Icon={IconTimelineEvent} />,
|
||||
<FloatingButton key="notes" Icon={IconNotes} ariaLabel="Notes" />,
|
||||
<FloatingButton key="checkbox" Icon={IconCheckbox} ariaLabel="Tasks" />,
|
||||
<FloatingButton
|
||||
key="timeline"
|
||||
Icon={IconTimelineEvent}
|
||||
ariaLabel="Timeline"
|
||||
/>,
|
||||
],
|
||||
},
|
||||
argTypes: {
|
||||
@@ -49,8 +56,7 @@ export const Catalog: CatalogStory<Story, typeof FloatingButtonGroup> = {
|
||||
children: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
@@ -16,6 +16,7 @@ export type FloatingIconButtonPosition =
|
||||
export type FloatingIconButtonProps = {
|
||||
className?: string;
|
||||
Icon?: IconComponent;
|
||||
ariaLabel?: string;
|
||||
size?: FloatingIconButtonSize;
|
||||
position?: FloatingIconButtonPosition;
|
||||
applyShadow?: boolean;
|
||||
@@ -29,6 +30,7 @@ export type FloatingIconButtonProps = {
|
||||
export const FloatingIconButton = ({
|
||||
className,
|
||||
Icon,
|
||||
ariaLabel,
|
||||
size = 'small',
|
||||
position = 'standalone',
|
||||
applyShadow = true,
|
||||
@@ -43,6 +45,7 @@ export const FloatingIconButton = ({
|
||||
return (
|
||||
<button
|
||||
disabled={disabled}
|
||||
aria-label={ariaLabel}
|
||||
className={clsx(styles.button, styles[size], className)}
|
||||
data-position={position}
|
||||
data-apply-shadow={applyShadow || undefined}
|
||||
|
||||
+4
-5
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { IconSearch } from '@ui/icon';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -19,8 +20,6 @@ export default meta;
|
||||
type Story = StoryObj<typeof FloatingIconButton>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
args: {
|
||||
size: 'small',
|
||||
disabled: false,
|
||||
@@ -29,6 +28,7 @@ export const Default: Story = {
|
||||
applyShadow: true,
|
||||
position: 'standalone',
|
||||
Icon: IconSearch,
|
||||
ariaLabel: 'Search',
|
||||
},
|
||||
argTypes: {
|
||||
Icon: { control: false },
|
||||
@@ -37,15 +37,14 @@ export const Default: Story = {
|
||||
};
|
||||
|
||||
export const Catalog: CatalogStory<Story, typeof FloatingIconButton> = {
|
||||
args: { Icon: IconSearch },
|
||||
args: { Icon: IconSearch, ariaLabel: 'Search' },
|
||||
argTypes: {
|
||||
size: { control: false },
|
||||
disabled: { control: false },
|
||||
focus: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
@@ -17,6 +17,7 @@ export type FloatingIconButtonGroupProps = Pick<
|
||||
> & {
|
||||
iconButtons: {
|
||||
Icon: IconComponent;
|
||||
ariaLabel?: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onClick?: (event: MouseEvent<any>) => void;
|
||||
isActive?: boolean;
|
||||
@@ -30,7 +31,7 @@ export const FloatingIconButtonGroup = ({
|
||||
}: FloatingIconButtonGroupProps) => {
|
||||
return (
|
||||
<div className={clsx(styles.container, className)}>
|
||||
{iconButtons.map(({ Icon, onClick, isActive }, index) => {
|
||||
{iconButtons.map(({ Icon, onClick, isActive, ariaLabel }, index) => {
|
||||
const position: FloatingIconButtonPosition =
|
||||
iconButtons.length === 1
|
||||
? 'standalone'
|
||||
@@ -46,6 +47,7 @@ export const FloatingIconButtonGroup = ({
|
||||
applyBlur={false}
|
||||
applyShadow={false}
|
||||
Icon={Icon}
|
||||
ariaLabel={ariaLabel}
|
||||
onClick={onClick}
|
||||
position={position}
|
||||
size={size}
|
||||
|
||||
+5
-7
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { IconCheckbox, IconNotes, IconTimelineEvent } from '@ui/icon';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -13,9 +14,9 @@ const meta: Meta<typeof FloatingIconButtonGroup> = {
|
||||
component: FloatingIconButtonGroup,
|
||||
args: {
|
||||
iconButtons: [
|
||||
{ Icon: IconNotes },
|
||||
{ Icon: IconCheckbox },
|
||||
{ Icon: IconTimelineEvent },
|
||||
{ Icon: IconNotes, ariaLabel: 'Notes' },
|
||||
{ Icon: IconCheckbox, ariaLabel: 'Tasks' },
|
||||
{ Icon: IconTimelineEvent, ariaLabel: 'Timeline' },
|
||||
],
|
||||
},
|
||||
argTypes: {
|
||||
@@ -27,8 +28,6 @@ export default meta;
|
||||
type Story = StoryObj<typeof FloatingIconButtonGroup>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
args: {
|
||||
size: 'small',
|
||||
},
|
||||
@@ -40,8 +39,7 @@ export const Catalog: CatalogStory<Story, typeof FloatingIconButtonGroup> = {
|
||||
size: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { IconSearch } from '@ui/icon';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -22,8 +23,6 @@ export default meta;
|
||||
type Story = StoryObj<typeof IconButton>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
args: {
|
||||
size: 'small',
|
||||
variant: 'primary',
|
||||
@@ -32,12 +31,13 @@ export const Default: Story = {
|
||||
focus: false,
|
||||
position: 'standalone',
|
||||
Icon: IconSearch,
|
||||
ariaLabel: 'Search',
|
||||
},
|
||||
decorators: [ComponentDecorator],
|
||||
};
|
||||
|
||||
export const Catalog: CatalogStory<Story, typeof IconButton> = {
|
||||
args: { Icon: IconSearch },
|
||||
args: { Icon: IconSearch, ariaLabel: 'Search' },
|
||||
argTypes: {
|
||||
size: { control: false },
|
||||
variant: { control: false },
|
||||
@@ -48,8 +48,7 @@ export const Catalog: CatalogStory<Story, typeof IconButton> = {
|
||||
position: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
@@ -109,7 +108,7 @@ export const Catalog: CatalogStory<Story, typeof IconButton> = {
|
||||
};
|
||||
|
||||
export const PositionCatalog: CatalogStory<Story, typeof IconButton> = {
|
||||
args: { Icon: IconSearch },
|
||||
args: { Icon: IconSearch, ariaLabel: 'Search' },
|
||||
argTypes: {
|
||||
size: { control: false },
|
||||
variant: { control: false },
|
||||
@@ -120,8 +119,7 @@ export const PositionCatalog: CatalogStory<Story, typeof IconButton> = {
|
||||
Icon: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
@@ -10,6 +10,7 @@ export type IconButtonGroupProps = {
|
||||
disabled?: boolean;
|
||||
iconButtons: {
|
||||
Icon: IconComponent;
|
||||
ariaLabel?: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onClick?: (event: MouseEvent<any>) => void;
|
||||
}[];
|
||||
@@ -26,11 +27,12 @@ export const IconButtonGroup = ({
|
||||
className={clsx(styles.container, className)}
|
||||
data-disabled={disabled || undefined}
|
||||
>
|
||||
{iconButtons.map(({ Icon, onClick }, index) => {
|
||||
{iconButtons.map(({ Icon, onClick, ariaLabel }, index) => {
|
||||
return (
|
||||
<InsideButton
|
||||
key={index}
|
||||
Icon={Icon}
|
||||
ariaLabel={ariaLabel}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
+3
-7
@@ -13,9 +13,9 @@ const meta: Meta<typeof IconButtonGroup> = {
|
||||
component: IconButtonGroup,
|
||||
args: {
|
||||
iconButtons: [
|
||||
{ Icon: IconNotes },
|
||||
{ Icon: IconCheckbox },
|
||||
{ Icon: IconTimelineEvent },
|
||||
{ Icon: IconNotes, ariaLabel: 'Notes' },
|
||||
{ Icon: IconCheckbox, ariaLabel: 'Tasks' },
|
||||
{ Icon: IconTimelineEvent, ariaLabel: 'Timeline' },
|
||||
],
|
||||
},
|
||||
argTypes: {
|
||||
@@ -27,8 +27,6 @@ export default meta;
|
||||
type Story = StoryObj<typeof IconButtonGroup>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
args: {
|
||||
disabled: false,
|
||||
},
|
||||
@@ -40,8 +38,6 @@ export const Catalog: CatalogStory<Story, typeof IconButtonGroup> = {
|
||||
disabled: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ import styles from './InsideButton.module.scss';
|
||||
export type InsideButtonProps = {
|
||||
className?: string;
|
||||
Icon?: IconComponent;
|
||||
ariaLabel?: string;
|
||||
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
disabled?: boolean;
|
||||
};
|
||||
@@ -16,6 +17,7 @@ export type InsideButtonProps = {
|
||||
export const InsideButton = ({
|
||||
className,
|
||||
Icon,
|
||||
ariaLabel,
|
||||
onClick,
|
||||
disabled = false,
|
||||
}: InsideButtonProps) => {
|
||||
@@ -24,6 +26,7 @@ export const InsideButton = ({
|
||||
return (
|
||||
<button
|
||||
className={clsx(styles.button, className)}
|
||||
aria-label={ariaLabel}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
data-disabled={disabled || undefined}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { IconSearch } from '@ui/icon';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -42,8 +43,7 @@ export const Catalog: CatalogStory<Story, typeof LightButton> = {
|
||||
focus: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
+2
-2
@@ -1,6 +1,7 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { IconSearch } from '@ui/icon';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -43,8 +44,7 @@ export const Catalog: CatalogStory<Story, typeof LightIconButton> = {
|
||||
focus: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.pressed'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -33,8 +34,7 @@ export const Catalog: CatalogStory<Story, typeof Radio> = {
|
||||
size: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
catalog: {
|
||||
dimensions: [
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@ export const RoundedIconButton = ({
|
||||
disabled,
|
||||
className,
|
||||
size = 'small',
|
||||
'aria-label': ariaLabel,
|
||||
}: RoundedIconButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
|
||||
@@ -26,6 +27,7 @@ export const RoundedIconButton = ({
|
||||
<button
|
||||
className={clsx(styles.button, styles[size], className)}
|
||||
disabled={disabled}
|
||||
aria-label={ariaLabel}
|
||||
onClick={onClick}
|
||||
>
|
||||
<Icon size={theme.icon.size.md} />
|
||||
|
||||
+1
-3
@@ -15,11 +15,9 @@ export default meta;
|
||||
type Story = StoryObj<typeof RoundedIconButton>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
decorators: [ComponentDecorator],
|
||||
argTypes: { Icon: { control: false } },
|
||||
args: { onClick: clickJestFn, Icon: IconArrowRight },
|
||||
args: { onClick: clickJestFn, Icon: IconArrowRight, 'aria-label': 'Next' },
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from '@ui/icon';
|
||||
import { TabButton } from '@ui/input/TabButton/TabButton';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
AVATAR_URL_MOCK,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
@@ -181,8 +182,7 @@ export const Catalog: CatalogStory<Story, typeof TabButton> = {
|
||||
</TabContainer>
|
||||
),
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
pseudo: { hover: ['.hover'], active: ['.active'] },
|
||||
catalog: {
|
||||
dimensions: [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import {
|
||||
A11Y_DEFER_COLOR_CONTRAST,
|
||||
CatalogDecorator,
|
||||
type CatalogStory,
|
||||
ComponentDecorator,
|
||||
@@ -31,6 +32,7 @@ const InteractiveToggle = ({
|
||||
toggleSize={toggleSize}
|
||||
color={color}
|
||||
disabled={disabled}
|
||||
aria-label="Toggle"
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -44,8 +46,6 @@ export default meta;
|
||||
type Story = StoryObj<typeof InteractiveToggle>;
|
||||
|
||||
export const Default: Story = {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
parameters: { a11y: { test: 'todo' } },
|
||||
args: {
|
||||
initialValue: false,
|
||||
disabled: false,
|
||||
@@ -63,8 +63,7 @@ export const Catalog: CatalogStory<Story, typeof InteractiveToggle> = {
|
||||
color: { control: false },
|
||||
},
|
||||
parameters: {
|
||||
// TODO(a11y): violations inherited from deprecated story; fix during a11y pass
|
||||
a11y: { test: 'todo' },
|
||||
a11y: A11Y_DEFER_COLOR_CONTRAST,
|
||||
catalog: {
|
||||
dimensions: [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { type Parameters } from '@storybook/react-vite';
|
||||
|
||||
export const A11Y_DEFER_COLOR_CONTRAST = {
|
||||
test: 'error',
|
||||
config: { rules: [{ id: 'color-contrast', enabled: false }] },
|
||||
} satisfies Parameters['a11y'];
|
||||
@@ -54,28 +54,32 @@ export const CatalogDecorator: Decorator = (Story, context) => {
|
||||
<div className={styles.container}>
|
||||
{dimension4.values.map((value4: any, index4: number) => (
|
||||
<div className={styles.columnContainer} key={`d4-${index4}`}>
|
||||
<h1 className={styles.columnTitle}>
|
||||
<div className={styles.columnTitle}>
|
||||
{dimension4.labels?.(value4) ??
|
||||
(isStringOrNumber(value4) ? value4 : '')}
|
||||
</h1>
|
||||
</div>
|
||||
{dimension3.values.map((value3: any, index3: number) => (
|
||||
<div className={styles.rowsContainer} key={`d3-${index3}`}>
|
||||
<h2 className={styles.rowsTitle}>
|
||||
<div className={styles.rowsTitle}>
|
||||
{dimension3.labels?.(value3) ??
|
||||
(isStringOrNumber(value3) ? value3 : '')}
|
||||
</h2>
|
||||
</div>
|
||||
{dimension2.values.map((value2: any, index2: number) => (
|
||||
<div className={styles.rowContainer} key={`d2-${index2}`}>
|
||||
<h3 className={styles.rowTitle}>
|
||||
<div className={styles.rowTitle}>
|
||||
{dimension2.labels?.(value2) ??
|
||||
(isStringOrNumber(value2) ? value2 : '')}
|
||||
</h3>
|
||||
</div>
|
||||
{dimension1.values.map((value1: any, index1: number) => {
|
||||
return (
|
||||
<div
|
||||
className={styles.cellContainer}
|
||||
key={`d1-${index1}`}
|
||||
id={value1}
|
||||
id={
|
||||
dimensions.length > 1
|
||||
? `catalog-cell-${index4}-${index3}-${index2}-${index1}`
|
||||
: value1
|
||||
}
|
||||
>
|
||||
<span className={styles.elementTitle}>
|
||||
{dimension1.labels?.(value1) ??
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* |___/
|
||||
*/
|
||||
|
||||
export { A11Y_DEFER_COLOR_CONTRAST } from './a11yParameters';
|
||||
export { ComponentStorybookLayout } from './ComponentStorybookLayout';
|
||||
export type {
|
||||
CatalogDimension,
|
||||
|
||||
Reference in New Issue
Block a user