@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
@@ -1 +1 @@
1
- {"version":3,"file":"statusRegion.js","sources":["../../../src/helpers/statusRegion.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\n\n/**\n * What a status region says for one of a container's items.\n */\ninterface Announcement {\n /** The id of the item it announces. */\n id: string;\n /** The text a screen reader reads out. */\n text: string;\n}\n\n/**\n * An announcement in the region.\n */\ninterface WrittenAnnouncement extends Announcement {\n /** The batch it was written with, which is what its clear removes. */\n batch: number;\n}\n\n/**\n * How long after an item appears its announcement is written, in ms. The wait\n * lets a screen reader register a region the container has only just mounted,\n * and items shown in quick succession are written, and read out, together.\n */\nexport const announceDelay = 100;\n\n/**\n * How long an announcement stays in the region once written, in ms. That's\n * long enough for a screen reader to pick it up. Clearing it after keeps a\n * second copy of the item's text from sitting in the page, where someone\n * reading through the page, or a test looking the text up, would find it\n * again.\n */\nexport const announcementLifetime = 1000;\n\n/**\n * What the region says, and what it's about to say.\n */\ninterface Announcements {\n /**\n * Changes whenever announcements join the wait, which restarts it. It also\n * names the batch they're written with.\n */\n key: number;\n /** Waiting to be written, in the order their items were shown. */\n waiting: Announcement[];\n /** In the region, in the order they were written. */\n written: WrittenAnnouncement[];\n}\n\nconst noAnnouncements: Announcement[] = [];\nconst nothingWritten: WrittenAnnouncement[] = [];\nconst noAnnouncementsYet: Announcements = {\n key: 0,\n waiting: noAnnouncements,\n written: nothingWritten,\n};\n\n// Hides the region with inline styles rather than a class, so it needs no\n// stylesheet, including the helper classes a modular Bulma build can leave\n// out. Clipping it, rather than using `display` or `visibility`, keeps it in\n// the accessibility tree. The declarations match the `extras-sr-only` mixin,\n// plus `clip-path`, which replaces the deprecated `clip`. The negative margin\n// pulls the 1px box back inside the page, so it doesn't add scrollable\n// overflow. Exported for other live regions that must work without a\n// stylesheet, such as a range calendar's.\nexport const visuallyHidden: React.CSSProperties = {\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: 0,\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n border: 0,\n};\n\n/**\n * Works out what a status region says. Each item is announced once. Its\n * announcement is written `announceDelay` after it appears, or after the last\n * item to join it when several appear in quick succession, alongside whatever\n * the region still says. Once written, it stays for `announcementLifetime`,\n * whatever is written after it and whether or not its item goes in the\n * meantime. An item that goes before its announcement is written isn't\n * announced.\n *\n * Nothing is written in the commit that mounts the region or the item. A\n * screen reader reliably announces a polite live region whose content changes\n * after the region is already in the page, and not always one that arrives\n * with its content. By the time `describe` runs, an item's rendered text can\n * be read.\n *\n * @function useAnnouncements\n * @param items - The items to announce, in the order they were shown.\n * @param describe - The text to announce for an item, or nothing to skip it.\n * It runs once the item is on screen, and it must keep its identity between\n * renders (a module-level function or a `useCallback`), or every render\n * re-checks the items.\n * @returns The announcements to render, in the order they were written.\n */\nfunction useAnnouncements<Item extends { id: string }>(\n items: readonly Item[],\n describe: (item: Item) => string | null\n): WrittenAnnouncement[] {\n // The ids of the items on screen as of the last change, every one of which\n // has been looked at for an announcement already.\n const onScreenIdsRef = useRef(new Set<string>());\n // Clears that haven't run yet. They outlive the batch that started them, so\n // they're only stopped when the region unmounts.\n const clearTimersRef = useRef(new Set<ReturnType<typeof setTimeout>>());\n const [announcements, setAnnouncements] = useState(noAnnouncementsYet);\n\n // Runs after the commit that puts an item on screen, which is the first\n // point its rendered text can be read.\n useEffect(() => {\n const announced = onScreenIdsRef.current;\n const appeared = items.filter(item => !announced.has(item.id));\n // Items that have gone drop out here too. Ids are never reused, so\n // forgetting them can't bring an old item back.\n onScreenIdsRef.current = new Set(items.map(item => item.id));\n\n const next: Announcement[] = [];\n for (const item of appeared) {\n const text = describe(item);\n if (text) next.push({ id: item.id, text });\n }\n if (next.length > 0) {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- an item's rendered text can only be read once it's on screen\n setAnnouncements(current => ({\n ...current,\n key: current.key + 1,\n // Announcements still waiting go out with the new ones. What's\n // already written stays put.\n waiting: [...current.waiting, ...next],\n }));\n }\n }, [items, describe]);\n\n // The write only touches the batch it was started for: a newer batch can\n // be set before the render that cancels this timer. Its clear is started\n // by the write itself, so it's timed from the write without waiting on a\n // render, and a newer batch arriving doesn't cut short what's written.\n const { key } = announcements;\n useEffect(() => {\n if (key === noAnnouncementsYet.key) return undefined;\n const clearTimers = clearTimersRef.current;\n const write = setTimeout(() => {\n // Whether an item is on screen is decided here, once. An item that\n // went before its announcement was due isn't announced, and one that\n // goes after keeps its announcement for the rest of its lifetime, when\n // the region holds the only copy of its text rather than a second one.\n const onScreen = onScreenIdsRef.current;\n setAnnouncements(current =>\n current.key === key\n ? {\n ...current,\n waiting: noAnnouncements,\n written: [\n ...current.written,\n ...current.waiting\n .filter(announcement => onScreen.has(announcement.id))\n .map(announcement => ({ ...announcement, batch: key })),\n ],\n }\n : current\n );\n // eslint-disable-next-line @eslint-react/web-api-no-leaked-timeout -- it has to outlive this effect when a newer batch arrives, so the unmount effect below clears it\n const clear = setTimeout(() => {\n clearTimers.delete(clear);\n setAnnouncements(current => {\n const written = current.written.filter(\n announcement => announcement.batch !== key\n );\n return written.length === current.written.length\n ? current\n : { ...current, written };\n });\n }, announcementLifetime);\n clearTimers.add(clear);\n }, announceDelay);\n return () => clearTimeout(write);\n }, [key]);\n\n useEffect(() => {\n const clearTimers = clearTimersRef.current;\n return () => {\n clearTimers.forEach(clearTimeout);\n clearTimers.clear();\n };\n }, []);\n\n return announcements.written;\n}\n\n/**\n * Reads an element out roughly the way a screen reader would: its text, with\n * an element's `aria-label`, or an image's `alt`, standing in for what's\n * inside it, a break between block-level elements, and parts that are\n * `aria-hidden`, `hidden` or inline-styled `display: none` left out. It isn't\n * the full accessible name computation, so `aria-labelledby`, CSS-generated\n * content, content hidden by a stylesheet and other ways of naming or hiding\n * content aren't followed.\n *\n * @function spokenText\n * @param element - The element to read.\n * @returns Its text, with runs of whitespace collapsed and the ends trimmed.\n */\nexport function spokenText(element: Element): string {\n return readAloud(element).replace(/\\s+/g, ' ').trim();\n}\n\n// Elements a browser displays as blocks by default, and `br`. A screen reader\n// pauses between them, so their text shouldn't run into the text beside them.\n// They're known by tag rather than by computed `display`, which would depend\n// on a stylesheet and on layout.\nconst blockLevelTags = new Set([\n 'ADDRESS',\n 'ARTICLE',\n 'ASIDE',\n 'BLOCKQUOTE',\n 'BR',\n 'CAPTION',\n 'DD',\n 'DETAILS',\n 'DIALOG',\n 'DIV',\n 'DL',\n 'DT',\n 'FIELDSET',\n 'FIGCAPTION',\n 'FIGURE',\n 'FOOTER',\n 'FORM',\n 'H1',\n 'H2',\n 'H3',\n 'H4',\n 'H5',\n 'H6',\n 'HEADER',\n 'HGROUP',\n 'HR',\n 'LEGEND',\n 'LI',\n 'MAIN',\n 'MENU',\n 'NAV',\n 'OL',\n 'P',\n 'PRE',\n 'SEARCH',\n 'SECTION',\n 'SUMMARY',\n 'TABLE',\n 'TBODY',\n 'TD',\n 'TFOOT',\n 'TH',\n 'THEAD',\n 'TR',\n 'UL',\n]);\n\n/**\n * Whether an element is left out of what a screen reader reads.\n *\n * @function isHidden\n * @param element - The element to check.\n * @returns True for `aria-hidden=\"true\"`, the `hidden` attribute, and an\n * inline `display: none`, on an HTML, SVG or any other element with an\n * inline style.\n */\nconst isHidden = (element: Element): boolean =>\n element.getAttribute('aria-hidden') === 'true' ||\n element.hasAttribute('hidden') ||\n (element as Partial<ElementCSSInlineStyle>).style?.display === 'none';\n\n/**\n * The text `spokenText` reads for an element, before its whitespace is\n * tidied.\n *\n * @function readAloud\n * @param element - The element to read.\n * @returns Its text.\n */\nfunction readAloud(element: Element): string {\n if (isHidden(element)) return '';\n const name =\n element.getAttribute('aria-label') ||\n (element.tagName === 'IMG' ? element.getAttribute('alt') : null);\n const text =\n name ||\n Array.from(element.childNodes, child => {\n if (child instanceof Element) return readAloud(child);\n return child.nodeType === Node.TEXT_NODE ? child.textContent : '';\n }).join('');\n // A name stands in for the element's content, and a block's content stands\n // apart from what's around it, so both are padded to keep them from running\n // into the neighboring text. An inline run, like `<span>Up</span>` then\n // `<span>loaded</span>`, still reads as one word.\n return name || blockLevelTags.has(element.tagName) ? ` ${text} ` : text;\n}\n\n/**\n * Props for StatusRegion.\n */\nexport interface StatusRegionProps<Item extends { id: string }> {\n /** The items to announce politely, in the order they were shown. */\n items: readonly Item[];\n /**\n * The text to announce for an item, or nothing to skip it, as\n * `useAnnouncements` takes it.\n */\n describe: (item: Item) => string | null;\n}\n\n/**\n * A visually hidden, polite `status` live region that a programmatic\n * container announces its items through. The container renders it from the\n * moment it mounts, whether or not it has anything to show, so the region is\n * already in the page when an announcement is written into it.\n *\n * The announcements are this component's own state, so writing and clearing\n * them re-renders the region and leaves the container's items alone. Each one\n * is its own keyed node, so a re-render that leaves the announcements alone\n * leaves the region's content alone too, and nothing is read out twice.\n *\n * @function StatusRegion\n * @param props - The items to announce, and the text to announce for each.\n * @returns The region.\n */\nexport function StatusRegion<Item extends { id: string }>({\n items,\n describe,\n}: StatusRegionProps<Item>): React.ReactElement {\n const announcements = useAnnouncements(items, describe);\n\n // `role=\"status\"` makes a region atomic unless it says otherwise, which\n // reads the whole region on every change. Each announcement is its own\n // node, and only additions are relevant by default, so with atomic off a\n // screen reader reads just what was written, and removing one announcement\n // doesn't read out the ones still there.\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n style={visuallyHidden}\n >\n {announcements.map(announcement => (\n <div key={announcement.id}>{announcement.text}</div>\n ))}\n </div>\n );\n}\n"],"names":["_jsx"],"mappings":"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"}
1
+ {"version":3,"file":"statusRegion.js","sources":["../../../src/helpers/statusRegion.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\n\n/**\n * What a status region says for one of a container's items.\n */\ninterface Announcement {\n /** The id of the item it announces. */\n id: string;\n /** The text a screen reader reads out. */\n text: string;\n}\n\n/**\n * An announcement in the region.\n */\ninterface WrittenAnnouncement extends Announcement {\n /** The batch it was written with, which is what its clear removes. */\n batch: number;\n}\n\n/**\n * How long after an item appears its announcement is written, in ms. The wait\n * lets a screen reader register a region the container has only just mounted,\n * and items shown in quick succession are written, and read out, together.\n */\nexport const announceDelay = 100;\n\n/**\n * How long an announcement stays in the region once written, in ms. That's\n * long enough for a screen reader to pick it up. Clearing it after keeps a\n * second copy of the item's text from sitting in the page, where someone\n * reading through the page, or a test looking the text up, would find it\n * again.\n */\nexport const announcementLifetime = 1000;\n\n/**\n * What the region says, and what it's about to say.\n */\ninterface Announcements {\n /**\n * Changes whenever announcements join the wait, which restarts it. It also\n * names the batch they're written with.\n */\n key: number;\n /** Waiting to be written, in the order their items were shown. */\n waiting: Announcement[];\n /** In the region, in the order they were written. */\n written: WrittenAnnouncement[];\n}\n\nconst noAnnouncements: Announcement[] = [];\nconst nothingWritten: WrittenAnnouncement[] = [];\nconst noAnnouncementsYet: Announcements = {\n key: 0,\n waiting: noAnnouncements,\n written: nothingWritten,\n};\n\n// Hides the region with inline styles rather than a class, so it needs no\n// stylesheet, including the helper classes a modular Bulma build can leave\n// out. Clipping it, rather than using `display` or `visibility`, keeps it in\n// the accessibility tree. The declarations match the `extras-sr-only` mixin,\n// plus `clip-path`, which replaces the deprecated `clip`. The negative margin\n// pulls the 1px box back inside the page, so it doesn't add scrollable\n// overflow. Exported for other live regions that must work without a\n// stylesheet, such as a range calendar's.\nexport const visuallyHidden: React.CSSProperties = {\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: 0,\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n border: 0,\n};\n\n/**\n * Works out what a status region says. Each item is announced once each time\n * it appears, so one that goes and comes back is announced again. Its\n * announcement is written `announceDelay` after it appears, or after the last\n * item to join it when several appear in quick succession, alongside whatever\n * the region still says. Once written, it stays for `announcementLifetime`,\n * whatever is written after it and whether or not its item goes in the\n * meantime. An item that goes before its announcement is written isn't\n * announced.\n *\n * Nothing is written in the commit that mounts the region or the item. A\n * screen reader reliably announces a polite live region whose content changes\n * after the region is already in the page, and not always one that arrives\n * with its content. By the time `describe` runs, an item's rendered text can\n * be read.\n *\n * @function useAnnouncements\n * @param items - The items to announce, in the order they were shown.\n * @param describe - The text to announce for an item, or nothing to skip it.\n * It runs once the item is on screen, and it must keep its identity between\n * renders (a module-level function or a `useCallback`), or every render\n * re-checks the items.\n * @returns The announcements to render, in the order they were written.\n */\nfunction useAnnouncements<Item extends { id: string }>(\n items: readonly Item[],\n describe: (item: Item) => string | null\n): WrittenAnnouncement[] {\n // The ids of the items on screen as of the last change, every one of which\n // has been looked at for an announcement already.\n const onScreenIdsRef = useRef(new Set<string>());\n // Clears that haven't run yet. They outlive the batch that started them, so\n // they're only stopped when the region unmounts.\n const clearTimersRef = useRef(new Set<ReturnType<typeof setTimeout>>());\n const [announcements, setAnnouncements] = useState(noAnnouncementsYet);\n\n // Runs after the commit that puts an item on screen, which is the first\n // point its rendered text can be read.\n useEffect(() => {\n const announced = onScreenIdsRef.current;\n const appeared = items.filter(item => !announced.has(item.id));\n // Items that have gone drop out here too, so one that comes back has\n // appeared again.\n onScreenIdsRef.current = new Set(items.map(item => item.id));\n\n const next: Announcement[] = [];\n for (const item of appeared) {\n const text = describe(item);\n if (text) next.push({ id: item.id, text });\n }\n if (next.length > 0) {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- an item's rendered text can only be read once it's on screen\n setAnnouncements(current => ({\n ...current,\n key: current.key + 1,\n // Announcements still waiting go out with the new ones, apart from\n // one whose item came back before it was written, which the new one\n // replaces. What's already written stays put.\n waiting: [\n ...current.waiting.filter(\n waiting => !next.some(({ id }) => id === waiting.id)\n ),\n ...next,\n ],\n }));\n }\n }, [items, describe]);\n\n // The write only touches the batch it was started for: a newer batch can\n // be set before the render that cancels this timer. Its clear is started\n // by the write itself, so it's timed from the write without waiting on a\n // render, and a newer batch arriving doesn't cut short what's written.\n const { key } = announcements;\n useEffect(() => {\n if (key === noAnnouncementsYet.key) return undefined;\n const clearTimers = clearTimersRef.current;\n const write = setTimeout(() => {\n // Whether an item is on screen is decided here, once. An item that\n // went before its announcement was due isn't announced, and one that\n // goes after keeps its announcement for the rest of its lifetime, when\n // the region holds the only copy of its text rather than a second one.\n const onScreen = onScreenIdsRef.current;\n setAnnouncements(current =>\n current.key === key\n ? {\n ...current,\n waiting: noAnnouncements,\n written: [\n ...current.written,\n ...current.waiting\n .filter(announcement => onScreen.has(announcement.id))\n .map(announcement => ({ ...announcement, batch: key })),\n ],\n }\n : current\n );\n // eslint-disable-next-line @eslint-react/web-api-no-leaked-timeout -- it has to outlive this effect when a newer batch arrives, so the unmount effect below clears it\n const clear = setTimeout(() => {\n clearTimers.delete(clear);\n setAnnouncements(current => {\n const written = current.written.filter(\n announcement => announcement.batch !== key\n );\n return written.length === current.written.length\n ? current\n : { ...current, written };\n });\n }, announcementLifetime);\n clearTimers.add(clear);\n }, announceDelay);\n return () => clearTimeout(write);\n }, [key]);\n\n useEffect(() => {\n const clearTimers = clearTimersRef.current;\n return () => {\n clearTimers.forEach(clearTimeout);\n clearTimers.clear();\n };\n }, []);\n\n return announcements.written;\n}\n\n/**\n * Reads an element out roughly the way a screen reader would: its text, with\n * an element's `aria-label`, or an image's `alt`, standing in for what's\n * inside it, a break between block-level elements, and parts that are\n * `aria-hidden`, `hidden` or inline-styled `display: none` left out. It isn't\n * the full accessible name computation, so `aria-labelledby`, CSS-generated\n * content, content hidden by a stylesheet and other ways of naming or hiding\n * content aren't followed.\n *\n * @function spokenText\n * @param element - The element to read.\n * @returns Its text, with runs of whitespace collapsed and the ends trimmed.\n */\nexport function spokenText(element: Element): string {\n return readAloud(element).replace(/\\s+/g, ' ').trim();\n}\n\n// Elements a browser displays as blocks by default, and `br`. A screen reader\n// pauses between them, so their text shouldn't run into the text beside them.\n// They're known by tag rather than by computed `display`, which would depend\n// on a stylesheet and on layout.\nconst blockLevelTags = new Set([\n 'ADDRESS',\n 'ARTICLE',\n 'ASIDE',\n 'BLOCKQUOTE',\n 'BR',\n 'CAPTION',\n 'DD',\n 'DETAILS',\n 'DIALOG',\n 'DIV',\n 'DL',\n 'DT',\n 'FIELDSET',\n 'FIGCAPTION',\n 'FIGURE',\n 'FOOTER',\n 'FORM',\n 'H1',\n 'H2',\n 'H3',\n 'H4',\n 'H5',\n 'H6',\n 'HEADER',\n 'HGROUP',\n 'HR',\n 'LEGEND',\n 'LI',\n 'MAIN',\n 'MENU',\n 'NAV',\n 'OL',\n 'P',\n 'PRE',\n 'SEARCH',\n 'SECTION',\n 'SUMMARY',\n 'TABLE',\n 'TBODY',\n 'TD',\n 'TFOOT',\n 'TH',\n 'THEAD',\n 'TR',\n 'UL',\n]);\n\n/**\n * Whether an element is left out of what a screen reader reads.\n *\n * @function isHidden\n * @param element - The element to check.\n * @returns True for `aria-hidden=\"true\"`, the `hidden` attribute, and an\n * inline `display: none`, on an HTML, SVG or any other element with an\n * inline style.\n */\nconst isHidden = (element: Element): boolean =>\n element.getAttribute('aria-hidden') === 'true' ||\n element.hasAttribute('hidden') ||\n (element as Partial<ElementCSSInlineStyle>).style?.display === 'none';\n\n/**\n * The text `spokenText` reads for an element, before its whitespace is\n * tidied.\n *\n * @function readAloud\n * @param element - The element to read.\n * @returns Its text.\n */\nfunction readAloud(element: Element): string {\n if (isHidden(element)) return '';\n const name =\n element.getAttribute('aria-label') ||\n (element.tagName === 'IMG' ? element.getAttribute('alt') : null);\n const text =\n name ||\n Array.from(element.childNodes, child => {\n if (child instanceof Element) return readAloud(child);\n return child.nodeType === Node.TEXT_NODE ? child.textContent : '';\n }).join('');\n // A name stands in for the element's content, and a block's content stands\n // apart from what's around it, so both are padded to keep them from running\n // into the neighboring text. An inline run, like `<span>Up</span>` then\n // `<span>loaded</span>`, still reads as one word.\n return name || blockLevelTags.has(element.tagName) ? ` ${text} ` : text;\n}\n\n/**\n * Props for StatusRegion.\n */\nexport interface StatusRegionProps<Item extends { id: string }> {\n /** The items to announce politely, in the order they were shown. */\n items: readonly Item[];\n /**\n * The text to announce for an item, or nothing to skip it, as\n * `useAnnouncements` takes it.\n */\n describe: (item: Item) => string | null;\n}\n\n/**\n * A visually hidden, polite `status` live region that a container announces\n * its items through. The container renders it from the moment it mounts,\n * whether or not it has anything to show, so the region is already in the\n * page when an announcement is written into it.\n *\n * The announcements are this component's own state, so writing and clearing\n * them re-renders the region and leaves the container's items alone. Each one\n * is its own keyed node, so a re-render that leaves the announcements alone\n * leaves the region's content alone too, and nothing is read out twice.\n *\n * @function StatusRegion\n * @param props - The items to announce, and the text to announce for each.\n * @returns The region.\n */\nexport function StatusRegion<Item extends { id: string }>({\n items,\n describe,\n}: StatusRegionProps<Item>): React.ReactElement {\n const announcements = useAnnouncements(items, describe);\n\n // `role=\"status\"` makes a region atomic unless it says otherwise, which\n // reads the whole region on every change. Each announcement is its own\n // node, and only additions are relevant by default, so with atomic off a\n // screen reader reads just what was written, and removing one announcement\n // doesn't read out the ones still there. A node is keyed by its batch as\n // well as its item, since an item that comes back can be written again\n // while what it said before is still there.\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n style={visuallyHidden}\n >\n {announcements.map(announcement => (\n <div key={`${announcement.batch}:${announcement.id}`}>\n {announcement.text}\n </div>\n ))}\n </div>\n );\n}\n"],"names":["_jsx"],"mappings":"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"}