Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Composite: export useCompositeStore, add more focus-related props #64450

Merged
merged 4 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- `Composite`: add stable version of the component ([#63564](https://github.com/WordPress/gutenberg/pull/63564)).
- `Composite`: add `Hover` and `Typeahead` subcomponents ([#64399](https://github.com/WordPress/gutenberg/pull/64399)).
- `Composite`: export `useCompositeStore, add focus-related props to `Composite`and`Composite.Item` subcomponents ([#64450](https://github.com/WordPress/gutenberg/pull/64450)).

### Enhancements

Expand Down
67 changes: 67 additions & 0 deletions packages/components/src/composite/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,55 @@ Allows the component to be rendered as a different HTML element or React compone

- Required: no

##### `focusable`: `boolean`

Makes the component a focusable element. When this element gains keyboard focus, it gets a `data-focus-visible` attribute and triggers the `onFocusVisible` prop.

The component supports the `disabled` prop even for those elements not supporting the native `disabled` attribute. Disabled elements may be still accessible via keyboard by using the the `accessibleWhenDisabled` prop.

Non-native focusable elements will lose their focusability entirely. However, native focusable elements will retain their inherent focusability.

- Required: no

##### `disabled`: `boolean`

Determines if the element is disabled. This sets the `aria-disabled` attribute accordingly, enabling support for all elements, including those that don't support the native `disabled` attribute.

This feature can be combined with the `accessibleWhenDisabled` prop to
make disabled elements still accessible via keyboard.

**Note**: For this prop to work, the `focusable` prop must be set to
`true`, if it's not set by default.

- Required: no
- Default: `false`

##### `accessibleWhenDisabled`: `boolean`

Indicates whether the element should be focusable even when it is
`disabled`.

This is important when discoverability is a concern. For example:

> A toolbar in an editor contains a set of special smart paste functions
> that are disabled when the clipboard is empty or when the function is not
> applicable to the current content of the clipboard. It could be helpful to
> keep the disabled buttons focusable if the ability to discover their
> functionality is primarily via their presence on the toolbar.

Learn more on [Focusability of disabled
controls](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#focusabilityofdisabledcontrols).

- Required: no

##### `onFocusVisible`: `(event: SyntheticEvent<HTMLElement>) => void`

Custom event handler invoked when the element gains focus through keyboard interaction or a key press occurs while the element is in focus. This is the programmatic equivalent of the `data-focus-visible` attribute.

**Note**: For this prop to work, the `focusable` prop must be set to `true` if it's not set by default.

- Required: no

##### `children`: `React.ReactNode`

The contents of the component.
Expand Down Expand Up @@ -189,6 +238,24 @@ The contents of the component.

Renders a composite item.

##### `accessibleWhenDisabled`: `boolean`

Indicates whether the element should be focusable even when it is
`disabled`.

This is important when discoverability is a concern. For example:

> A toolbar in an editor contains a set of special smart paste functions
> that are disabled when the clipboard is empty or when the function is not
> applicable to the current content of the clipboard. It could be helpful to
> keep the disabled buttons focusable if the ability to discover their
> functionality is primarily via their presence on the toolbar.

Learn more on [Focusability of disabled
controls](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#focusabilityofdisabledcontrols).

- Required: no

##### `render`: `RenderProp<React.HTMLAttributes<any> & { ref?: React.Ref<any> | undefined; }> | React.ReactElement<any, string | React.JSXElementConstructor<any>>`

Allows the component to be rendered as a different HTML element or React component. The value can be a React element or a function that takes in the original component props and gives back a React element with the props merged.
Expand Down
6 changes: 4 additions & 2 deletions packages/components/src/composite/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,10 @@ export const Composite = Object.assign(
forwardRef<
HTMLDivElement,
WordPressComponentProps< CompositeProps, 'div', false >
>( function CompositeRow( props, ref ) {
return <Ariakit.Composite { ...props } ref={ ref } />;
>( function Composite( { disabled = false, ...props }, ref ) {
return (
<Ariakit.Composite disabled={ disabled } { ...props } ref={ ref } />
);
} ),
{
displayName: 'Composite',
Expand Down
71 changes: 70 additions & 1 deletion packages/components/src/composite/stories/index.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,28 @@ const meta: Meta< typeof UseCompositeStorePlaceholder > = {
table: { type: { summary: 'React.ReactNode' } },
},
};
const accessibleWhenDisabled = {
name: 'accessibleWhenDisabled',
description: `Indicates whether the element should be focusable even when it is
\`disabled\`.

This is important when discoverability is a concern. For example:

> A toolbar in an editor contains a set of special smart paste functions
> that are disabled when the clipboard is empty or when the function is not
> applicable to the current content of the clipboard. It could be helpful to
> keep the disabled buttons focusable if the ability to discover their
> functionality is primarily via their presence on the toolbar.

Learn more on [Focusability of disabled
controls](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#focusabilityofdisabledcontrols).`,
table: {
type: {
summary: 'boolean',
},
},
};

const argTypes = {
useCompositeStore: {
activeId: {
Expand Down Expand Up @@ -226,11 +248,58 @@ This only affects the composite widget behavior. You still need to set \`dir="rt
},
type: { required: true },
},
focusable: {
name: 'focusable',
description: `Makes the component a focusable element. When this element gains keyboard focus, it gets a \`data-focus-visible\` attribute and triggers the \`onFocusVisible\` prop.

The component supports the \`disabled\` prop even for those elements not supporting the native \`disabled\` attribute. Disabled elements may be still accessible via keyboard by using the the \`accessibleWhenDisabled\` prop.

Non-native focusable elements will lose their focusability entirely. However, native focusable elements will retain their inherent focusability.`,
table: {
type: {
summary: 'boolean',
},
},
},
disabled: {
name: 'disabled',
description: `Determines if the element is disabled. This sets the \`aria-disabled\` attribute accordingly, enabling support for all elements, including those that don't support the native \`disabled\` attribute.

This feature can be combined with the \`accessibleWhenDisabled\` prop to
make disabled elements still accessible via keyboard.

**Note**: For this prop to work, the \`focusable\` prop must be set to
\`true\`, if it's not set by default.`,
table: {
defaultValue: {
summary: 'false',
},
type: {
summary: 'boolean',
},
},
},
accessibleWhenDisabled,
onFocusVisible: {
name: 'onFocusVisible',
description: `Custom event handler invoked when the element gains focus through keyboard interaction or a key press occurs while the element is in focus. This is the programmatic equivalent of the \`data-focus-visible\` attribute.

**Note**: For this prop to work, the \`focusable\` prop must be set to \`true\` if it's not set by default.`,
table: {
type: {
summary:
'(event: SyntheticEvent<HTMLElement>) => void',
},
},
},
},
'Composite.Group': commonArgTypes,
'Composite.GroupLabel': commonArgTypes,
'Composite.Row': commonArgTypes,
'Composite.Item': commonArgTypes,
'Composite.Item': {
...commonArgTypes,
accessibleWhenDisabled,
},
'Composite.Hover': commonArgTypes,
'Composite.Typeahead': commonArgTypes,
};
Expand Down
67 changes: 67 additions & 0 deletions packages/components/src/composite/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,57 @@ export type CompositeProps = {
* merged.
*/
render?: Ariakit.CompositeProps[ 'render' ];
/**
* Makes the component a focusable element. When this element gains keyboard
* focus, it gets a `data-focus-visible` attribute and triggers the
* `onFocusVisible` prop.
* The component supports the `disabled` prop even for those elements not
* supporting the native `disabled` attribute. Disabled elements may be
* still accessible via keyboard by using the the `accessibleWhenDisabled`
* prop.
* Non-native focusable elements will lose their focusability entirely.
* However, native focusable elements will retain their inherent focusability.
*/
focusable?: Ariakit.CompositeProps[ 'focusable' ];
/**
* Determines if the element is disabled. This sets the `aria-disabled`
* attribute accordingly, enabling support for all elements, including those
* that don't support the native `disabled` attribute.
*
* This feature can be combined with the `accessibleWhenDisabled` prop to
* make disabled elements still accessible via keyboard.
*
* **Note**: For this prop to work, the `focusable` prop must be set to
* `true`, if it's not set by default.
*
* @default false
*/
disabled?: Ariakit.CompositeProps[ 'disabled' ];
/**
* Indicates whether the element should be focusable even when it is
* `disabled`.
*
* This is important when discoverability is a concern. For example:
*
* > A toolbar in an editor contains a set of special smart paste functions
* that are disabled when the clipboard is empty or when the function is not
* applicable to the current content of the clipboard. It could be helpful to
* keep the disabled buttons focusable if the ability to discover their
* functionality is primarily via their presence on the toolbar.
*
* Learn more on [Focusability of disabled
* controls](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#focusabilityofdisabledcontrols).
*/
accessibleWhenDisabled?: Ariakit.CompositeProps[ 'accessibleWhenDisabled' ];
/**
* Custom event handler invoked when the element gains focus through keyboard
* interaction or a key press occurs while the element is in focus. This is
* the programmatic equivalent of the `data-focus-visible` attribute.
*
* **Note**: For this prop to work, the `focusable` prop must be set to `true`
* if it's not set by default.
*/
onFocusVisible?: Ariakit.CompositeProps[ 'onFocusVisible' ];
/**
* The contents of the component.
*/
Expand Down Expand Up @@ -177,6 +228,22 @@ export type CompositeItemProps = {
* The contents of the component.
*/
children?: Ariakit.CompositeItemProps[ 'children' ];
/**
* Indicates whether the element should be focusable even when it is
* `disabled`.
*
* This is important when discoverability is a concern. For example:
*
* > A toolbar in an editor contains a set of special smart paste functions
* that are disabled when the clipboard is empty or when the function is not
* applicable to the current content of the clipboard. It could be helpful to
* keep the disabled buttons focusable if the ability to discover their
* functionality is primarily via their presence on the toolbar.
*
* Learn more on [Focusability of disabled
* controls](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#focusabilityofdisabledcontrols).
*/
accessibleWhenDisabled?: Ariakit.CompositeItemProps[ 'accessibleWhenDisabled' ];
};

export type CompositeRowProps = {
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export {
CompositeItem as __unstableCompositeItem,
useCompositeState as __unstableUseCompositeState,
} from './composite/legacy';
export { Composite } from './composite';
export { Composite, useCompositeStore } from './composite';
export { ConfirmDialog as __experimentalConfirmDialog } from './confirm-dialog';
export { default as CustomSelectControl } from './custom-select-control';
export { default as Dashicon } from './dashicon';
Expand Down
Loading