@allxsmith/bestax-bulma 5.32.0 → 5.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/bestax.css +1 -1
  2. package/dist/bestax.css.map +1 -1
  3. package/dist/esm/components/Avatars.js +4 -21
  4. package/dist/esm/components/Avatars.js.map +1 -1
  5. package/dist/esm/components/Collapses.js +1 -20
  6. package/dist/esm/components/Collapses.js.map +1 -1
  7. package/dist/esm/elements/Kbd.js +86 -0
  8. package/dist/esm/elements/Kbd.js.map +1 -0
  9. package/dist/esm/form/Autocomplete.js +59 -14
  10. package/dist/esm/form/Autocomplete.js.map +1 -1
  11. package/dist/esm/helpers/flattenChildren.js +35 -0
  12. package/dist/esm/helpers/flattenChildren.js.map +1 -0
  13. package/dist/esm/helpers/statusRegion.js +19 -12
  14. package/dist/esm/helpers/statusRegion.js.map +1 -1
  15. package/dist/extras.css +1 -1
  16. package/dist/extras.css.map +1 -1
  17. package/dist/index.cjs +254 -134
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.esm.js +1 -0
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/types/elements/Kbd.d.ts +100 -0
  22. package/dist/types/form/Autocomplete.d.ts +18 -3
  23. package/dist/types/helpers/flattenChildren.d.ts +16 -0
  24. package/dist/types/helpers/statusRegion.d.ts +4 -4
  25. package/dist/types/index.d.ts +1 -0
  26. package/dist/types-cjs/elements/Kbd.d.ts +100 -0
  27. package/dist/types-cjs/form/Autocomplete.d.ts +18 -3
  28. package/dist/types-cjs/helpers/flattenChildren.d.ts +16 -0
  29. package/dist/types-cjs/helpers/statusRegion.d.ts +4 -4
  30. package/dist/types-cjs/index.d.ts +1 -0
  31. package/dist/versions/bestax-no-dark-mode.css +1 -1
  32. package/dist/versions/bestax-no-dark-mode.css.map +1 -1
  33. package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
  34. package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
  35. package/dist/versions/bestax-no-helpers.css +1 -1
  36. package/dist/versions/bestax-no-helpers.css.map +1 -1
  37. package/dist/versions/bestax-prefixed.css +1 -1
  38. package/dist/versions/bestax-prefixed.css.map +1 -1
  39. package/package.json +1 -1
  40. package/src/scss/elements/_index.scss +1 -0
  41. package/src/scss/elements/_kbd.scss +86 -0
@@ -6,6 +6,7 @@ import { withSubComponents } from '../helpers/withSubComponents.js';
6
6
  import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
7
7
  import { Collapse } from './Collapse.js';
8
8
  import { CollapsesItemContext } from './collapsesContext.js';
9
+ import { flattenChildren } from '../helpers/flattenChildren.js';
9
10
 
10
11
  /** Either mode's value as the list of open indexes. */
