From de15432861f8d63b30502a1ecf2a6f5244497f65 Mon Sep 17 00:00:00 2001 From: Mohammer5 Date: Wed, 6 Nov 2024 11:12:55 +0800 Subject: [PATCH] fix(select a11y): start writing recipes & fix things found along the way --- collections/forms/i18n/en.pot | 4 +- collections/ui/API.md | 11 +- components/input/API.md | 2 + components/input/src/input/input.js | 8 + components/select/API.md | 6 +- .../single-select-a11y/__stories__/Loading.js | 16 + .../single-select-a11y/menu/menu-filter.js | 20 +- .../single-select-a11y/menu/menu-loading.js | 6 +- .../src/single-select-a11y/menu/menu.js | 89 +- .../src/single-select-a11y/menu/option.js | 7 +- .../selected-value/selected-value.js | 7 +- .../single-select-a11y/single-select-a11y.js | 21 +- .../single-select-a11y.prod.stories.js | 1 + .../use-handle-key-press-on-filter-input.js | 6 + .../use-handle-key-press.js | 6 +- docs/docs/components/single-select-a11y.md | 247 + docs/docs/recipes/recipes.md | 2 + ...ingle-select-a11y-server-side-filtering.js | 266 + ...ingle-select-a11y-server-side-filtering.md | 222 + .../CustomDataProvider.js | 70 + .../dataElements.js | 4271 +++++++++++++++++ .../index.js | 1 + .../single-select-a11y-simple-filtering.js | 54 + .../single-select-a11y-simple-filtering.md | 142 + ...r-infinite-loading-all-options-selected.md | 2 +- 25 files changed, 5413 insertions(+), 74 deletions(-) create mode 100644 components/select/src/single-select-a11y/__stories__/Loading.js create mode 100644 docs/docs/components/single-select-a11y.md create mode 100644 docs/docs/recipes/single-select-a11y-server-side-filtering.js create mode 100644 docs/docs/recipes/single-select-a11y-server-side-filtering.md create mode 100644 docs/docs/recipes/single-select-a11y-server-side-filtering/CustomDataProvider.js create mode 100644 docs/docs/recipes/single-select-a11y-server-side-filtering/dataElements.js create mode 100644 docs/docs/recipes/single-select-a11y-server-side-filtering/index.js create mode 100644 docs/docs/recipes/single-select-a11y-simple-filtering.js create mode 100644 docs/docs/recipes/single-select-a11y-simple-filtering.md diff --git a/collections/forms/i18n/en.pot b/collections/forms/i18n/en.pot index 375e2a0932..fa82bdf6da 100644 --- a/collections/forms/i18n/en.pot +++ b/collections/forms/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-10-28T03:31:24.818Z\n" -"PO-Revision-Date: 2024-10-28T03:31:24.818Z\n" +"POT-Creation-Date: 2024-11-04T09:32:49.754Z\n" +"PO-Revision-Date: 2024-11-04T09:32:49.755Z\n" msgid "Upload file" msgstr "Upload file" diff --git a/collections/ui/API.md b/collections/ui/API.md index 70bccb9efb..ba40672e3a 100644 --- a/collections/ui/API.md +++ b/collections/ui/API.md @@ -761,6 +761,8 @@ import { Input } from '@dhis2/ui' |Name|Type|Default|Required|Description| |---|---|---|---|---| |ariaLabel|string|||Add an aria-label attribute to the input element *| +|ariaControls|string|||Add an aria-controls attribute to the input element *| +|ariaHaspopup|string|||Add an aria-haspopup attribute to the input element *| |autoComplete|string|||The [native `autocomplete` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-autocomplete)| |className|string|||| |dataTest|string|`'dhis2-uicore-input'`||| @@ -1858,18 +1860,18 @@ import { SingleSelectA11y } from '@dhis2/ui' |---|---|---|---|---| |idPrefix|string||*|necessary for IDs that are required for accessibility *| |options|arrayOf(custom)||*|An array of options *| -|value|string|`''`||As of now, this component does not support being uncontrolled *| |onChange|function||*|A callback that will be called with the new value or an empty string *| |autoFocus|boolean|`false`||Will focus the select initially *| |className|string|`''`||Additional class names that will be applied to the root element *| |clearText|custom|`''`||This will allow us to put an aria-label on the clear button *| |clearable|boolean|`false`||Whether a clear button should be displayed or not *| -|customOption|elementType|||Allows to override what's rendered inside the `button[role="option"]`.
Can be overriden on an individual option basis *| +|customOption|elementType|`undefined`||Allows to override what's rendered inside the `button[role="option"]`.
Can be overriden on an individual option basis *| |dataTest|string|`'dhis2-singleselecta11y'`||A value for a `data-test` attribute on the root element *| |dense|boolean|`false`||Renders a select with lower height *| |disabled|boolean|`false`||Disables all interactions with the select (except focussing) *| |empty|node|`false`||Text or component to display when there are no options *| |error|custom|`false`||Applies 'error' appearance for validation feedback. Mutually exclusive with `warning` and `valid` props *| +|filterHelpText|string|`''`||Help text that will be displayed below the input *| |filterLabel|string|`''`||Value will be used as aria-label attribute on the filter input *| |filterPlaceholder|string|`''`||Placeholder for the filter input *| |filterValue|string|`''`||Value of the filter input *| @@ -1884,9 +1886,11 @@ import { SingleSelectA11y } from '@dhis2/ui' |prefix|string|`''`||String that will be displayed before the label of the selected option *| |tabIndex|string │ number|`'0'`||Standard HTML tab-index attribute that will be put on the combobox's root element *| |valid|custom|`false`||Applies 'valid' appearance for validation feedback. Mutually exclusive with `warning` and `valid` props *| +|value|string|`''`||As of now, this component does not support being uncontrolled *| |valueLabel|custom|`''`||When the option is not in the options list (e.g. not loaded or list is
filtered), but a selected value needs to be displayed, then this prop can
be used to supply the text to be shown.| |warning|custom|`false`||Applies 'warning' appearance for validation feedback. Mutually exclusive with `warning` and `valid` props *| |onBlur|function|`() => undefined`||Will be called when the combobox is loses focus *| +|onEndReached|function|||Will be called when the last option is scrolled into the visible area *| |onFilterChange|function|`() => undefined`||Will be called when the filter value changes *| |onFocus|function|`() => undefined`||Will be called when the combobox is being focused *| @@ -2004,7 +2008,10 @@ import { Menu } from '@dhis2/ui' |selected|string|||| |onBlur|function|||| |onClose|function|||| +|onEndReached|function|||| |onFilterChange|function|||| +|onFilterInputKeyDown|function|||| +|onSearch|function|||| ### SelectorBar diff --git a/components/input/API.md b/components/input/API.md index bacd97cc96..22459332e5 100644 --- a/components/input/API.md +++ b/components/input/API.md @@ -15,6 +15,8 @@ import { Input } from '@dhis2/ui' |Name|Type|Default|Required|Description| |---|---|---|---|---| |ariaLabel|string|||Add an aria-label attribute to the input element *| +|ariaControls|string|||Add an aria-controls attribute to the input element *| +|ariaHaspopup|string|||Add an aria-haspopup attribute to the input element *| |autoComplete|string|||The [native `autocomplete` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-autocomplete)| |className|string|||| |dataTest|string|`'dhis2-uicore-input'`||| diff --git a/components/input/src/input/input.js b/components/input/src/input/input.js index 4035684da2..55be46db95 100644 --- a/components/input/src/input/input.js +++ b/components/input/src/input/input.js @@ -138,6 +138,8 @@ export class Input extends Component { const { role, ariaLabel, + ariaControls, + ariaHaspopup, className, type = 'text', dense, @@ -162,6 +164,8 @@ export class Input extends Component {
Can be overriden on an individual option basis *| +|customOption|elementType|`undefined`||Allows to override what's rendered inside the `button[role="option"]`.
Can be overriden on an individual option basis *| |dataTest|string|`'dhis2-singleselecta11y'`||A value for a `data-test` attribute on the root element *| |dense|boolean|`false`||Renders a select with lower height *| |disabled|boolean|`false`||Disables all interactions with the select (except focussing) *| |empty|node|`false`||Text or component to display when there are no options *| |error|custom|`false`||Applies 'error' appearance for validation feedback. Mutually exclusive with `warning` and `valid` props *| +|filterHelpText|string|`''`||Help text that will be displayed below the input *| |filterLabel|string|`''`||Value will be used as aria-label attribute on the filter input *| |filterPlaceholder|string|`''`||Placeholder for the filter input *| |filterValue|string|`''`||Value of the filter input *| @@ -203,9 +203,11 @@ import { SingleSelectA11y } from '@dhis2/ui' |prefix|string|`''`||String that will be displayed before the label of the selected option *| |tabIndex|string │ number|`'0'`||Standard HTML tab-index attribute that will be put on the combobox's root element *| |valid|custom|`false`||Applies 'valid' appearance for validation feedback. Mutually exclusive with `warning` and `valid` props *| +|value|string|`''`||As of now, this component does not support being uncontrolled *| |valueLabel|custom(function)|`''`||When the option is not in the options list (e.g. not loaded or list is
filtered), but a selected value needs to be displayed, then this prop can
be used to supply the text to be shown.| |warning|custom|`false`||Applies 'warning' appearance for validation feedback. Mutually exclusive with `warning` and `valid` props *| |onBlur|function|`() => undefined`||Will be called when the combobox is loses focus *| +|onEndReached|function|||Will be called when the last option is scrolled into the visible area *| |onFilterChange|function|`() => undefined`||Will be called when the filter value changes *| |onFocus|function|`() => undefined`||Will be called when the combobox is being focused *| diff --git a/components/select/src/single-select-a11y/__stories__/Loading.js b/components/select/src/single-select-a11y/__stories__/Loading.js new file mode 100644 index 0000000000..8e95a0b44b --- /dev/null +++ b/components/select/src/single-select-a11y/__stories__/Loading.js @@ -0,0 +1,16 @@ +import React from 'react' +import { SingleSelectA11y } from '../single-select-a11y.js' +import { options } from './options.js' + +export const Loading = () => { + return ( + null} + options={options} + /> + ) +} diff --git a/components/select/src/single-select-a11y/menu/menu-filter.js b/components/select/src/single-select-a11y/menu/menu-filter.js index 8d6aee1738..828ed0ec55 100644 --- a/components/select/src/single-select-a11y/menu/menu-filter.js +++ b/components/select/src/single-select-a11y/menu/menu-filter.js @@ -5,18 +5,20 @@ import React from 'react' import i18n from '../../locales/index.js' export function MenuFilter({ + dataTest, idPrefix, + label, + placeholder, + tabIndex, value, onChange, - dataTest, - placeholder, - label, onKeyDown, }) { return (
{` div { - position: sticky; + height: 100%; inset-block-start: 0; background: ${colors.white}; - padding-block-start: ${spacers.dp8}; - padding-inline-end: ${spacers.dp8}; - padding-block-end: ${spacers.dp4}; - padding-inline-start: ${spacers.dp8}; - z-index: 1; + // padding-block-start: ${spacers.dp8}; + // padding-inline-end: ${spacers.dp8}; + // padding-block-end: ${spacers.dp4}; + // padding-inline-start: ${spacers.dp8}; } `}
@@ -52,5 +53,6 @@ MenuFilter.propTypes = { dataTest: PropTypes.string, label: PropTypes.string, placeholder: PropTypes.string, + tabIndex: PropTypes.string, onKeyDown: PropTypes.func, } diff --git a/components/select/src/single-select-a11y/menu/menu-loading.js b/components/select/src/single-select-a11y/menu/menu-loading.js index cdf7cbe500..936db63910 100644 --- a/components/select/src/single-select-a11y/menu/menu-loading.js +++ b/components/select/src/single-select-a11y/menu/menu-loading.js @@ -14,9 +14,9 @@ export function MenuLoading({ message }) {