11
12
  function toIndexes(value) {
@@ -13,26 +14,6 @@ function toIndexes(value) {
13
14
  return value;
14
15
  return typeof value === 'number' ? [value] : [];
15
16
  }
16
- /**
17
- * Flattens Fragment children (recursively) so each item inside one gets its
18
- * own index rather than sharing the fragment's. Children.toArray keys restart
19
- * at ".0" inside each fragment, so those children are re-keyed with the
20
- * fragment's own key as a prefix, the way Avatars does it.
21
- */
22
- function flattenChildren(children, keyPrefix = '') {
23
- return React.Children.toArray(children).flatMap(child => {
24
- if (!React.isValidElement(child))
25
- return [child];
26
- if (child.type === React.Fragment) {
27
- return flattenChildren(child.props.children, keyPrefix + child.key);
28
- }
29
- return [
30
- keyPrefix
31
- ? React.cloneElement(child, { key: keyPrefix + child.key })
32
- : child,
33
- ];
34
- });
35
- }
36
17
  /**
37
18
  * The `Collapses` component groups `Collapse` items into an accordion that keeps one item open at a time, or any number with `multiple`.
38
19
  *
@@ -1 +1 @@
1
- {"version":3,"file":"Collapses.js","sources":["../../../src/components/Collapses.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { Collapse } from './Collapse';\nimport { CollapsesItemContext } from './collapsesContext';\n\n/**\n * Props shared by both modes of the Collapses component.\n */\ninterface CollapsesBaseProps\n extends\n Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'color' | 'defaultValue' | 'onChange'\n >,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Joins the items into one block, with no gap between them and only the outer corners rounded. The joins show on `bordered` items. */\n seamless?: boolean;\n /** Additional CSS classes to apply. */\n className?: string;\n /** The `Collapse` items. Each child element is one item, indexed from 0 in order, with the children of a fragment counted one by one. A child that sets its own `open` keeps it: the group leaves that item alone. */\n children?: React.ReactNode;\n}\n\n/**\n * Props for Collapses in single mode, the accordion: opening one item closes the others.\n */\nexport interface CollapsesSingleProps extends CollapsesBaseProps {\n /**\n * Lets items open independently. Without it, opening one item closes the others.\n * @defaultValue false\n */\n multiple?: false;\n /** Controlled open items: the index of the open item, or `null` for none. With `multiple`, an array of indexes. An index is a position among the children, so rendering an item conditionally or reordering them moves the open state onto a neighbour: render every item and hide one with `visibility=\"hidden\"`, or keep `value` in step yourself. */\n value?: number | null;\n /** Open items for uncontrolled use, as an index or `null` (the default, none open). With `multiple`, an array of indexes, empty by default. Indexes are positions among the children, as for `value`. */\n defaultValue?: number | null;\n /** Called with the new open items each time a trigger asks for a change, whether or not `value` is set: an index or `null`, or with `multiple` an array of indexes in ascending order. Indexes are positions among the children, as for `value`. */\n onChange?: (value: number | null) => void;\n}\n\n/**\n * Props for Collapses with `multiple`: items open and close independently.\n */\nexport interface CollapsesMultipleProps extends CollapsesBaseProps {\n /**\n * Lets items open independently. Without it, opening one item closes the others.\n * @defaultValue false\n */\n multiple: true;\n /** Controlled open items: the index of the open item, or `null` for none. With `multiple`, an array of indexes. An index is a position among the children, so rendering an item conditionally or reordering them moves the open state onto a neighbour: render every item and hide one with `visibility=\"hidden\"`, or keep `value` in step yourself. */\n value?: number[];\n /** Open items for uncontrolled use, as an index or `null` (the default, none open). With `multiple`, an array of indexes, empty by default. Indexes are positions among the children, as for `value`. */\n defaultValue?: number[];\n /** Called with the new open items each time a trigger asks for a change, whether or not `value` is set: an index or `null`, or with `multiple` an array of indexes in ascending order. Indexes are positions among the children, as for `value`. */\n onChange?: (value: number[]) => void;\n}\n\n/**\n * Props for the Collapses component, a discriminated union on `multiple`: the open items are an index (or `null`) in single mode and an array of indexes with `multiple`.\n */\nexport type CollapsesProps = CollapsesSingleProps | CollapsesMultipleProps;\n\n/** Either mode's value as the list of open indexes. */\nfunction toIndexes(value: number | number[] | null | undefined): number[] {\n if (Array.isArray(value)) return value;\n return typeof value === 'number' ? [value] : [];\n}\n\n/**\n * Flattens Fragment children (recursively) so each item inside one gets its\n * own index rather than sharing the fragment's. Children.toArray keys restart\n * at \".0\" inside each fragment, so those children are re-keyed with the\n * fragment's own key as a prefix, the way Avatars does it.\n */\nfunction flattenChildren(\n children: React.ReactNode,\n keyPrefix = ''\n): React.ReactNode[] {\n return React.Children.toArray(children).flatMap(child => {\n if (!React.isValidElement(child)) return [child];\n if (child.type === React.Fragment) {\n return flattenChildren(\n (child.props as { children?: React.ReactNode }).children,\n keyPrefix + child.key\n );\n }\n return [\n keyPrefix\n ? React.cloneElement(child, { key: keyPrefix + child.key })\n : child,\n ];\n });\n}\n\n/**\n * The `Collapses` component groups `Collapse` items into an accordion that keeps one item open at a time, or any number with `multiple`.\n *\n * @function\n * @param {CollapsesProps} props - Props for the Collapses component.\n * @returns {JSX.Element} The rendered group.\n *\n * @example\n * // Accordion: one item open at a time, the first to start with\n * <Collapses defaultValue={0}>\n * <Collapse bordered trigger={<strong>Shipping</strong>}>…</Collapse>\n * <Collapse bordered trigger={<strong>Returns</strong>}>…</Collapse>\n * </Collapses>\n *\n * @example\n * // Controlled, with items that open independently\n * const [open, setOpen] = useState<number[]>([]);\n * <Collapses multiple value={open} onChange={setOpen}>…</Collapses>\n */\nconst CollapsesComponent: React.FC<CollapsesProps> = ({\n multiple = false,\n value,\n defaultValue,\n onChange,\n seamless = false,\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });\n\n // Controlled vs uncontrolled, as in Tabs. State is held as a list of open\n // indexes in both modes; `multiple` only decides how a change is computed\n // and which shape `onChange` receives.\n const isControlled = value !== undefined;\n const [internalOpen, setInternalOpen] = useState(() =>\n toIndexes(defaultValue)\n );\n const openIndexes = isControlled ? toIndexes(value) : internalOpen;\n\n // Each mode types `onChange` for its own shape, and the value built below\n // always matches `multiple`, the union's discriminant.\n const reportChange = onChange as\n ((next: number | number[] | null) => void) | undefined;\n\n const setItemOpen = (index: number, open: boolean) => {\n const others = openIndexes.filter(i => i !== index);\n // Single mode keeps at most one item open, so opening one drops the rest.\n // Ascending order, whatever order the items were opened in, so the value\n // reads and compares the same way however the user got there.\n const next = (\n open ? (multiple ? [...others, index] : [index]) : others\n ).sort((a, b) => a - b);\n if (!isControlled) setInternalOpen(next);\n reportChange?.(multiple ? next : (next[0] ?? null));\n };\n\n const groupClasses = usePrefixedClassNames('collapses', {\n 'is-seamless': seamless,\n });\n const combinedClasses = classNames(\n groupClasses,\n bulmaHelperClasses,\n className\n );\n\n const items: React.ReactNode[] = [];\n let index = 0;\n for (const child of flattenChildren(children)) {\n if (!React.isValidElement(child)) {\n items.push(child);\n continue;\n }\n const itemIndex = index;\n index += 1;\n items.push(\n <CollapsesItemContext.Provider\n key={child.key}\n value={{\n open: openIndexes.includes(itemIndex),\n setOpen: open => setItemOpen(itemIndex, open),\n }}\n >\n {child}\n </CollapsesItemContext.Provider>\n );\n }\n\n return (\n <div className={combinedClasses} {...rest}>\n {items}\n </div>\n );\n};\n\nexport const Collapses = withSubComponents(\n CollapsesComponent,\n { Collapse },\n 'Collapses'\n);\n\nexport default Collapses;\n"],"names":["_jsx"],"mappings":"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"}
1
+ {"version":3,"file":"Collapses.js","sources":["../../../src/components/Collapses.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { Collapse } from './Collapse';\nimport { CollapsesItemContext } from './collapsesContext';\nimport { flattenChildren } from '../helpers/flattenChildren';\n\n/**\n * Props shared by both modes of the Collapses component.\n */\ninterface CollapsesBaseProps\n extends\n Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'color' | 'defaultValue' | 'onChange'\n >,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Joins the items into one block, with no gap between them and only the outer corners rounded. The joins show on `bordered` items. */\n seamless?: boolean;\n /** Additional CSS classes to apply. */\n className?: string;\n /** The `Collapse` items. Each child element is one item, indexed from 0 in order, with the children of a fragment counted one by one. A child that sets its own `open` keeps it: the group leaves that item alone. */\n children?: React.ReactNode;\n}\n\n/**\n * Props for Collapses in single mode, the accordion: opening one item closes the others.\n */\nexport interface CollapsesSingleProps extends CollapsesBaseProps {\n /**\n * Lets items open independently. Without it, opening one item closes the others.\n * @defaultValue false\n */\n multiple?: false;\n /** Controlled open items: the index of the open item, or `null` for none. With `multiple`, an array of indexes. An index is a position among the children, so rendering an item conditionally or reordering them moves the open state onto a neighbour: render every item and hide one with `visibility=\"hidden\"`, or keep `value` in step yourself. */\n value?: number | null;\n /** Open items for uncontrolled use, as an index or `null` (the default, none open). With `multiple`, an array of indexes, empty by default. Indexes are positions among the children, as for `value`. */\n defaultValue?: number | null;\n /** Called with the new open items each time a trigger asks for a change, whether or not `value` is set: an index or `null`, or with `multiple` an array of indexes in ascending order. Indexes are positions among the children, as for `value`. */\n onChange?: (value: number | null) => void;\n}\n\n/**\n * Props for Collapses with `multiple`: items open and close independently.\n */\nexport interface CollapsesMultipleProps extends CollapsesBaseProps {\n /**\n * Lets items open independently. Without it, opening one item closes the others.\n * @defaultValue false\n */\n multiple: true;\n /** Controlled open items: the index of the open item, or `null` for none. With `multiple`, an array of indexes. An index is a position among the children, so rendering an item conditionally or reordering them moves the open state onto a neighbour: render every item and hide one with `visibility=\"hidden\"`, or keep `value` in step yourself. */\n value?: number[];\n /** Open items for uncontrolled use, as an index or `null` (the default, none open). With `multiple`, an array of indexes, empty by default. Indexes are positions among the children, as for `value`. */\n defaultValue?: number[];\n /** Called with the new open items each time a trigger asks for a change, whether or not `value` is set: an index or `null`, or with `multiple` an array of indexes in ascending order. Indexes are positions among the children, as for `value`. */\n onChange?: (value: number[]) => void;\n}\n\n/**\n * Props for the Collapses component, a discriminated union on `multiple`: the open items are an index (or `null`) in single mode and an array of indexes with `multiple`.\n */\nexport type CollapsesProps = CollapsesSingleProps | CollapsesMultipleProps;\n\n/** Either mode's value as the list of open indexes. */\nfunction toIndexes(value: number | number[] | null | undefined): number[] {\n if (Array.isArray(value)) return value;\n return typeof value === 'number' ? [value] : [];\n}\n\n/**\n * The `Collapses` component groups `Collapse` items into an accordion that keeps one item open at a time, or any number with `multiple`.\n *\n * @function\n * @param {CollapsesProps} props - Props for the Collapses component.\n * @returns {JSX.Element} The rendered group.\n *\n * @example\n * // Accordion: one item open at a time, the first to start with\n * <Collapses defaultValue={0}>\n * <Collapse bordered trigger={<strong>Shipping</strong>}>…</Collapse>\n * <Collapse bordered trigger={<strong>Returns</strong>}>…</Collapse>\n * </Collapses>\n *\n * @example\n * // Controlled, with items that open independently\n * const [open, setOpen] = useState<number[]>([]);\n * <Collapses multiple value={open} onChange={setOpen}>…</Collapses>\n */\nconst CollapsesComponent: React.FC<CollapsesProps> = ({\n multiple = false,\n value,\n defaultValue,\n onChange,\n seamless = false,\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });\n\n // Controlled vs uncontrolled, as in Tabs. State is held as a list of open\n // indexes in both modes; `multiple` only decides how a change is computed\n // and which shape `onChange` receives.\n const isControlled = value !== undefined;\n const [internalOpen, setInternalOpen] = useState(() =>\n toIndexes(defaultValue)\n );\n const openIndexes = isControlled ? toIndexes(value) : internalOpen;\n\n // Each mode types `onChange` for its own shape, and the value built below\n // always matches `multiple`, the union's discriminant.\n const reportChange = onChange as\n ((next: number | number[] | null) => void) | undefined;\n\n const setItemOpen = (index: number, open: boolean) => {\n const others = openIndexes.filter(i => i !== index);\n // Single mode keeps at most one item open, so opening one drops the rest.\n // Ascending order, whatever order the items were opened in, so the value\n // reads and compares the same way however the user got there.\n const next = (\n open ? (multiple ? [...others, index] : [index]) : others\n ).sort((a, b) => a - b);\n if (!isControlled) setInternalOpen(next);\n reportChange?.(multiple ? next : (next[0] ?? null));\n };\n\n const groupClasses = usePrefixedClassNames('collapses', {\n 'is-seamless': seamless,\n });\n const combinedClasses = classNames(\n groupClasses,\n bulmaHelperClasses,\n className\n );\n\n const items: React.ReactNode[] = [];\n let index = 0;\n for (const child of flattenChildren(children)) {\n if (!React.isValidElement(child)) {\n items.push(child);\n continue;\n }\n const itemIndex = index;\n index += 1;\n items.push(\n <CollapsesItemContext.Provider\n key={child.key}\n value={{\n open: openIndexes.includes(itemIndex),\n setOpen: open => setItemOpen(itemIndex, open),\n }}\n >\n {child}\n </CollapsesItemContext.Provider>\n );\n }\n\n return (\n <div className={combinedClasses} {...rest}>\n {items}\n </div>\n );\n};\n\nexport const Collapses = withSubComponents(\n CollapsesComponent,\n { Collapse },\n 'Collapses'\n);\n\nexport default Collapses;\n"],"names":["_jsx"],"mappings":";;;;;;;;;;AAiEA;AACA,SAAS,SAAS,CAAC,KAA2C,EAAA;AAC5D,IAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,KAAK;AACtC,IAAA,OAAO,OAAO,KAAK,KAAK,QAAQ,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE;AACjD;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACH,MAAM,kBAAkB,GAA6B,CAAC,EACpD,QAAQ,GAAG,KAAK,EAChB,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,KAAI;AACH,IAAA,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;;;;AAKlE,IAAA,MAAM,YAAY,GAAG,KAAK,KAAK,SAAS;AACxC,IAAA,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,MAC/C,SAAS,CAAC,YAAY,CAAC,CACxB;AACD,IAAA,MAAM,WAAW,GAAG,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,YAAY;;;IAIlE,MAAM,YAAY,GAAG,QACmC;AAExD,IAAA,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,IAAa,KAAI;AACnD,QAAA,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC;;;;QAInD,MAAM,IAAI,GAAG,CACX,IAAI,IAAI,QAAQ,GAAG,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,MAAM,EACzD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACvB,QAAA,IAAI,CAAC,YAAY;YAAE,eAAe,CAAC,IAAI,CAAC;AACxC,QAAA,YAAY,GAAG,QAAQ,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;AACrD,IAAA,CAAC;AAED,IAAA,MAAM,YAAY,GAAG,qBAAqB,CAAC,WAAW,EAAE;AACtD,QAAA,aAAa,EAAE,QAAQ;AACxB,KAAA,CAAC;IACF,MAAM,eAAe,GAAG,UAAU,CAChC,YAAY,EACZ,kBAAkB,EAClB,SAAS,CACV;IAED,MAAM,KAAK,GAAsB,EAAE;IACnC,IAAI,KAAK,GAAG,CAAC;IACb,KAAK,MAAM,KAAK,IAAI,eAAe,CAAC,QAAQ,CAAC,EAAE;QAC7C,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE;AAChC,YAAA,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;YACjB;QACF;QACA,MAAM,SAAS,GAAG,KAAK;QACvB,KAAK,IAAI,CAAC;QACV,KAAK,CAAC,IAAI,CACRA,GAAA,CAAC,oBAAoB,CAAC,QAAQ,EAAA,EAE5B,KAAK,EAAE;AACL,gBAAA,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC;gBACrC,OAAO,EAAE,IAAI,IAAI,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC;AAC9C,aAAA,EAAA,QAAA,EAEA,KAAK,EAAA,EAND,KAAK,CAAC,GAAG,CAOgB,CACjC;IACH;IAEA,QACEA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,eAAe,EAAA,GAAM,IAAI,EAAA,QAAA,EACtC,KAAK,EAAA,CACF;AAEV,CAAC;AAEM,MAAM,SAAS,GAAG,iBAAiB,CACxC,kBAAkB,EAClB,EAAE,QAAQ,EAAE,EACZ,WAAW;;"}
@@ -0,0 +1,86 @@
1
+ /* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import React, { forwardRef } from 'react';
4
+ import { usePrefixedClassNames, classNames } from '../helpers/classNames.js';
5
+ import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
6
+ import { flattenChildren } from '../helpers/flattenChildren.js';
7
+ import { visuallyHidden } from '../helpers/statusRegion.js';
8
+ import { withSubComponents } from '../helpers/withSubComponents.js';
9
+
10
+ /**
11
+ * Keys pressed together or one after another, in the outer `<kbd>` HTML gives a combination, with the separator between each pair as text.
12
+ *
13
+ * It doesn't wrap in the middle and isn't drawn as a key itself. It sets no
14
+ * font size, so the keys in it are the size of a key on its own.
15
+ *
16
+ * @function
17
+ * @param {KbdGroupProps} props - Props for Kbd.Group.
18
+ * @param {React.Ref<HTMLElement>} ref - Forwarded ref to the outer `<kbd>`.
19
+ * @returns {JSX.Element} The rendered combination.
20
+ *
21
+ * @example
22
+ * <Kbd.Group>
23
+ * <Kbd>Ctrl</Kbd>
24
+ * <Kbd>Shift</Kbd>
25
+ * <Kbd>P</Kbd>
26
+ * </Kbd.Group>
27
+ *
28
+ * @example
29
+ * <Kbd.Group separator="then">
30
+ * <Kbd>G</Kbd>
31
+ * <Kbd>I</Kbd>
32
+ * </Kbd.Group>
33
+ */
34
+ const KbdGroup = forwardRef(({ className, textColor, separator = '+', children, ...props }, ref) => {
35
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
36
+ color: textColor,
37
+ ...props,
38
+ });
39
+ const groupClass = usePrefixedClassNames('kbd-group');
40
+ const separatorClass = usePrefixedClassNames('kbd-separator');
41
+ // Null, undefined and booleans drop out, and Fragments are opened up, so
42
+ // an empty Fragment leaves no separator behind and the keys in one are
43
+ // separated like the rest. The spaces are part of the text, so a screen
44
+ // reader reads "Ctrl plus S" rather than one run-together word, whatever
45
+ // the CSS does.
46
+ const keys = flattenChildren(children);
47
+ return (jsx("kbd", { ref: ref, className: classNames(groupClass, bulmaHelperClasses, className), ...rest, children: keys.map((key, index) => (jsxs(React.Fragment, { children: [index > 0 && (jsx("span", { className: separatorClass, children: ` ${separator} ` })), key] }, React.isValidElement(key) && key.key != null ? key.key : index))) }));
48
+ });
49
+ KbdGroup.displayName = 'Kbd.Group';
50
+ /**
51
+ * The `Kbd` component renders a `<kbd>` drawn as a keycap, for a key the reader presses.
52
+ *
53
+ * It only shows the key: it doesn't listen for it. The key takes its colors
54
+ * from the text it sits in, and its size in `em`, so it fits a paragraph, a
55
+ * title or a filled button as it is, and `textSize` sizes it outright. For a
56
+ * combination or a sequence, put the keys in a `Kbd.Group`. What tells
57
+ * assistive tech a control has a shortcut is `aria-keyshortcuts` on that
58
+ * control, with `Kbd` as the hint people see next to it.
59
+ *
60
+ * @function
61
+ * @param {KbdProps} props - Props for the Kbd component.
62
+ * @param {React.Ref<HTMLElement>} ref - Forwarded ref to the `<kbd>`.
63
+ * @returns {JSX.Element} The rendered key.
64
+ *
65
+ * @example
66
+ * <Kbd>Esc</Kbd>
67
+ *
68
+ * @example
69
+ * <Kbd label="Command">⌘</Kbd>
70
+ */
71
+ const KbdRoot = forwardRef(({ className, textColor, bgColor, label, children, ...props }, ref) => {
72
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
73
+ color: textColor,
74
+ backgroundColor: bgColor,
75
+ ...props,
76
+ });
77
+ const kbdClass = usePrefixedClassNames('kbd');
78
+ // The name is text rather than an aria-label, which ARIA in HTML
79
+ // prohibits on kbd. Its styles are inline, so it stays hidden in a
80
+ // modular build that leaves out Bulma's helper classes.
81
+ return (jsx("kbd", { ref: ref, className: classNames(kbdClass, bulmaHelperClasses, className), ...rest, children: label ? (jsxs(Fragment, { children: [jsx("span", { "aria-hidden": "true", children: children }), jsx("span", { style: visuallyHidden, children: label })] })) : (children) }));
82
+ });
83
+ const Kbd = withSubComponents(KbdRoot, { Group: KbdGroup }, 'Kbd');
84
+
85
+ export { Kbd, KbdGroup };
86
+ //# sourceMappingURL=Kbd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Kbd.js","sources":["../../../src/elements/Kbd.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport { flattenChildren } from '../helpers/flattenChildren';\nimport { visuallyHidden } from '../helpers/statusRegion';\nimport { withSubComponents } from '../helpers/withSubComponents';\n\n/**\n * Props for the Kbd component. The helper props, the other attributes and\n * the `ref` land on the `<kbd>`.\n *\n * @extraProp {React.Ref<HTMLElement>} [ref] - Ref forwarded to the `<kbd>`.\n */\nexport interface KbdProps\n extends\n Omit<React.HTMLAttributes<HTMLElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /**\n * The key as it's printed on the keyboard: a word (`Ctrl`, `Esc`), a\n * letter, or a symbol (`⌘`).\n */\n children?: React.ReactNode;\n /**\n * What a screen reader says in place of a symbol, in your app's language:\n * `label=\"Command\"` on `⌘`. The symbol is hidden from assistive tech with\n * `aria-hidden`, and the label is read in its place, from text that's\n * visually hidden. Use it for a glyph that isn't a word, such as `⌘`, `⌥`,\n * `⇧`, `⌃` or `⏎`, and leave it off a key written as a word. Copying the\n * key copies the label along with the glyph. Don't reach for `aria-label`\n * instead: ARIA in HTML prohibits naming a `<kbd>`, so nothing obliges a\n * screen reader to read it.\n */\n label?: string;\n /**\n * Text color helper. The key's edge and fill are mixed from its text\n * color, so they follow it.\n */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /**\n * Background color helper. It replaces the key's faint fill, and the text\n * still follows the text around it, which turns light in dark mode, so pair\n * it with a `textColor` that reads on that color in both schemes, such as\n * `textColor=\"black\"` on `bgColor=\"warning\"`.\n */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/**\n * Props for Kbd.Group, keys pressed together or one after another. The\n * group renders the outer `<kbd>` of a combination, and the helper props,\n * the other attributes and the `ref` land on it.\n *\n * @extraProp {React.Ref<HTMLElement>} [ref] - Ref forwarded to the outer `<kbd>`.\n */\nexport interface KbdGroupProps\n extends\n Omit<React.HTMLAttributes<HTMLElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /**\n * The keys, a `Kbd` each, in the order they're pressed. The group renders\n * the outer `<kbd>` around them, so it doesn't go inside a `Kbd` of its\n * own, and it puts the separator between them, so don't type one: a `+`\n * of your own doubles up. A `null` or `false` child, or an empty Fragment,\n * gets no separator, and the keys in a Fragment are separated like the\n * rest. A component that renders nothing still gets one, since the group\n * can't see what a child renders, so write a conditional key inline\n * (`{isMac && <Kbd label=\"Command\">⌘</Kbd>}`), not in a component of its\n * own.\n */\n children?: React.ReactNode;\n /**\n * What goes between the keys, shown and read aloud, with a space either\n * side. Use `'then'` for a sequence pressed one key after another. It's a\n * string because a screen reader has to read it.\n */\n separator?: string;\n /** Text color helper. The keys and separators inside follow it. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/**\n * Keys pressed together or one after another, in the outer `<kbd>` HTML gives a combination, with the separator between each pair as text.\n *\n * It doesn't wrap in the middle and isn't drawn as a key itself. It sets no\n * font size, so the keys in it are the size of a key on its own.\n *\n * @function\n * @param {KbdGroupProps} props - Props for Kbd.Group.\n * @param {React.Ref<HTMLElement>} ref - Forwarded ref to the outer `<kbd>`.\n * @returns {JSX.Element} The rendered combination.\n *\n * @example\n * <Kbd.Group>\n * <Kbd>Ctrl</Kbd>\n * <Kbd>Shift</Kbd>\n * <Kbd>P</Kbd>\n * </Kbd.Group>\n *\n * @example\n * <Kbd.Group separator=\"then\">\n * <Kbd>G</Kbd>\n * <Kbd>I</Kbd>\n * </Kbd.Group>\n */\nexport const KbdGroup = forwardRef<HTMLElement, KbdGroupProps>(\n ({ className, textColor, separator = '+', children, ...props }, ref) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n ...props,\n });\n const groupClass = usePrefixedClassNames('kbd-group');\n const separatorClass = usePrefixedClassNames('kbd-separator');\n\n // Null, undefined and booleans drop out, and Fragments are opened up, so\n // an empty Fragment leaves no separator behind and the keys in one are\n // separated like the rest. The spaces are part of the text, so a screen\n // reader reads \"Ctrl plus S\" rather than one run-together word, whatever\n // the CSS does.\n const keys = flattenChildren(children);\n\n return (\n <kbd\n ref={ref}\n className={classNames(groupClass, bulmaHelperClasses, className)}\n {...rest}\n >\n {keys.map((key, index) => (\n // Each wrapper takes its child's own React key, so a child that\n // moves keeps its node. Text has none, so it goes by its place.\n <React.Fragment\n key={React.isValidElement(key) && key.key != null ? key.key : index}\n >\n {index > 0 && (\n <span className={separatorClass}>{` ${separator} `}</span>\n )}\n {key}\n </React.Fragment>\n ))}\n </kbd>\n );\n }\n);\n\nKbdGroup.displayName = 'Kbd.Group';\n\n/**\n * The `Kbd` component renders a `<kbd>` drawn as a keycap, for a key the reader presses.\n *\n * It only shows the key: it doesn't listen for it. The key takes its colors\n * from the text it sits in, and its size in `em`, so it fits a paragraph, a\n * title or a filled button as it is, and `textSize` sizes it outright. For a\n * combination or a sequence, put the keys in a `Kbd.Group`. What tells\n * assistive tech a control has a shortcut is `aria-keyshortcuts` on that\n * control, with `Kbd` as the hint people see next to it.\n *\n * @function\n * @param {KbdProps} props - Props for the Kbd component.\n * @param {React.Ref<HTMLElement>} ref - Forwarded ref to the `<kbd>`.\n * @returns {JSX.Element} The rendered key.\n *\n * @example\n * <Kbd>Esc</Kbd>\n *\n * @example\n * <Kbd label=\"Command\">⌘</Kbd>\n */\nconst KbdRoot = forwardRef<HTMLElement, KbdProps>(\n ({ className, textColor, bgColor, label, children, ...props }, ref) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n const kbdClass = usePrefixedClassNames('kbd');\n\n // The name is text rather than an aria-label, which ARIA in HTML\n // prohibits on kbd. Its styles are inline, so it stays hidden in a\n // modular build that leaves out Bulma's helper classes.\n return (\n <kbd\n ref={ref}\n className={classNames(kbdClass, bulmaHelperClasses, className)}\n {...rest}\n >\n {label ? (\n <>\n <span aria-hidden=\"true\">{children}</span>\n <span style={visuallyHidden}>{label}</span>\n </>\n ) : (\n children\n )}\n </kbd>\n );\n }\n);\n\nexport const Kbd = withSubComponents(KbdRoot, { Group: KbdGroup }, 'Kbd');\n\nexport default Kbd;\n"],"names":["_jsx","_jsxs"],"mappings":";;;;;;;;;AAwFA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;AACI,MAAM,QAAQ,GAAG,UAAU,CAChC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,KAAI;AACrE,IAAA,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC;AACnD,QAAA,KAAK,EAAE,SAAS;AAChB,QAAA,GAAG,KAAK;AACT,KAAA,CAAC;AACF,IAAA,MAAM,UAAU,GAAG,qBAAqB,CAAC,WAAW,CAAC;AACrD,IAAA,MAAM,cAAc,GAAG,qBAAqB,CAAC,eAAe,CAAC;;;;;;AAO7D,IAAA,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC;AAEtC,IAAA,QACEA,GAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,UAAU,CAAC,UAAU,EAAE,kBAAkB,EAAE,SAAS,CAAC,KAC5D,IAAI,EAAA,QAAA,EAEP,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,MAGnBC,KAAC,KAAK,CAAC,QAAQ,EAAA,EAAA,QAAA,EAAA,CAGZ,KAAK,GAAG,CAAC,KACRD,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAE,cAAc,EAAA,QAAA,EAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,CAAG,EAAA,CAAQ,CAC3D,EACA,GAAG,CAAA,EAAA,EALC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC,GAAG,GAAG,KAAK,CAMpD,CAClB,CAAC,EAAA,CACE;AAEV,CAAC;AAGH,QAAQ,CAAC,WAAW,GAAG,WAAW;AAElC;;;;;;;;;;;;;;;;;;;;AAoBG;AACH,MAAM,OAAO,GAAG,UAAU,CACxB,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,KAAI;AACpE,IAAA,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC;AACnD,QAAA,KAAK,EAAE,SAAS;AAChB,QAAA,eAAe,EAAE,OAAO;AACxB,QAAA,GAAG,KAAK;AACT,KAAA,CAAC;AACF,IAAA,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAK,CAAC;;;;IAK7C,QACEA,aACE,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,UAAU,CAAC,QAAQ,EAAE,kBAAkB,EAAE,SAAS,CAAC,EAAA,GAC1D,IAAI,EAAA,QAAA,EAEP,KAAK,IACJC,4BACED,GAAA,CAAA,MAAA,EAAA,EAAA,aAAA,EAAkB,MAAM,YAAE,QAAQ,EAAA,CAAQ,EAC1CA,GAAA,CAAA,MAAA,EAAA,EAAM,KAAK,EAAE,cAAc,EAAA,QAAA,EAAG,KAAK,GAAQ,CAAA,EAAA,CAC1C,KAEH,QAAQ,CACT,EAAA,CACG;AAEV,CAAC,CACF;AAEM,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,KAAK;;"}
@@ -8,7 +8,12 @@ import { useInsideField } from './FormContext.js';
8
8
  import { Field } from './Field.js';
9
9
  import { useAutoLabelId } from './useAutoLabelId.js';
10
10
  import { useControlLoading } from './controlLoading.js';
11
+ import { spokenText, StatusRegion } from '../helpers/statusRegion.js';
11
12
 
13
+ // What the status region announces: the `empty` content, as the one item
14
+ // it's handed while that content is on screen because of the user's typing.
15
+ const typedNoMatches = [{ id: 'empty' }];
16
+ const nothingToAnnounce = [];
12
17
  /**
13
18
  * The `Autocomplete` component provides an input field with dropdown suggestions that filter based on user input.
14
19
  *
@@ -53,6 +58,13 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
53
58
  const dropdownRef = useRef(null);
54
59
  const [internalValue, setInternalValue] = useState('');
55
60
  const [isActive, setIsActive] = useState(false);
61
+ // Whether the user has typed since the list opened, since only typing
62
+ // gets the `empty` content announced. Closing the list resets it (during
63
+ // render, React's pattern for adjusting state when other state changes),
64
+ // so opening the list again without typing stays quiet.
65
+ const [typed, setTyped] = useState(false);
66
+ if (typed && !isActive)
67
+ setTyped(false);
56
68
  const [highlightedIndex, setHighlightedIndex] = useState(-1);
57
69
  const listboxId = `${useId()}-listbox`;
58
70
  // Use controlled or internal value
@@ -71,6 +83,11 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
71
83
  const displayValue = getDisplayValue(item);
72
84
  return displayValue.toLowerCase().includes(inputValue.toLowerCase());
73
85
  });
86
+ // The dropdown shows the options or, when nothing matches, the `empty`
87
+ // content. The listbox holds only options, so it's on screen only while
88
+ // there are some.
89
+ const menuOpen = isActive && (filteredData.length > 0 || !!empty);
90
+ const listOpen = isActive && filteredData.length > 0;
74
91
  // Handle input change
75
92
  const handleInputChange = useCallback((e) => {
76
93
  const newValue = e.target.value;
@@ -78,6 +95,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
78
95
  setInternalValue(newValue);
79
96
  }
80
97
  onInput?.(newValue);
98
+ setTyped(true);
81
99
  if (!isActive && newValue) {
82
100
  setIsActive(true);
83
101
  }
@@ -228,7 +246,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
228
246
  });
229
247
  const controlClasses = usePrefixedClassNames('control', 'is-expanded', 'has-icons-right');
230
248
  const dropdownMenuClasses = usePrefixedClassNames('dropdown-menu', {
231
- 'is-active': isActive && (filteredData.length > 0 || !!empty),
249
+ 'is-active': menuOpen,
232
250
  });
233
251
  const dropdownContentClass = usePrefixedClassNames('dropdown-content');
234
252
  const dropdownHeaderClass = usePrefixedClassNames('dropdown-header');
@@ -250,24 +268,51 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
250
268
  // The listbox takes its name from the label that names the combobox, the
251
269
  // one this renders or a surrounding Field's, so the two say the same
252
270
  // thing. When no label names the combobox, or the one that does has no
253
- // id to point at, the list keeps a fallback name.
254
- const listOpen = isActive && (filteredData.length > 0 || !!empty);
271
+ // id to point at, the list keeps a fallback name. While the dropdown
272
+ // shows only the `empty` content there's no listbox, so the combobox is
273
+ // collapsed and points at nothing.
255
274
  const activeOptionId = listOpen &&
256
275
  highlightedIndex >= 0 &&
257
276
  highlightedIndex < filteredData.length
258
277
  ? `${listboxId}-${highlightedIndex}`
259
278
  : undefined;
260
- const autocompleteElement = (jsxs("div", { ref: containerRef, className: combinedClasses, ...rest, children: [jsxs("div", { className: controlClasses, children: [jsx("input", { ref: combinedRef, type: "text", className: inputClasses, id: controlId, value: inputValue, placeholder: placeholder, disabled: disabled, name: name, form: form, required: required, onChange: handleInputChange, onFocus: handleFocus, onKeyDown: handleKeyDown, role: "combobox", "aria-expanded": listOpen, "aria-controls": listOpen ? listboxId : undefined, "aria-activedescendant": activeOptionId, "aria-haspopup": "listbox", "aria-autocomplete": "list", autoComplete: "off" }), showClear && (jsx("button", { type: "button", className: iconRightClickableClass, onClick: handleClear, "aria-label": "Clear", children: jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", width: "16", height: "16", "aria-hidden": "true", children: [jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })), loading && (jsx("span", { className: iconRightClass, children: jsx("span", { className: loaderClass }) }))] }), listOpen && (jsx("div", { className: dropdownMenuClasses, children: jsxs("div", { ref: dropdownRef, className: dropdownContentClass, style: { maxHeight: `${maxHeight}px`, overflowY: 'auto' }, id: listboxId, role: "listbox", "aria-labelledby": listLabelId, "aria-label": listLabelId ? undefined : 'Suggestions', onScroll: handleDropdownScroll, children: [header && jsx("div", { className: dropdownHeaderClass, children: header }), filteredData.length > 0 ? (filteredData.map((item, index) => {
261
- const isDisabled = typeof item !== 'string' && item.disabled;
262
- const isHighlighted = index === highlightedIndex;
263
- const itemClasses = prefixedClassNames(classPrefix, 'dropdown-item', {
264
- 'is-active': isHighlighted,
265
- 'is-disabled': isDisabled,
266
- });
267
- return (jsx("a", { id: `${listboxId}-${index}`, "data-index": index, className: itemClasses, onClick: () => !isDisabled && handleSelect(item), onMouseEnter: () => !isDisabled && setHighlightedIndex(index), role: "option", "aria-selected": isHighlighted, "aria-disabled": isDisabled, children: itemTemplate
268
- ? itemTemplate(item)
269
- : getDisplayValue(item) }, index));
270
- })) : (jsx("div", { className: emptyItemClasses, children: empty })), footer && jsx("div", { className: dropdownFooterClass, children: footer })] }) }))] }));
279
+ // A polite status region, in the page from the start so it's there
280
+ // before anything is written into it, announces the `empty` content
281
+ // when the user's typing leaves nothing that matches what's in the
282
+ // field. It follows what's on screen, so results that come in after the
283
+ // typing count too. It's said once each time that happens, not again on
284
+ // each keystroke while nothing matches. An empty field isn't a search,
285
+ // so it stays quiet then, even with no data. While `loading`, or a
286
+ // loading Control around it, says results are on their way, it waits,
287
+ // and it's said once loading ends with nothing matching.
288
+ const emptyItems = typed &&
289
+ menuOpen &&
290
+ !listOpen &&
291
+ !!inputValue &&
292
+ !loading &&
293
+ !controlLoading
294
+ ? typedNoMatches
295
+ : nothingToAnnounce;
296
+ // The region reads the text on screen, whatever `empty` renders.
297
+ const emptyRef = useRef(null);
298
+ const describeEmpty = useCallback(() => {
299
+ const node = emptyRef.current;
300
+ /* istanbul ignore if: it's only announced while it's on screen */
301
+ if (!node)
302
+ return null;
303
+ return spokenText(node);
304
+ }, []);
305
+ const autocompleteElement = (jsxs("div", { ref: containerRef, className: combinedClasses, ...rest, children: [jsxs("div", { className: controlClasses, children: [jsx("input", { ref: combinedRef, type: "text", className: inputClasses, id: controlId, value: inputValue, placeholder: placeholder, disabled: disabled, name: name, form: form, required: required, onChange: handleInputChange, onFocus: handleFocus, onKeyDown: handleKeyDown, role: "combobox", "aria-expanded": listOpen, "aria-controls": listOpen ? listboxId : undefined, "aria-activedescendant": activeOptionId, "aria-haspopup": "listbox", "aria-autocomplete": "list", autoComplete: "off" }), showClear && (jsx("button", { type: "button", className: iconRightClickableClass, onClick: handleClear, "aria-label": "Clear", children: jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", width: "16", height: "16", "aria-hidden": "true", children: [jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })), loading && (jsx("span", { className: iconRightClass, children: jsx("span", { className: loaderClass }) }))] }), menuOpen && (jsx("div", { className: dropdownMenuClasses, children: jsxs("div", { ref: dropdownRef, className: dropdownContentClass, style: { maxHeight: `${maxHeight}px`, overflowY: 'auto' }, onScroll: handleDropdownScroll, children: [header && jsx("div", { className: dropdownHeaderClass, children: header }), listOpen ? (jsx("div", { id: listboxId, role: "listbox", "aria-labelledby": listLabelId, "aria-label": listLabelId ? undefined : 'Suggestions', children: filteredData.map((item, index) => {
306
+ const isDisabled = typeof item !== 'string' && item.disabled;
307
+ const isHighlighted = index === highlightedIndex;
308
+ const itemClasses = prefixedClassNames(classPrefix, 'dropdown-item', {
309
+ 'is-active': isHighlighted,
310
+ 'is-disabled': isDisabled,
311
+ });
312
+ return (jsx("a", { id: `${listboxId}-${index}`, "data-index": index, className: itemClasses, onClick: () => !isDisabled && handleSelect(item), onMouseEnter: () => !isDisabled && setHighlightedIndex(index), role: "option", "aria-selected": isHighlighted, "aria-disabled": isDisabled, children: itemTemplate
313
+ ? itemTemplate(item)
314
+ : getDisplayValue(item) }, index));
315
+ }) })) : (jsx("div", { ref: emptyRef, className: emptyItemClasses, children: empty })), footer && jsx("div", { className: dropdownFooterClass, children: footer })] }) })), jsx(StatusRegion, { items: emptyItems, describe: describeEmpty })] }));
271
316
  if (!insideField) {
272
317
  return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [autocompleteElement, messageEl] }));
273
318
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Autocomplete.js","sources":["../../../src/form/Autocomplete.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useState,\n useRef,\n useEffect,\n useCallback,\n useId,\n} from 'react';\nimport {\n classNames,\n usePrefixedClassNames,\n prefixedClassNames,\n} from '../helpers/classNames';\nimport { useConfig } from '../helpers/Config';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { useInsideField } from './FormContext';\nimport { Field } from './Field';\nimport { FormFieldProps } from './fieldProps';\nimport { useAutoLabelId } from './useAutoLabelId';\nimport { useControlLoading } from './controlLoading';\n\n/**\n * An item in the Autocomplete dropdown list.\n */\nexport interface AutocompleteItem {\n /** The value used for filtering and selection. */\n value: string;\n /** Display label (optional). */\n label?: string;\n /** Whether the item is disabled and unselectable. */\n disabled?: boolean;\n [key: string]: unknown;\n}\n\n/**\n * Props for the Autocomplete component.\n * @extraProp {string} [className] - Additional CSS classes.\n * @extraProp {React.Ref<HTMLInputElement>} [ref] - Ref forwarded to the input element.\n */\nexport interface AutocompleteProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onInput'>,\n Omit<BulmaClassesProps, 'color'>,\n FormFieldProps {\n /** Field label, associated with the text input via `htmlFor`: through your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose label names the input instead when it points at it. The `Field` points its label there itself when the Autocomplete has no `id` and no inner `Field` sits between them (and the `Field` is not `grouped` or `hasAddons`); a label you wire by hand with `labelProps.htmlFor` points at the input with that `id`. The label naming the input also names the open suggestion list, through `aria-labelledby`, when it has an id: this label always does, and an outer `Field`'s does unless you wired it by hand without an `id` in its `labelProps`. Otherwise the list is named \"Suggestions\". */\n label?: React.ReactNode;\n /** Props for the label element. An explicit `htmlFor` here overrides the automatic association (the input then gets no generated id). While the label names the input, the suggestion list's `aria-labelledby` points at it, through an `id` here when you give one and a generated one otherwise. */\n labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {\n [key: string]: unknown;\n };\n /** Applied to the inner text input (the labellable control), not the wrapper div. */\n id?: string;\n /** The options data to display (required). */\n data: AutocompleteItem[] | string[];\n /** The current input value (controlled). */\n value?: string;\n /** The selected item (controlled). */\n selected?: AutocompleteItem | string | null;\n /** Placeholder text for the input. */\n placeholder?: string;\n /** Object property to use as the display field. */\n field?: string;\n /**\n * Whether to show a clear button while the input holds a value.\n * It hides while the input is disabled, and gives way to a loading\n * spinner at the same right edge: the one `loading` draws, or that of a\n * `Control` with `isLoading` around the Autocomplete.\n */\n clearable?: boolean;\n /** Open dropdown when input is focused. */\n openOnFocus?: boolean;\n /** Keep first option highlighted. */\n keepFirst?: boolean;\n /** Keep dropdown open after selection. */\n keepOpen?: boolean;\n /** Select highlighted item on click outside. */\n selectOnClickOutside?: boolean;\n /** Maximum dropdown height in pixels. */\n maxHeight?: number;\n /** Render as dropdown style. */\n dropdown?: boolean;\n /**\n * Show a loading spinner in the input.\n * Under `prefers-reduced-motion: reduce` the spinner stops and stays\n * drawn (with bestax's CSS loaded).\n */\n loading?: boolean;\n /** Whether the input is disabled. */\n disabled?: boolean;\n /** Enables infinite scroll detection in the dropdown. */\n checkInfiniteScroll?: boolean;\n /** Distance in pixels from the bottom to trigger `onInfiniteScroll`. */\n infiniteScrollDistance?: number;\n /** Input color variant. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Size variant. */\n size?: 'small' | 'medium' | 'large';\n /** Form field name. Forwarded to the inner `<input>`. */\n name?: string;\n /** Optional id of the form the input belongs to. */\n form?: string;\n /** Marks the field as required for native HTML form validation. */\n required?: boolean;\n /** Callback when input value changes. */\n onInput?: (value: string) => void;\n /** Callback when item is selected. */\n onSelect?: (item: AutocompleteItem | string | null) => void;\n /** Callback when dropdown active state changes. */\n onActiveChange?: (active: boolean) => void;\n /** Callback when scrolled to bottom (infinite scroll). */\n onInfiniteScroll?: () => void;\n /** Custom render for items. */\n itemTemplate?: (item: AutocompleteItem | string) => React.ReactNode;\n /** Custom header in dropdown. */\n header?: React.ReactNode;\n /** Custom footer in dropdown. */\n footer?: React.ReactNode;\n /** Content to show when no results. */\n empty?: React.ReactNode;\n}\n\n/**\n * The `Autocomplete` component provides an input field with dropdown suggestions that filter based on user input.\n *\n * @function\n * @param {AutocompleteProps} props - Props for the Autocomplete component.\n * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the input element.\n * @returns {JSX.Element} The rendered autocomplete component.\n *\n * @example\n * // Basic usage with string array\n * <Autocomplete\n * data={['Apple', 'Banana', 'Cherry']}\n * placeholder=\"Search fruit...\"\n * onSelect={(item) => console.log(item)}\n * />\n *\n * @example\n * // With object data\n * <Autocomplete\n * data={[{ value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }]}\n * field=\"label\"\n * onSelect={(item) => console.log(item)}\n * />\n */\nexport const Autocomplete = forwardRef<HTMLInputElement, AutocompleteProps>(\n (\n {\n data = [],\n value: controlledValue,\n placeholder,\n field = 'label',\n clearable = false,\n openOnFocus = false,\n keepFirst = false,\n keepOpen = false,\n selectOnClickOutside = false,\n maxHeight = 200,\n loading = false,\n disabled = false,\n checkInfiniteScroll = false,\n infiniteScrollDistance = 50,\n color,\n size,\n onInput,\n onSelect,\n onActiveChange,\n onInfiniteScroll,\n itemTemplate,\n header,\n footer,\n empty,\n name,\n form,\n required,\n id,\n // Field props\n label,\n labelSize,\n labelProps,\n horizontal,\n message,\n messageColor,\n fieldClassName,\n className,\n ...props\n },\n ref\n ) => {\n const insideField = useInsideField();\n // The suggestion list points `aria-labelledby` at the label that names\n // the input, so it needs that label's id.\n const {\n controlId,\n fieldLabelProps,\n labelId: listLabelId,\n } = useAutoLabelId({\n label,\n id,\n labelProps,\n rendersLabel: !insideField,\n needsLabelId: true,\n });\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const { classPrefix } = useConfig();\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n const [internalValue, setInternalValue] = useState('');\n const [isActive, setIsActive] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const listboxId = `${useId()}-listbox`;\n\n // Use controlled or internal value\n const inputValue =\n controlledValue !== undefined ? controlledValue : internalValue;\n\n // Get display value from item\n const getDisplayValue = (item: AutocompleteItem | string): string => {\n if (typeof item === 'string') return item;\n const fieldValue = item[field];\n if (typeof fieldValue === 'string') return fieldValue;\n return item.value || '';\n };\n\n // Filter data based on input\n const filteredData = data.filter(item => {\n const displayValue = getDisplayValue(item);\n return displayValue.toLowerCase().includes(inputValue.toLowerCase());\n });\n\n // Handle input change\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n if (controlledValue === undefined) {\n setInternalValue(newValue);\n }\n onInput?.(newValue);\n if (!isActive && newValue) {\n setIsActive(true);\n }\n },\n [controlledValue, isActive, onInput]\n );\n\n // Handle item selection\n const handleSelect = useCallback(\n (item: AutocompleteItem | string) => {\n if (typeof item !== 'string' && item.disabled) return;\n\n const displayValue = getDisplayValue(item);\n if (controlledValue === undefined) {\n setInternalValue(displayValue);\n }\n onInput?.(displayValue);\n onSelect?.(item);\n\n if (!keepOpen) {\n setIsActive(false);\n }\n setHighlightedIndex(-1);\n },\n [controlledValue, field, keepOpen, onInput, onSelect]\n );\n\n // Handle clear\n const handleClear = useCallback(() => {\n if (controlledValue === undefined) {\n setInternalValue('');\n }\n onInput?.('');\n onSelect?.(null);\n inputRef.current?.focus();\n }, [controlledValue, onInput, onSelect]);\n\n // Handle focus\n const handleFocus = useCallback(() => {\n if (openOnFocus && !disabled) {\n setIsActive(true);\n }\n }, [openOnFocus, disabled]);\n\n // Handle blur (click outside)\n useEffect(() => {\n if (!isActive) return undefined;\n\n const handleClickOutside = (e: MouseEvent) => {\n if (!containerRef.current) return;\n\n // Use composedPath() to correctly detect clicks inside Shadow DOM\n const path = e.composedPath();\n const isInside = path.includes(containerRef.current);\n\n if (!isInside) {\n if (selectOnClickOutside && highlightedIndex >= 0) {\n handleSelect(filteredData[highlightedIndex]);\n }\n setIsActive(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () =>\n document.removeEventListener('mousedown', handleClickOutside);\n }, [\n isActive,\n selectOnClickOutside,\n highlightedIndex,\n filteredData,\n handleSelect,\n ]);\n\n // Notify active state change\n useEffect(() => {\n onActiveChange?.(isActive);\n }, [isActive, onActiveChange]);\n\n // Keep first highlighted\n useEffect(() => {\n if (keepFirst && isActive && filteredData.length > 0) {\n setHighlightedIndex(0);\n }\n }, [keepFirst, isActive, filteredData.length, inputValue]);\n\n // Handle keyboard navigation\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (disabled) return;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!isActive) {\n setIsActive(true);\n } else {\n setHighlightedIndex(prev =>\n prev < filteredData.length - 1 ? prev + 1 : prev\n );\n }\n break;\n case 'ArrowUp':\n e.preventDefault();\n setHighlightedIndex(prev => (prev > 0 ? prev - 1 : prev));\n break;\n case 'Enter':\n e.preventDefault();\n if (highlightedIndex >= 0 && filteredData[highlightedIndex]) {\n handleSelect(filteredData[highlightedIndex]);\n }\n break;\n case 'Escape':\n e.preventDefault();\n setIsActive(false);\n setHighlightedIndex(-1);\n break;\n case 'Tab':\n if (highlightedIndex >= 0 && filteredData[highlightedIndex]) {\n handleSelect(filteredData[highlightedIndex]);\n }\n setIsActive(false);\n break;\n }\n },\n [disabled, isActive, highlightedIndex, filteredData, handleSelect]\n );\n\n // Handle dropdown scroll for infinite scroll\n const handleDropdownScroll = useCallback(() => {\n if (!checkInfiniteScroll || !dropdownRef.current) return;\n\n const { scrollTop, scrollHeight, clientHeight } = dropdownRef.current;\n if (scrollHeight - scrollTop - clientHeight <= infiniteScrollDistance) {\n onInfiniteScroll?.();\n }\n }, [checkInfiniteScroll, infiniteScrollDistance, onInfiniteScroll]);\n\n // Scroll highlighted item into view\n useEffect(() => {\n if (highlightedIndex >= 0 && dropdownRef.current) {\n const highlightedEl = dropdownRef.current.querySelector(\n `[data-index=\"${highlightedIndex}\"]`\n );\n if (\n highlightedEl &&\n typeof highlightedEl.scrollIntoView === 'function'\n ) {\n highlightedEl.scrollIntoView({ block: 'nearest' });\n }\n }\n }, [highlightedIndex]);\n\n // Combined ref\n const combinedRef = useCallback(\n (node: HTMLInputElement | null) => {\n (inputRef as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n }\n },\n [ref]\n );\n\n // Generate classes\n const autocompleteClasses = usePrefixedClassNames('autocomplete', {\n 'is-active': isActive,\n [`is-${size}`]: !!size,\n });\n\n const inputClasses = usePrefixedClassNames('input', {\n [`is-${color}`]: !!color,\n [`is-${size}`]: !!size,\n 'is-loading': loading,\n });\n\n const controlClasses = usePrefixedClassNames(\n 'control',\n 'is-expanded',\n 'has-icons-right'\n );\n\n const dropdownMenuClasses = usePrefixedClassNames('dropdown-menu', {\n 'is-active': isActive && (filteredData.length > 0 || !!empty),\n });\n\n const dropdownContentClass = usePrefixedClassNames('dropdown-content');\n const dropdownHeaderClass = usePrefixedClassNames('dropdown-header');\n const dropdownFooterClass = usePrefixedClassNames('dropdown-footer');\n const emptyItemClasses = usePrefixedClassNames(\n 'dropdown-item',\n 'has-text-grey'\n );\n\n const iconRightClickableClass = usePrefixedClassNames(\n 'icon',\n 'is-right',\n 'is-clickable'\n );\n const iconRightClass = usePrefixedClassNames('icon', 'is-right');\n const loaderClass = usePrefixedClassNames('loader', 'is-loading');\n\n const combinedClasses = classNames(\n autocompleteClasses,\n bulmaHelperClasses,\n className\n );\n\n const helpClass = usePrefixedClassNames('help', {\n [`is-${messageColor}`]: !!messageColor,\n });\n const messageEl = message ? <p className={helpClass}>{message}</p> : null;\n\n // The clear button gives way to a spinner at its spot: the `loading` one,\n // or that of a loading Control this sits in.\n const controlLoading = useControlLoading();\n const showClear =\n clearable && !!inputValue && !disabled && !loading && !controlLoading;\n\n // The combobox controls its listbox and points at the highlighted option.\n // The listbox takes its name from the label that names the combobox, the\n // one this renders or a surrounding Field's, so the two say the same\n // thing. When no label names the combobox, or the one that does has no\n // id to point at, the list keeps a fallback name.\n const listOpen = isActive && (filteredData.length > 0 || !!empty);\n const activeOptionId =\n listOpen &&\n highlightedIndex >= 0 &&\n highlightedIndex < filteredData.length\n ? `${listboxId}-${highlightedIndex}`\n : undefined;\n\n const autocompleteElement = (\n <div ref={containerRef} className={combinedClasses} {...rest}>\n <div className={controlClasses}>\n <input\n ref={combinedRef}\n type=\"text\"\n className={inputClasses}\n id={controlId}\n value={inputValue}\n placeholder={placeholder}\n disabled={disabled}\n name={name}\n form={form}\n required={required}\n onChange={handleInputChange}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n role=\"combobox\"\n aria-expanded={listOpen}\n aria-controls={listOpen ? listboxId : undefined}\n aria-activedescendant={activeOptionId}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n />\n {showClear && (\n <button\n type=\"button\"\n className={iconRightClickableClass}\n onClick={handleClear}\n aria-label=\"Clear\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n width=\"16\"\n height=\"16\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n {loading && (\n <span className={iconRightClass}>\n <span className={loaderClass} />\n </span>\n )}\n </div>\n\n {listOpen && (\n <div className={dropdownMenuClasses}>\n <div\n ref={dropdownRef}\n className={dropdownContentClass}\n style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto' }}\n id={listboxId}\n role=\"listbox\"\n aria-labelledby={listLabelId}\n aria-label={listLabelId ? undefined : 'Suggestions'}\n onScroll={handleDropdownScroll}\n >\n {header && <div className={dropdownHeaderClass}>{header}</div>}\n\n {filteredData.length > 0 ? (\n filteredData.map((item, index) => {\n const isDisabled = typeof item !== 'string' && item.disabled;\n const isHighlighted = index === highlightedIndex;\n\n const itemClasses = prefixedClassNames(\n classPrefix,\n 'dropdown-item',\n {\n 'is-active': isHighlighted,\n 'is-disabled': isDisabled,\n }\n );\n\n return (\n <a\n key={index}\n id={`${listboxId}-${index}`}\n data-index={index}\n className={itemClasses}\n onClick={() => !isDisabled && handleSelect(item)}\n onMouseEnter={() =>\n !isDisabled && setHighlightedIndex(index)\n }\n role=\"option\"\n aria-selected={isHighlighted}\n aria-disabled={isDisabled}\n >\n {itemTemplate\n ? itemTemplate(item)\n : getDisplayValue(item)}\n </a>\n );\n })\n ) : (\n <div className={emptyItemClasses}>{empty}</div>\n )}\n\n {footer && <div className={dropdownFooterClass}>{footer}</div>}\n </div>\n </div>\n )}\n </div>\n );\n\n if (!insideField) {\n return (\n <Field\n label={label}\n labelSize={labelSize}\n labelProps={fieldLabelProps}\n horizontal={horizontal}\n className={fieldClassName}\n >\n {autocompleteElement}\n {messageEl}\n </Field>\n );\n }\n\n return (\n <>\n {autocompleteElement}\n {messageEl}\n </>\n );\n }\n);\n\nAutocomplete.displayName = 'Autocomplete';\n\nexport default Autocomplete;\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"Autocomplete.js","sources":["../../../src/form/Autocomplete.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useState,\n useRef,\n useEffect,\n useCallback,\n useId,\n} from 'react';\nimport {\n classNames,\n usePrefixedClassNames,\n prefixedClassNames,\n} from '../helpers/classNames';\nimport { useConfig } from '../helpers/Config';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { useInsideField } from './FormContext';\nimport { Field } from './Field';\nimport { FormFieldProps } from './fieldProps';\nimport { useAutoLabelId } from './useAutoLabelId';\nimport { useControlLoading } from './controlLoading';\nimport { StatusRegion, spokenText } from '../helpers/statusRegion';\n\n/**\n * An item in the Autocomplete dropdown list.\n */\nexport interface AutocompleteItem {\n /** The value used for filtering and selection. */\n value: string;\n /** Display label (optional). */\n label?: string;\n /** Whether the item is disabled and unselectable. */\n disabled?: boolean;\n [key: string]: unknown;\n}\n\n// What the status region announces: the `empty` content, as the one item\n// it's handed while that content is on screen because of the user's typing.\nconst typedNoMatches = [{ id: 'empty' }];\nconst nothingToAnnounce: Array<{ id: string }> = [];\n\n/**\n * Props for the Autocomplete component.\n * @extraProp {string} [className] - Additional CSS classes.\n * @extraProp {React.Ref<HTMLInputElement>} [ref] - Ref forwarded to the input element.\n */\nexport interface AutocompleteProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onInput'>,\n Omit<BulmaClassesProps, 'color'>,\n FormFieldProps {\n /** Field label, associated with the text input via `htmlFor`: through your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose label names the input instead when it points at it. The `Field` points its label there itself when the Autocomplete has no `id` and no inner `Field` sits between them (and the `Field` is not `grouped` or `hasAddons`); a label you wire by hand with `labelProps.htmlFor` points at the input with that `id`. The label naming the input also names the open suggestion list, through `aria-labelledby`, when it has an id: this label always does, and an outer `Field`'s does unless you wired it by hand without an `id` in its `labelProps`. Otherwise the list is named \"Suggestions\". */\n label?: React.ReactNode;\n /** Props for the label element. An explicit `htmlFor` here overrides the automatic association (the input then gets no generated id). While the label names the input, the suggestion list's `aria-labelledby` points at it, through an `id` here when you give one and a generated one otherwise. */\n labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {\n [key: string]: unknown;\n };\n /** Applied to the inner text input (the labellable control), not the wrapper div. */\n id?: string;\n /** The options data to display (required). */\n data: AutocompleteItem[] | string[];\n /** The current input value (controlled). */\n value?: string;\n /** The selected item (controlled). */\n selected?: AutocompleteItem | string | null;\n /** Placeholder text for the input. */\n placeholder?: string;\n /** Object property to use as the display field. */\n field?: string;\n /**\n * Whether to show a clear button while the input holds a value.\n * It hides while the input is disabled, and gives way to a loading\n * spinner at the same right edge: the one `loading` draws, or that of a\n * `Control` with `isLoading` around the Autocomplete.\n */\n clearable?: boolean;\n /** Open dropdown when input is focused. */\n openOnFocus?: boolean;\n /** Keep first option highlighted. */\n keepFirst?: boolean;\n /** Keep dropdown open after selection. */\n keepOpen?: boolean;\n /** Select highlighted item on click outside. */\n selectOnClickOutside?: boolean;\n /** Maximum dropdown height in pixels. */\n maxHeight?: number;\n /** Render as dropdown style. */\n dropdown?: boolean;\n /**\n * Show a loading spinner in the input.\n * Under `prefers-reduced-motion: reduce` the spinner stops and stays\n * drawn (with bestax's CSS loaded).\n */\n loading?: boolean;\n /** Whether the input is disabled. */\n disabled?: boolean;\n /** Enables infinite scroll detection in the dropdown. */\n checkInfiniteScroll?: boolean;\n /** Distance in pixels from the bottom to trigger `onInfiniteScroll`. */\n infiniteScrollDistance?: number;\n /** Input color variant. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Size variant. */\n size?: 'small' | 'medium' | 'large';\n /** Form field name. Forwarded to the inner `<input>`. */\n name?: string;\n /** Optional id of the form the input belongs to. */\n form?: string;\n /** Marks the field as required for native HTML form validation. */\n required?: boolean;\n /** Callback when input value changes. */\n onInput?: (value: string) => void;\n /** Callback when item is selected. */\n onSelect?: (item: AutocompleteItem | string | null) => void;\n /** Callback when dropdown active state changes. */\n onActiveChange?: (active: boolean) => void;\n /** Callback when scrolled to bottom (infinite scroll). */\n onInfiniteScroll?: () => void;\n /** Custom render for items. */\n itemTemplate?: (item: AutocompleteItem | string) => React.ReactNode;\n /** Custom header at the top of the dropdown. It sits above the list of options rather than in it, so assistive technology doesn't count it as one. */\n header?: React.ReactNode;\n /** Custom footer at the bottom of the dropdown. It sits below the list of options rather than in it, so assistive technology doesn't count it as one. */\n footer?: React.ReactNode;\n /**\n * A message the dropdown shows in place of the options when nothing\n * matches. Keep it to text: `Tab` closes the list, so a keyboard user\n * can't reach a link or button in it. It sits beside the list of options\n * rather than in it, so the input's `aria-expanded` stays false while it\n * shows. When the user's typing leaves nothing that matches, a polite\n * status region announces its text: once each time the matches run out.\n * The text is read when they first run out, and isn't read again as it\n * changes while they stay out, so a message that names the query is heard\n * for that first query only. Keep it static.\n * Opening the list without typing, or emptying the field, announces\n * nothing. While `loading`, or a `Control` with `isLoading` around the\n * Autocomplete, is on, it waits, and it's announced once loading ends\n * with nothing matching. Without `empty`, the dropdown closes when nothing\n * matches and nothing is announced.\n */\n empty?: React.ReactNode;\n}\n\n/**\n * The `Autocomplete` component provides an input field with dropdown suggestions that filter based on user input.\n *\n * @function\n * @param {AutocompleteProps} props - Props for the Autocomplete component.\n * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the input element.\n * @returns {JSX.Element} The rendered autocomplete component.\n *\n * @example\n * // Basic usage with string array\n * <Autocomplete\n * data={['Apple', 'Banana', 'Cherry']}\n * placeholder=\"Search fruit...\"\n * onSelect={(item) => console.log(item)}\n * />\n *\n * @example\n * // With object data\n * <Autocomplete\n * data={[{ value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }]}\n * field=\"label\"\n * onSelect={(item) => console.log(item)}\n * />\n */\nexport const Autocomplete = forwardRef<HTMLInputElement, AutocompleteProps>(\n (\n {\n data = [],\n value: controlledValue,\n placeholder,\n field = 'label',\n clearable = false,\n openOnFocus = false,\n keepFirst = false,\n keepOpen = false,\n selectOnClickOutside = false,\n maxHeight = 200,\n loading = false,\n disabled = false,\n checkInfiniteScroll = false,\n infiniteScrollDistance = 50,\n color,\n size,\n onInput,\n onSelect,\n onActiveChange,\n onInfiniteScroll,\n itemTemplate,\n header,\n footer,\n empty,\n name,\n form,\n required,\n id,\n // Field props\n label,\n labelSize,\n labelProps,\n horizontal,\n message,\n messageColor,\n fieldClassName,\n className,\n ...props\n },\n ref\n ) => {\n const insideField = useInsideField();\n // The suggestion list points `aria-labelledby` at the label that names\n // the input, so it needs that label's id.\n const {\n controlId,\n fieldLabelProps,\n labelId: listLabelId,\n } = useAutoLabelId({\n label,\n id,\n labelProps,\n rendersLabel: !insideField,\n needsLabelId: true,\n });\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const { classPrefix } = useConfig();\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n const [internalValue, setInternalValue] = useState('');\n const [isActive, setIsActive] = useState(false);\n // Whether the user has typed since the list opened, since only typing\n // gets the `empty` content announced. Closing the list resets it (during\n // render, React's pattern for adjusting state when other state changes),\n // so opening the list again without typing stays quiet.\n const [typed, setTyped] = useState(false);\n if (typed && !isActive) setTyped(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const listboxId = `${useId()}-listbox`;\n\n // Use controlled or internal value\n const inputValue =\n controlledValue !== undefined ? controlledValue : internalValue;\n\n // Get display value from item\n const getDisplayValue = (item: AutocompleteItem | string): string => {\n if (typeof item === 'string') return item;\n const fieldValue = item[field];\n if (typeof fieldValue === 'string') return fieldValue;\n return item.value || '';\n };\n\n // Filter data based on input\n const filteredData = data.filter(item => {\n const displayValue = getDisplayValue(item);\n return displayValue.toLowerCase().includes(inputValue.toLowerCase());\n });\n\n // The dropdown shows the options or, when nothing matches, the `empty`\n // content. The listbox holds only options, so it's on screen only while\n // there are some.\n const menuOpen = isActive && (filteredData.length > 0 || !!empty);\n const listOpen = isActive && filteredData.length > 0;\n\n // Handle input change\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n if (controlledValue === undefined) {\n setInternalValue(newValue);\n }\n onInput?.(newValue);\n setTyped(true);\n if (!isActive && newValue) {\n setIsActive(true);\n }\n },\n [controlledValue, isActive, onInput]\n );\n\n // Handle item selection\n const handleSelect = useCallback(\n (item: AutocompleteItem | string) => {\n if (typeof item !== 'string' && item.disabled) return;\n\n const displayValue = getDisplayValue(item);\n if (controlledValue === undefined) {\n setInternalValue(displayValue);\n }\n onInput?.(displayValue);\n onSelect?.(item);\n\n if (!keepOpen) {\n setIsActive(false);\n }\n setHighlightedIndex(-1);\n },\n [controlledValue, field, keepOpen, onInput, onSelect]\n );\n\n // Handle clear\n const handleClear = useCallback(() => {\n if (controlledValue === undefined) {\n setInternalValue('');\n }\n onInput?.('');\n onSelect?.(null);\n inputRef.current?.focus();\n }, [controlledValue, onInput, onSelect]);\n\n // Handle focus\n const handleFocus = useCallback(() => {\n if (openOnFocus && !disabled) {\n setIsActive(true);\n }\n }, [openOnFocus, disabled]);\n\n // Handle blur (click outside)\n useEffect(() => {\n if (!isActive) return undefined;\n\n const handleClickOutside = (e: MouseEvent) => {\n if (!containerRef.current) return;\n\n // Use composedPath() to correctly detect clicks inside Shadow DOM\n const path = e.composedPath();\n const isInside = path.includes(containerRef.current);\n\n if (!isInside) {\n if (selectOnClickOutside && highlightedIndex >= 0) {\n handleSelect(filteredData[highlightedIndex]);\n }\n setIsActive(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () =>\n document.removeEventListener('mousedown', handleClickOutside);\n }, [\n isActive,\n selectOnClickOutside,\n highlightedIndex,\n filteredData,\n handleSelect,\n ]);\n\n // Notify active state change\n useEffect(() => {\n onActiveChange?.(isActive);\n }, [isActive, onActiveChange]);\n\n // Keep first highlighted\n useEffect(() => {\n if (keepFirst && isActive && filteredData.length > 0) {\n setHighlightedIndex(0);\n }\n }, [keepFirst, isActive, filteredData.length, inputValue]);\n\n // Handle keyboard navigation\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (disabled) return;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!isActive) {\n setIsActive(true);\n } else {\n setHighlightedIndex(prev =>\n prev < filteredData.length - 1 ? prev + 1 : prev\n );\n }\n break;\n case 'ArrowUp':\n e.preventDefault();\n setHighlightedIndex(prev => (prev > 0 ? prev - 1 : prev));\n break;\n case 'Enter':\n e.preventDefault();\n if (highlightedIndex >= 0 && filteredData[highlightedIndex]) {\n handleSelect(filteredData[highlightedIndex]);\n }\n break;\n case 'Escape':\n e.preventDefault();\n setIsActive(false);\n setHighlightedIndex(-1);\n break;\n case 'Tab':\n if (highlightedIndex >= 0 && filteredData[highlightedIndex]) {\n handleSelect(filteredData[highlightedIndex]);\n }\n setIsActive(false);\n break;\n }\n },\n [disabled, isActive, highlightedIndex, filteredData, handleSelect]\n );\n\n // Handle dropdown scroll for infinite scroll\n const handleDropdownScroll = useCallback(() => {\n if (!checkInfiniteScroll || !dropdownRef.current) return;\n\n const { scrollTop, scrollHeight, clientHeight } = dropdownRef.current;\n if (scrollHeight - scrollTop - clientHeight <= infiniteScrollDistance) {\n onInfiniteScroll?.();\n }\n }, [checkInfiniteScroll, infiniteScrollDistance, onInfiniteScroll]);\n\n // Scroll highlighted item into view\n useEffect(() => {\n if (highlightedIndex >= 0 && dropdownRef.current) {\n const highlightedEl = dropdownRef.current.querySelector(\n `[data-index=\"${highlightedIndex}\"]`\n );\n if (\n highlightedEl &&\n typeof highlightedEl.scrollIntoView === 'function'\n ) {\n highlightedEl.scrollIntoView({ block: 'nearest' });\n }\n }\n }, [highlightedIndex]);\n\n // Combined ref\n const combinedRef = useCallback(\n (node: HTMLInputElement | null) => {\n (inputRef as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n }\n },\n [ref]\n );\n\n // Generate classes\n const autocompleteClasses = usePrefixedClassNames('autocomplete', {\n 'is-active': isActive,\n [`is-${size}`]: !!size,\n });\n\n const inputClasses = usePrefixedClassNames('input', {\n [`is-${color}`]: !!color,\n [`is-${size}`]: !!size,\n 'is-loading': loading,\n });\n\n const controlClasses = usePrefixedClassNames(\n 'control',\n 'is-expanded',\n 'has-icons-right'\n );\n\n const dropdownMenuClasses = usePrefixedClassNames('dropdown-menu', {\n 'is-active': menuOpen,\n });\n\n const dropdownContentClass = usePrefixedClassNames('dropdown-content');\n const dropdownHeaderClass = usePrefixedClassNames('dropdown-header');\n const dropdownFooterClass = usePrefixedClassNames('dropdown-footer');\n const emptyItemClasses = usePrefixedClassNames(\n 'dropdown-item',\n 'has-text-grey'\n );\n\n const iconRightClickableClass = usePrefixedClassNames(\n 'icon',\n 'is-right',\n 'is-clickable'\n );\n const iconRightClass = usePrefixedClassNames('icon', 'is-right');\n const loaderClass = usePrefixedClassNames('loader', 'is-loading');\n\n const combinedClasses = classNames(\n autocompleteClasses,\n bulmaHelperClasses,\n className\n );\n\n const helpClass = usePrefixedClassNames('help', {\n [`is-${messageColor}`]: !!messageColor,\n });\n const messageEl = message ? <p className={helpClass}>{message}</p> : null;\n\n // The clear button gives way to a spinner at its spot: the `loading` one,\n // or that of a loading Control this sits in.\n const controlLoading = useControlLoading();\n const showClear =\n clearable && !!inputValue && !disabled && !loading && !controlLoading;\n\n // The combobox controls its listbox and points at the highlighted option.\n // The listbox takes its name from the label that names the combobox, the\n // one this renders or a surrounding Field's, so the two say the same\n // thing. When no label names the combobox, or the one that does has no\n // id to point at, the list keeps a fallback name. While the dropdown\n // shows only the `empty` content there's no listbox, so the combobox is\n // collapsed and points at nothing.\n const activeOptionId =\n listOpen &&\n highlightedIndex >= 0 &&\n highlightedIndex < filteredData.length\n ? `${listboxId}-${highlightedIndex}`\n : undefined;\n\n // A polite status region, in the page from the start so it's there\n // before anything is written into it, announces the `empty` content\n // when the user's typing leaves nothing that matches what's in the\n // field. It follows what's on screen, so results that come in after the\n // typing count too. It's said once each time that happens, not again on\n // each keystroke while nothing matches. An empty field isn't a search,\n // so it stays quiet then, even with no data. While `loading`, or a\n // loading Control around it, says results are on their way, it waits,\n // and it's said once loading ends with nothing matching.\n const emptyItems =\n typed &&\n menuOpen &&\n !listOpen &&\n !!inputValue &&\n !loading &&\n !controlLoading\n ? typedNoMatches\n : nothingToAnnounce;\n // The region reads the text on screen, whatever `empty` renders.\n const emptyRef = useRef<HTMLDivElement>(null);\n const describeEmpty = useCallback(() => {\n const node = emptyRef.current;\n /* istanbul ignore if: it's only announced while it's on screen */\n if (!node) return null;\n return spokenText(node);\n }, []);\n\n const autocompleteElement = (\n <div ref={containerRef} className={combinedClasses} {...rest}>\n <div className={controlClasses}>\n <input\n ref={combinedRef}\n type=\"text\"\n className={inputClasses}\n id={controlId}\n value={inputValue}\n placeholder={placeholder}\n disabled={disabled}\n name={name}\n form={form}\n required={required}\n onChange={handleInputChange}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n role=\"combobox\"\n aria-expanded={listOpen}\n aria-controls={listOpen ? listboxId : undefined}\n aria-activedescendant={activeOptionId}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n />\n {showClear && (\n <button\n type=\"button\"\n className={iconRightClickableClass}\n onClick={handleClear}\n aria-label=\"Clear\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n width=\"16\"\n height=\"16\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n {loading && (\n <span className={iconRightClass}>\n <span className={loaderClass} />\n </span>\n )}\n </div>\n\n {menuOpen && (\n <div className={dropdownMenuClasses}>\n <div\n ref={dropdownRef}\n className={dropdownContentClass}\n style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto' }}\n onScroll={handleDropdownScroll}\n >\n {header && <div className={dropdownHeaderClass}>{header}</div>}\n\n {listOpen ? (\n <div\n id={listboxId}\n role=\"listbox\"\n aria-labelledby={listLabelId}\n aria-label={listLabelId ? undefined : 'Suggestions'}\n >\n {filteredData.map((item, index) => {\n const isDisabled =\n typeof item !== 'string' && item.disabled;\n const isHighlighted = index === highlightedIndex;\n\n const itemClasses = prefixedClassNames(\n classPrefix,\n 'dropdown-item',\n {\n 'is-active': isHighlighted,\n 'is-disabled': isDisabled,\n }\n );\n\n return (\n <a\n key={index}\n id={`${listboxId}-${index}`}\n data-index={index}\n className={itemClasses}\n onClick={() => !isDisabled && handleSelect(item)}\n onMouseEnter={() =>\n !isDisabled && setHighlightedIndex(index)\n }\n role=\"option\"\n aria-selected={isHighlighted}\n aria-disabled={isDisabled}\n >\n {itemTemplate\n ? itemTemplate(item)\n : getDisplayValue(item)}\n </a>\n );\n })}\n </div>\n ) : (\n <div ref={emptyRef} className={emptyItemClasses}>\n {empty}\n </div>\n )}\n\n {footer && <div className={dropdownFooterClass}>{footer}</div>}\n </div>\n </div>\n )}\n\n <StatusRegion items={emptyItems} describe={describeEmpty} />\n </div>\n );\n\n if (!insideField) {\n return (\n <Field\n label={label}\n labelSize={labelSize}\n labelProps={fieldLabelProps}\n horizontal={horizontal}\n className={fieldClassName}\n >\n {autocompleteElement}\n {messageEl}\n </Field>\n );\n }\n\n return (\n <>\n {autocompleteElement}\n {messageEl}\n </>\n );\n }\n);\n\nAutocomplete.displayName = 'Autocomplete';\n\nexport default Autocomplete;\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
2
+ import React from 'react';
3
+
4
+ // INTERNAL: deliberately not exported from src/index.ts.
5
+ /**
6
+ * A component's children as a flat list, with each Fragment opened up
7
+ * (recursively) so the items inside one count one by one rather than as the
8
+ * Fragment. `Children.toArray` already drops `null`, `undefined` and
9
+ * booleans and flattens arrays, but it keeps a Fragment whole, so an empty
10
+ * one would still count as an item and two items in one would count as one.
11
+ *
12
+ * `Children.toArray` keys restart at ".0" inside each Fragment, so the items
13
+ * in one are re-keyed with the Fragment's own key as a prefix. Otherwise an
14
+ * item in a Fragment and a sibling outside it could share a key.
15
+ *
16
+ * Text and numbers pass through as they are, so a caller that wants only
17
+ * elements filters with `React.isValidElement`.
18
+ */
19
+ function flattenChildren(children, keyPrefix = '') {
20
+ return React.Children.toArray(children).flatMap(child => {
21
+ if (!React.isValidElement(child))
22
+ return [child];
23
+ if (child.type === React.Fragment) {
24
+ return flattenChildren(child.props.children, keyPrefix + child.key);
25
+ }
26
+ return [
27
+ keyPrefix
28
+ ? React.cloneElement(child, { key: keyPrefix + child.key })
29
+ : child,
30
+ ];
31
+ });
32
+ }
33
+
34
+ export { flattenChildren };
35
+ //# sourceMappingURL=flattenChildren.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flattenChildren.js","sources":["../../../src/helpers/flattenChildren.ts"],"sourcesContent":["// INTERNAL: deliberately not exported from src/index.ts.\nimport React from 'react';\n\n/**\n * A component's children as a flat list, with each Fragment opened up\n * (recursively) so the items inside one count one by one rather than as the\n * Fragment. `Children.toArray` already drops `null`, `undefined` and\n * booleans and flattens arrays, but it keeps a Fragment whole, so an empty\n * one would still count as an item and two items in one would count as one.\n *\n * `Children.toArray` keys restart at \".0\" inside each Fragment, so the items\n * in one are re-keyed with the Fragment's own key as a prefix. Otherwise an\n * item in a Fragment and a sibling outside it could share a key.\n *\n * Text and numbers pass through as they are, so a caller that wants only\n * elements filters with `React.isValidElement`.\n */\nexport function flattenChildren(\n children: React.ReactNode,\n keyPrefix = ''\n): React.ReactNode[] {\n return React.Children.toArray(children).flatMap(child => {\n if (!React.isValidElement(child)) return [child];\n if (child.type === React.Fragment) {\n return flattenChildren(\n (child.props as { children?: React.ReactNode }).children,\n keyPrefix + child.key\n );\n }\n return [\n keyPrefix\n ? React.cloneElement(child, { key: keyPrefix + child.key })\n : child,\n ];\n });\n}\n"],"names":[],"mappings":";;;AAAA;AAGA;;;;;;;;;;;;;AAaG;SACa,eAAe,CAC7B,QAAyB,EACzB,SAAS,GAAG,EAAE,EAAA;AAEd,IAAA,OAAO,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,IAAG;AACtD,QAAA,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,KAAK,CAAC;QAChD,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,QAAQ,EAAE;AACjC,YAAA,OAAO,eAAe,CACnB,KAAK,CAAC,KAAwC,CAAC,QAAQ,EACxD,SAAS,GAAG,KAAK,CAAC,GAAG,CACtB;QACH;QACA,OAAO;YACL;AACE,kBAAE,KAAK,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE;AAC1D,kBAAE,KAAK;SACV;AACH,IAAA,CAAC,CAAC;AACJ;;"}
@@ -44,7 +44,8 @@ const visuallyHidden = {
44
44
  border: 0,
45
45
  };
46
46
  /**
47
- * Works out what a status region says. Each item is announced once. Its
47
+ * Works out what a status region says. Each item is announced once each time
48
+ * it appears, so one that goes and comes back is announced again. Its
48
49
  * announcement is written `announceDelay` after it appears, or after the last
49
50
  * item to join it when several appear in quick succession, alongside whatever
50
51
  * the region still says. Once written, it stays for `announcementLifetime`,
@@ -79,8 +80,8 @@ function useAnnouncements(items, describe) {
79
80
  useEffect(() => {
80
81
  const announced = onScreenIdsRef.current;
81
82
  const appeared = items.filter(item => !announced.has(item.id));
82
- // Items that have gone drop out here too. Ids are never reused, so
83
- // forgetting them can't bring an old item back.
83
+ // Items that have gone drop out here too, so one that comes back has
84
+ // appeared again.
84
85
  onScreenIdsRef.current = new Set(items.map(item => item.id));
85
86
  const next = [];
86
87
  for (const item of appeared) {
@@ -93,9 +94,13 @@ function useAnnouncements(items, describe) {
93
94
  setAnnouncements(current => ({
94
95
  ...current,
95
96
  key: current.key + 1,
96
- // Announcements still waiting go out with the new ones. What's
97
- // already written stays put.
98
- waiting: [...current.waiting, ...next],
97
+ // Announcements still waiting go out with the new ones, apart from
98
+ // one whose item came back before it was written, which the new one
99
+ // replaces. What's already written stays put.
100
+ waiting: [
101
+ ...current.waiting.filter(waiting => !next.some(({ id }) => id === waiting.id)),
102
+ ...next,
103
+ ],
99
104
  }));
100
105
  }
101
106
  }, [items, describe]);
@@ -254,10 +259,10 @@ function readAloud(element) {
254
259
  return name || blockLevelTags.has(element.tagName) ? ` ${text} ` : text;
255
260
  }
256
261
  /**
257
- * A visually hidden, polite `status` live region that a programmatic
258
- * container announces its items through. The container renders it from the
259
- * moment it mounts, whether or not it has anything to show, so the region is
260
- * already in the page when an announcement is written into it.
262
+ * A visually hidden, polite `status` live region that a container announces
263
+ * its items through. The container renders it from the moment it mounts,
264
+ * whether or not it has anything to show, so the region is already in the
265
+ * page when an announcement is written into it.
261
266
  *
262
267
  * The announcements are this component's own state, so writing and clearing
263
268
  * them re-renders the region and leaves the container's items alone. Each one
@@ -274,8 +279,10 @@ function StatusRegion({ items, describe, }) {
274
279
  // reads the whole region on every change. Each announcement is its own
275
280
  // node, and only additions are relevant by default, so with atomic off a
276
281
  // screen reader reads just what was written, and removing one announcement
277
- // doesn't read out the ones still there.
278
- return (jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "false", style: visuallyHidden, children: announcements.map(announcement => (jsx("div", { children: announcement.text }, announcement.id))) }));
282
+ // doesn't read out the ones still there. A node is keyed by its batch as
283
+ // well as its item, since an item that comes back can be written again
284
+ // while what it said before is still there.
285
+ return (jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "false", style: visuallyHidden, children: announcements.map(announcement => (jsx("div", { children: announcement.text }, `${announcement.batch}:${announcement.id}`))) }));
279
286
  }
280
287
 
281
288
  export { StatusRegion, announceDelay, announcementLifetime, spokenText, visuallyHidden };