@allxsmith/bestax-bulma 5.57.5 → 5.59.0
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.
- package/dist/bestax.css +1 -1
- package/dist/bestax.css.map +1 -1
- package/dist/esm/components/Avatars.js +2 -2
- package/dist/esm/components/Avatars.js.map +1 -1
- package/dist/esm/components/Badge.js +2 -2
- package/dist/esm/components/Badge.js.map +1 -1
- package/dist/esm/components/Pagination.js +2 -2
- package/dist/esm/components/Pagination.js.map +1 -1
- package/dist/esm/components/Steps.js +2 -2
- package/dist/esm/components/Steps.js.map +1 -1
- package/dist/esm/components/TreeView.js +7 -5
- package/dist/esm/components/TreeView.js.map +1 -1
- package/dist/esm/components/useDataTable.js +2 -2
- package/dist/esm/components/useDataTable.js.map +1 -1
- package/dist/esm/elements/Buttons.js +2 -0
- package/dist/esm/elements/Buttons.js.map +1 -1
- package/dist/esm/elements/IconButton.js +114 -0
- package/dist/esm/elements/IconButton.js.map +1 -0
- package/dist/esm/elements/NumberFormatter.js +42 -0
- package/dist/esm/elements/NumberFormatter.js.map +1 -0
- package/dist/esm/elements/RingProgress.js +2 -2
- package/dist/esm/elements/RingProgress.js.map +1 -1
- package/dist/esm/form/Dropzone.js +2 -2
- package/dist/esm/form/Dropzone.js.map +1 -1
- package/dist/esm/form/File.js +2 -2
- package/dist/esm/form/File.js.map +1 -1
- package/dist/esm/form/Rate.js +2 -2
- package/dist/esm/form/Rate.js.map +1 -1
- package/dist/esm/form/Slider.js +2 -2
- package/dist/esm/form/Slider.js.map +1 -1
- package/dist/esm/form/Taginput.js +2 -2
- package/dist/esm/form/Taginput.js.map +1 -1
- package/dist/esm/form/_colorInternals/pickerState.js +2 -2
- package/dist/esm/form/_colorInternals/pickerState.js.map +1 -1
- package/dist/esm/helpers/LocaleProvider.js +13 -6
- package/dist/esm/helpers/LocaleProvider.js.map +1 -1
- package/dist/esm/helpers/containerBreakpoints.js +14 -0
- package/dist/esm/helpers/containerBreakpoints.js.map +1 -0
- package/dist/esm/helpers/localeFormat.js +196 -36
- package/dist/esm/helpers/localeFormat.js.map +1 -1
- package/dist/esm/helpers/polymorphic.js.map +1 -1
- package/dist/esm/helpers/stackLayout.js +30 -0
- package/dist/esm/helpers/stackLayout.js.map +1 -0
- package/dist/esm/helpers/useBulmaClasses.js +8 -2
- package/dist/esm/helpers/useBulmaClasses.js.map +1 -1
- package/dist/esm/helpers/useFlexboxClasses.js +17 -4
- package/dist/esm/helpers/useFlexboxClasses.js.map +1 -1
- package/dist/esm/helpers/useTreeView.js +54 -20
- package/dist/esm/helpers/useTreeView.js.map +1 -1
- package/dist/esm/layout/Center.js +33 -0
- package/dist/esm/layout/Center.js.map +1 -0
- package/dist/esm/layout/Container.js +2 -6
- package/dist/esm/layout/Container.js.map +1 -1
- package/dist/esm/layout/Flex.js +34 -0
- package/dist/esm/layout/Flex.js.map +1 -0
- package/dist/esm/layout/Group.js +43 -0
- package/dist/esm/layout/Group.js.map +1 -0
- package/dist/esm/layout/Stack.js +34 -0
- package/dist/esm/layout/Stack.js.map +1 -0
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +712 -212
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +7 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/TreeView.d.ts +20 -11
- package/dist/types/elements/Buttons.d.ts +1 -0
- package/dist/types/elements/IconButton.d.ts +110 -0
- package/dist/types/elements/NumberFormatter.d.ts +62 -0
- package/dist/types/helpers/LocaleProvider.d.ts +7 -0
- package/dist/types/helpers/containerBreakpoints.d.ts +2 -0
- package/dist/types/helpers/localeFormat.d.ts +30 -8
- package/dist/types/helpers/polymorphic.d.ts +19 -0
- package/dist/types/helpers/stackLayout.d.ts +62 -0
- package/dist/types/helpers/useBulmaClasses.d.ts +8 -2
- package/dist/types/helpers/useFlexboxClasses.d.ts +26 -3
- package/dist/types/helpers/useTreeView.d.ts +12 -6
- package/dist/types/index.d.ts +10 -1
- package/dist/types/layout/Center.d.ts +54 -0
- package/dist/types/layout/Flex.d.ts +92 -0
- package/dist/types/layout/Group.d.ts +86 -0
- package/dist/types/layout/Stack.d.ts +63 -0
- package/dist/types-cjs/components/TreeView.d.ts +20 -11
- package/dist/types-cjs/elements/Buttons.d.ts +1 -0
- package/dist/types-cjs/elements/IconButton.d.ts +110 -0
- package/dist/types-cjs/elements/NumberFormatter.d.ts +62 -0
- package/dist/types-cjs/helpers/LocaleProvider.d.ts +7 -0
- package/dist/types-cjs/helpers/containerBreakpoints.d.ts +2 -0
- package/dist/types-cjs/helpers/localeFormat.d.ts +30 -8
- package/dist/types-cjs/helpers/polymorphic.d.ts +19 -0
- package/dist/types-cjs/helpers/stackLayout.d.ts +62 -0
- package/dist/types-cjs/helpers/useBulmaClasses.d.ts +8 -2
- package/dist/types-cjs/helpers/useFlexboxClasses.d.ts +26 -3
- package/dist/types-cjs/helpers/useTreeView.d.ts +12 -6
- package/dist/types-cjs/index.d.ts +10 -1
- package/dist/types-cjs/layout/Center.d.ts +54 -0
- package/dist/types-cjs/layout/Flex.d.ts +92 -0
- package/dist/types-cjs/layout/Group.d.ts +86 -0
- package/dist/types-cjs/layout/Stack.d.ts +63 -0
- package/dist/versions/bestax-no-dark-mode.css +1 -1
- package/dist/versions/bestax-no-dark-mode.css.map +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
- package/dist/versions/bestax-no-helpers.css +1 -1
- package/dist/versions/bestax-no-helpers.css.map +1 -1
- package/dist/versions/bestax-prefixed.css +1 -1
- package/dist/versions/bestax-prefixed.css.map +1 -1
- package/package.json +1 -1
- package/src/scss/elements/_iconbutton.scss +36 -0
- package/src/scss/elements/_index.scss +1 -0
- package/src/scss/layout/_index.scss +1 -0
- package/src/scss/layout/_stack.scss +145 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeView.js","sources":["../../../src/components/TreeView.tsx"],"sourcesContent":["import React, {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { warnOnce } from '../helpers/devWarnings';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport { useTreeView, type TreeViewEngine } from '../helpers/useTreeView';\nimport { StatusRegion, spokenText } from '../helpers/statusRegion';\nimport { Checkbox } from '../form/Checkbox';\nimport { Icon } from '../elements/Icon';\n\n/**\n * How items are picked: `none`, nothing is; `single`, one item at a time;\n * `checkbox`, any number, with a box on every item and mixed parents.\n */\nexport type TreeViewSelectionMode = 'none' | 'single' | 'checkbox';\n\nconst validTreeViewSizes = ['small', 'medium', 'large'] as const;\n\n/** What an open item's load says in the tree's live region. */\ninterface LoadAnnouncement {\n /** The item's key, so what it says next replaces this. */\n key: string;\n /** The key and the kind: the region says it once each time it appears. */\n id: string;\n kind: 'loading' | 'loaded' | 'error';\n /** The item's name, read off its label. */\n name: string;\n /** A failed load's message, read off its row. */\n message: string;\n}\n\n/** What the root hands its items: the engine, the live region, and the rows' words. */\ninterface TreeContextValue extends TreeViewEngine {\n /** Puts what an item's load says in the live region, or takes it out with `null`. */\n announce: (key: string, announcement: LoadAnnouncement | null) => void;\n loadingLabel: string;\n retryLabel: string;\n}\n\n// Not exported, so they stay out of the public API that `index.ts` re-exports.\nconst TreeViewContext = createContext<TreeContextValue | null>(null);\n\nconst sayLoading = (name: string) => `Loading ${name}`;\nconst sayLoaded = (name: string) => `${name} loaded`;\n\n/** Where an item sits: the values of the items above it, and whether one of them is closed. */\ninterface Branch {\n path: string[];\n hidden: boolean;\n}\n\nconst TOP: Branch = { path: [], hidden: false };\nconst BranchContext = createContext<Branch>(TOP);\n\n/** The box's input lets the row's click toggle it, so a change on its own does nothing. */\nconst ignoreChange = () => {};\n\n/** Whether an `icon` was given something to render. */\nconst isGiven = (node: React.ReactNode) =>\n node !== undefined &&\n node !== null &&\n typeof node !== 'boolean' &&\n node !== '';\n\n/**\n * Props for the TreeView component. The helper props, the other attributes\n * and the `ref` land on the `<ul role=\"tree\">`.\n *\n * @extraProp {string} [aria-label] - Names the tree, such as \"Files\". A tree needs a name, so pass this or `aria-labelledby`, and a development build warns when it has neither.\n * @extraProp {string} [aria-labelledby] - The id of a visible heading or label that names the tree, in place of `aria-label`.\n * @extraProp {React.Ref<HTMLUListElement>} [ref] - Ref forwarded to the `<ul>`.\n */\nexport interface TreeViewProps\n extends\n Omit<\n React.HTMLAttributes<HTMLUListElement>,\n | keyof BulmaClassesProps\n | 'role'\n | 'onSelect'\n | 'defaultValue'\n | 'defaultChecked'\n >,\n BulmaClassesProps {\n /**\n * `TreeView.Item`s, nested inside each other for their children. Render\n * an item's children whenever you have them, open or not: the tree hides\n * them while it's closed.\n */\n children?: React.ReactNode;\n /**\n * `none`: nothing is picked, and Enter and Space open and close a parent.\n * `single`: one item, picked with Enter, Space or a click.\n * `checkbox`: any number, checked with Space or a click. A check reaches\n * every enabled item under it, and a parent with some of them checked is mixed.\n */\n selectionMode?: TreeViewSelectionMode;\n /**\n * The selected item's value when you hold the state, or `null` for none.\n * Read with `single` only. Picking an item then only calls\n * `onSelectedChange`, and nothing changes until you pass the new value.\n */\n selected?: string | null;\n /** The item selected to begin with, when the tree holds its own state. Read with `single` only. */\n defaultSelected?: string | null;\n /**\n * Called with the value of the item picked. Not called for the one\n * already selected, and moving focus never calls it.\n */\n onSelectedChange?: (value: string) => void;\n /**\n * The checked items' values when you hold the state. Read with `checkbox`\n * only. A value checks its item, and an enabled item also counts as checked\n * when any item above it is in the list, so a parent's value stands for its\n * whole branch, loaded or not. A disabled item is checked only by its own value.\n */\n checked?: string[];\n /** The values checked to begin with, when the tree holds its own state. Read with `checkbox` only. */\n defaultChecked?: string[];\n /**\n * Called after a check or an uncheck with every item that now shows\n * checked, parents included, plus any earlier value that matches no item\n * the tree knows, left as it was. The order means nothing. Passed back as\n * `checked`, the list shows the same boxes.\n */\n onCheckedChange?: (checked: string[]) => void;\n /**\n * The open items' values when you hold the state. A value stays in the\n * list while its item's parent is closed, so the item reopens as it was.\n */\n expanded?: string[];\n /** The items open to begin with, when the tree holds its own state. */\n defaultExpanded?: string[];\n /** Called with the new list whenever an item opens or closes, `*` included. */\n onExpandedChange?: (expanded: string[]) => void;\n /** The text size, as Bulma's menu sizes it. The rows, the indent and the chevron scale with it. */\n size?: 'small' | 'medium' | 'large';\n /** What the row in a loading item's group says. In your app's language. */\n loadingLabel?: string;\n /** The Retry button's text on a failed load's row. In your app's language. */\n retryLabel?: string;\n /**\n * What the live region says when an open item starts loading, built from\n * the item's name. In your app's language. Default: `` `Loading ${name}` ``.\n */\n loadingAnnouncement?: (name: string) => string;\n /**\n * What the live region says when that load finishes. In your app's\n * language. Default: `` `${name} loaded` ``.\n */\n loadedAnnouncement?: (name: string) => string;\n}\n\n/**\n * Props for TreeView.Item, one row and, nested in it, its children. The other\n * attributes and the `ref` land on its `<li role=\"treeitem\">`.\n *\n * @extraProp {number} [aria-posinset] - The item's number among the items beside it. The tree declares it, and `aria-setsize`, from the items on the page once it mounts. When the page holds only part of a set, such as the first page of a long folder, pass both on every item of that set: yours win, and the tree's own stay on any item without them.\n * @extraProp {number} [aria-setsize] - How many items sit beside it, itself included. Declared by the tree like `aria-posinset`, and `-1` says the count isn't known.\n * @extraProp {React.Ref<HTMLLIElement>} [ref] - Ref forwarded to the `<li>`.\n */\nexport interface TreeViewItemProps extends Omit<\n React.LiHTMLAttributes<HTMLLIElement>,\n 'role' | 'value' | 'onSelect' | 'children'\n> {\n /** **Required.** Identifies the item in `selected`, `checked` and `expanded`. Unique in the tree. */\n value: string;\n /**\n * **Required.** What the row shows, and the item's name for assistive\n * tech. Nothing in it should be a link or a button: a tree item does one\n * thing, and nothing else in its row takes focus.\n */\n label: React.ReactNode;\n /** A picture before the label: an `Icon` name, or a node. Hidden from assistive tech. */\n icon?: React.ReactNode;\n /**\n * `TreeView.Item`s under this one. Render them whenever you have them,\n * open or not: the tree hides them while it's closed, and a checkbox tree\n * needs them to know what a check reaches.\n */\n children?: React.ReactNode;\n /** Shows the item as a parent before its children are known, such as a folder that loads when it opens. */\n hasChildren?: boolean;\n /**\n * Its children are on their way. While it's open, its group ends in a row\n * that says so, and the tree's live region says it's loading, then that\n * it's loaded once this goes back to `false`. A parent only: pair it with\n * `hasChildren`, or with the children it already has.\n */\n isLoading?: boolean;\n /**\n * Its children didn't load. While it's open, its group ends in a row with\n * this message, and a Retry button when there's an `onRetry`, and the live\n * region reads the message out, so name the item in it (\"Couldn't load\n * src\"), then says it's loaded once this goes with the item still open. A\n * parent only, like `isLoading`. Nothing in it should be a link or a\n * button: the row is what's pressed. `isLoading` wins while both are given.\n */\n loadError?: React.ReactNode;\n /**\n * Called by the Retry button on a failed load's row, and by Enter or Space\n * there. Set `isLoading` while the retry runs, so the live region says it's\n * loading, and reads the message out again if it fails again. The same\n * message passed a second time with no loading between is no change the\n * tree can see.\n */\n onRetry?: () => void;\n /**\n * Reachable with the arrow keys, Home, End and type-ahead, so a screen\n * reader finds it, but never selected, checked, opened or closed. One\n * that's already open stays open.\n */\n disabled?: boolean;\n}\n\n/**\n * The `TreeView` component renders a tree of items you browse and pick from, the way a file explorer works: one tab stop, the arrow keys to move, and Right and Left to open and close.\n *\n * It's the APG Tree View pattern, drawn to look like Bulma's menu. It isn't\n * for site navigation: items aren't links, and a sidebar whose sections open\n * and close is `Menu`'s job. The root owns which items are open, through\n * `expanded`, `defaultExpanded` and `onExpandedChange`.\n *\n * `selectionMode` picks one of three trees. With `none`, nothing is picked.\n * With `single`, one item is, and `selected` says which. With `checkbox`,\n * each item has a box, a check reaches every enabled item under it, closed\n * branches included, and a parent with some of its items checked is mixed.\n * `selected` is read in a `single` tree only, and `checked` in a `checkbox`\n * tree only. Selection never follows focus.\n *\n * Disabled items stay reachable from the keys, so a screen reader finds\n * them. The tree needs a name, from `aria-label` or `aria-labelledby`, and a\n * development build warns when it has neither.\n *\n * @function\n * @param {TreeViewProps} props - Props for the TreeView component.\n * @param {React.Ref<HTMLUListElement>} ref - Forwarded ref to the `<ul>`.\n * @returns {JSX.Element} The rendered tree.\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/treeview/ | APG Tree View Pattern}\n *\n * @example\n * <TreeView aria-label=\"Files\" selectionMode=\"single\" defaultExpanded={['src']}>\n * <TreeView.Item value=\"src\" label=\"src\" icon=\"folder\">\n * <TreeView.Item value=\"src/index.ts\" label=\"index.ts\" icon=\"file\" />\n * </TreeView.Item>\n * <TreeView.Item value=\"package.json\" label=\"package.json\" icon=\"file\" />\n * </TreeView>\n */\nconst TreeViewRoot = forwardRef<HTMLUListElement, TreeViewProps>(\n function TreeView(\n {\n children,\n selectionMode = 'none',\n selected,\n defaultSelected = null,\n onSelectedChange,\n checked,\n defaultChecked = [],\n onCheckedChange,\n expanded,\n defaultExpanded = [],\n onExpandedChange,\n size,\n loadingLabel = 'Loading…',\n retryLabel = 'Retry',\n loadingAnnouncement,\n loadedAnnouncement,\n className,\n ...props\n },\n ref\n ) {\n const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });\n const engine = useTreeView({\n mode: selectionMode,\n selected,\n defaultSelected,\n onSelectedChange,\n checked,\n defaultChecked,\n onCheckedChange,\n expanded,\n defaultExpanded,\n onExpandedChange,\n });\n\n const { treeRef } = engine;\n const setRefs = useCallback(\n (node: HTMLUListElement | null) => {\n treeRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [ref, treeRef]\n );\n\n const named = Boolean(rest['aria-label'] || rest['aria-labelledby']);\n useEffect(() => {\n if (!named) {\n warnOnce(\n 'TreeView:unnamed',\n '[bestax-bulma] <TreeView> has no accessible name. Pass ' +\n 'aria-label or aria-labelledby, so a screen reader can say what ' +\n 'the tree holds.'\n );\n }\n }, [named]);\n\n const rootClass = usePrefixedClassNames('tree-view', {\n [`is-${size}`]:\n !!size && (validTreeViewSizes as readonly string[]).includes(size),\n });\n\n // What each open item's load says, in the order they started saying it.\n const [announcements, setAnnouncements] = useState<LoadAnnouncement[]>([]);\n const announce = useCallback(\n (key: string, announcement: LoadAnnouncement | null) => {\n setAnnouncements(current => {\n const others = current.filter(said => said.key !== key);\n return announcement ? [...others, announcement] : others;\n });\n },\n []\n );\n const describe = useCallback(\n ({ kind, name, message }: LoadAnnouncement) => {\n if (kind === 'error') return message;\n const say =\n kind === 'loading'\n ? (loadingAnnouncement ?? sayLoading)\n : (loadedAnnouncement ?? sayLoaded);\n return say(name);\n },\n [loadingAnnouncement, loadedAnnouncement]\n );\n\n // The props are spread first, so the role and the attributes the tree\n // owns win over anything a caller passes along. The live region sits\n // beside the tree, since a tree holds items and groups only, and it's\n // there from the start, so a screen reader is listening to it before\n // anything is written into it.\n return (\n <TreeViewContext.Provider\n value={{ ...engine, announce, loadingLabel, retryLabel }}\n >\n <BranchContext.Provider value={TOP}>\n <ul\n {...rest}\n ref={setRefs}\n className={classNames(rootClass, bulmaHelperClasses, className)}\n role=\"tree\"\n aria-multiselectable={engine.rendersClosed || undefined}\n >\n {children}\n </ul>\n </BranchContext.Provider>\n <StatusRegion items={announcements} describe={describe} />\n </TreeViewContext.Provider>\n );\n }\n);\n\n/**\n * One item in the tree: a row with its chevron, its box, its icon and its label, and, while it's open, a group of the items under it.\n *\n * @function\n * @param {TreeViewItemProps} props - Props for TreeView.Item.\n * @param {React.Ref<HTMLLIElement>} ref - Forwarded ref to the `<li>`.\n * @returns {JSX.Element | null} The rendered item, or nothing under a closed one.\n */\nexport const TreeViewItem = forwardRef<HTMLLIElement, TreeViewItemProps>(\n function TreeViewItem(\n {\n value,\n label,\n icon,\n children,\n hasChildren = false,\n isLoading = false,\n loadError,\n onRetry,\n disabled = false,\n className,\n onClick,\n onKeyDown,\n onFocus,\n onBlur,\n ...props\n },\n ref\n ) {\n const tree = useContext(TreeViewContext);\n const branch = useContext(BranchContext);\n // Also the item's key in the live region.\n const labelId = useId();\n const hasItems = React.Children.toArray(children).length > 0;\n const isParent = hasItems || hasChildren;\n const open = isParent && !!tree?.isOpen(value);\n const parent = branch.path[branch.path.length - 1] ?? null;\n\n // The row at the end of its group, while it's open and on the page.\n const shown = open && !branch.hidden;\n const status = !shown\n ? null\n : isLoading\n ? 'loading'\n : isGiven(loadError)\n ? 'error'\n : null;\n const labelRef = useRef<HTMLSpanElement | null>(null);\n const statusLabelRef = useRef<HTMLSpanElement | null>(null);\n\n // What the live region says follows the row: it's loading, or it failed,\n // while the row says so, and it's loaded once the row goes with the item\n // still open, whichever row it was, until the item closes or loads again.\n // A closed item says nothing, loading or not.\n const phase = shown ? (status ?? 'open') : 'closed';\n const lastPhaseRef = useRef(phase);\n const announce = tree?.announce;\n useEffect(() => {\n const was = lastPhaseRef.current;\n lastPhaseRef.current = phase;\n const kind =\n phase === 'loading' || phase === 'error'\n ? phase\n : phase === 'open' && (was === 'loading' || was === 'error')\n ? 'loaded'\n : null;\n if (!kind) return undefined;\n // Only an item inside a tree can be open.\n announce!(labelId, {\n key: labelId,\n id: `${labelId}:${kind}`,\n kind,\n name: spokenText(labelRef.current!),\n message: kind === 'error' ? spokenText(statusLabelRef.current!) : '',\n });\n return () => announce!(labelId, null);\n }, [phase, announce, labelId]);\n\n const itemClass = usePrefixedClassNames('tree-view-item');\n const groupClass = usePrefixedClassNames('tree-view-group');\n const toggleClass = usePrefixedClassNames('tree-view-toggle');\n const checkClass = usePrefixedClassNames('tree-view-check');\n const iconClass = usePrefixedClassNames('tree-view-icon');\n const labelClass = usePrefixedClassNames('tree-view-label');\n\n const register = tree?.register;\n useClientLayoutEffect(() => {\n if (!register) {\n warnOnce(\n 'TreeView.Item:outside',\n '[bestax-bulma] <TreeView.Item> is outside a <TreeView>, so it ' +\n 'renders nothing. Put it inside one.'\n );\n return undefined;\n }\n return register(value, { parent, disabled, isParent });\n }, [register, value, parent, disabled, isParent]);\n\n const setElement = tree?.setElement;\n const setRefs = useCallback(\n (node: HTMLLIElement | null) => {\n // Only an item inside a tree renders an element to hand over.\n setElement!(value, node);\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [setElement, value, ref]\n );\n const rowRef = useRef<HTMLDivElement | null>(null);\n const toggleRef = useRef<HTMLSpanElement | null>(null);\n\n const childBranch = useMemo(\n () => ({\n path: [...branch.path, value],\n hidden: branch.hidden || !open,\n }),\n [branch, value, open]\n );\n\n const { selected, checked } =\n tree?.stateOf(value, branch.path, disabled) ?? {};\n const rowClass = usePrefixedClassNames('tree-view-row', {\n 'is-selected': selected,\n 'is-disabled': disabled,\n });\n\n if (!tree) return null;\n\n // While it's open the children render in its group. In a checkbox tree\n // they render while it's closed too, drawing nothing, so a check knows\n // what's under it.\n const items = (open || tree.rendersClosed) && (\n <BranchContext.Provider value={childBranch}>\n {children}\n </BranchContext.Provider>\n );\n if (branch.hidden) return <>{items}</>;\n\n const info = { value, parent, disabled, isParent, open };\n // A position the caller gives wins, for a set the page holds only part of.\n const position = tree.positionOf(value);\n\n return (\n <li\n {...props}\n ref={setRefs}\n className={classNames(itemClass, className)}\n role=\"treeitem\"\n aria-labelledby={labelId}\n aria-level={branch.path.length + 1}\n aria-posinset={props['aria-posinset'] ?? position?.posinset}\n aria-setsize={props['aria-setsize'] ?? position?.setsize}\n aria-expanded={isParent ? open : undefined}\n aria-disabled={disabled || undefined}\n aria-selected={selected}\n aria-checked={checked}\n tabIndex={tree.tabStop === value ? 0 : -1}\n onKeyDown={event => {\n onKeyDown?.(event);\n tree.onKeyDown(event, info);\n }}\n onFocus={event => {\n onFocus?.(event);\n if (event.target === event.currentTarget) {\n tree.onFocus(value, event.currentTarget);\n }\n }}\n onBlur={event => {\n onBlur?.(event);\n if (event.target === event.currentTarget) tree.onBlur();\n }}\n onClick={event => {\n onClick?.(event);\n // A click in its row is its own, and so is one on the item itself,\n // as a test's click on the treeitem is. One in its group belongs\n // to the item inside it, or to nothing. The chevron's box is on\n // every row, but it's a chevron only on a parent: on a leaf it's\n // more of the row.\n const target = event.target as Node;\n if (\n target === event.currentTarget ||\n rowRef.current!.contains(target)\n ) {\n tree.onClick(\n event.currentTarget,\n info,\n isParent && toggleRef.current!.contains(target)\n );\n }\n }}\n >\n <div className={rowClass} ref={rowRef}>\n <span className={toggleClass} aria-hidden=\"true\" ref={toggleRef} />\n {checked !== undefined && (\n <span\n className={checkClass}\n aria-hidden=\"true\"\n onClick={event => {\n // A click on the box's label is followed by one on its\n // input, and both reach the item. The label's is cancelled,\n // so the item toggles once.\n if (!(event.target instanceof HTMLInputElement)) {\n event.preventDefault();\n }\n }}\n >\n <Checkbox\n tabIndex={-1}\n checked={checked === true}\n indeterminate={checked === 'mixed'}\n disabled={disabled}\n onChange={ignoreChange}\n />\n </span>\n )}\n {isGiven(icon) && (\n <span className={iconClass} aria-hidden=\"true\">\n {typeof icon === 'string' ? <Icon name={icon} /> : icon}\n </span>\n )}\n <span className={labelClass} id={labelId} ref={labelRef}>\n {label}\n </span>\n </div>\n {open && (hasItems || status) ? (\n <ul className={groupClass} role=\"group\">\n {items}\n {status && (\n <StatusRow\n kind={status}\n parent={value}\n level={branch.path.length + 2}\n message={loadError}\n onRetry={onRetry}\n labelRef={statusLabelRef}\n />\n )}\n </ul>\n ) : (\n items\n )}\n </li>\n );\n }\n);\n\nTreeViewItem.displayName = 'TreeView.Item';\n\n/** Props for the row at the end of a loading item's group, or a failed load's. */\ninterface StatusRowProps {\n /** `loading`, or `error` for a load that failed. */\n kind: 'loading' | 'error';\n /** The value of the item it's in. */\n parent: string;\n /** Its `aria-level`, one under the item it's in. */\n level: number;\n /** A failed load's message. */\n message: React.ReactNode;\n /** Retries a failed load. */\n onRetry?: () => void;\n /** For its label, which the item reads a failed load's message off. */\n labelRef: React.Ref<HTMLSpanElement>;\n}\n\n/**\n * The row at the end of a loading item's group, or of one whose load failed.\n * It's a `treeitem` the keys reach, the way they reach a disabled item, so a\n * screen reader finds it. It has no value and no record, so it's never\n * selected or checked, and a check never counts it. A failed load's row with\n * `onRetry` retries with Enter, Space or a click, and any other is disabled.\n * The Retry button is drawn, hidden from assistive tech and out of the tab\n * order, the way an item's box is: the row is what's pressed, and its name\n * says so. Rendered in one place, a failed load's row that starts loading\n * again is the same element, so focus stays on it.\n */\nfunction StatusRow({\n kind,\n parent,\n level,\n message,\n onRetry,\n labelRef,\n}: StatusRowProps) {\n // Only an item inside a tree renders a group.\n const tree = useContext(TreeViewContext)!;\n // Also its key in the registry and for the tab stop, where an item has its value.\n const labelId = useId();\n const retryId = useId();\n const retry = kind === 'error' ? onRetry : undefined;\n\n const itemClass = usePrefixedClassNames('tree-view-item');\n const rowClass = usePrefixedClassNames('tree-view-row', {\n 'is-disabled': !retry,\n });\n const toggleClass = usePrefixedClassNames('tree-view-toggle');\n const labelClass = usePrefixedClassNames('tree-view-label');\n const loaderClass = usePrefixedClassNames('loader');\n const retryClass = usePrefixedClassNames('button', { 'is-small': true });\n\n const { setElement } = tree;\n const setRef = useCallback(\n (node: HTMLLIElement | null) => setElement(labelId, node),\n [setElement, labelId]\n );\n const info = {\n value: labelId,\n parent,\n disabled: !retry,\n isParent: false,\n open: false,\n retry,\n };\n const position = tree.positionOf(labelId);\n\n return (\n <li\n ref={setRef}\n className={itemClass}\n role=\"treeitem\"\n aria-labelledby={retry ? `${labelId} ${retryId}` : labelId}\n aria-level={level}\n aria-posinset={position?.posinset}\n aria-setsize={position?.setsize}\n aria-disabled={!retry || undefined}\n tabIndex={tree.tabStop === labelId ? 0 : -1}\n onKeyDown={event => tree.onKeyDown(event, info)}\n onFocus={event => {\n // Focus in something the message holds isn't the row's.\n if (event.target === event.currentTarget) {\n tree.onFocus(labelId, event.currentTarget);\n }\n }}\n onBlur={event => {\n if (event.target === event.currentTarget) tree.onBlur();\n }}\n onClick={event => tree.onClick(event.currentTarget, info, false)}\n >\n <div className={rowClass}>\n <span className={toggleClass} aria-hidden=\"true\">\n {kind === 'loading' && <span className={loaderClass} />}\n </span>\n <span className={labelClass} id={labelId} ref={labelRef}>\n {kind === 'loading' ? tree.loadingLabel : message}\n </span>\n {retry && (\n <span className={retryClass} id={retryId} aria-hidden=\"true\">\n {tree.retryLabel}\n </span>\n )}\n </div>\n </li>\n );\n}\n\nexport const TreeView = withSubComponents(\n TreeViewRoot,\n { Item: TreeViewItem },\n 'TreeView'\n);\n\nexport default TreeView;\n"],"names":["isGiven","_jsxs","_jsx","_Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TreeView.js","sources":["../../../src/components/TreeView.tsx"],"sourcesContent":["import React, {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { warnOnce } from '../helpers/devWarnings';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport { useTreeView, type TreeViewEngine } from '../helpers/useTreeView';\nimport { StatusRegion, spokenText } from '../helpers/statusRegion';\nimport { Checkbox } from '../form/Checkbox';\nimport { Icon } from '../elements/Icon';\n\n/**\n * How items are picked: `none`, nothing is; `single`, one item at a time;\n * `checkbox`, any number, with a box on every item and mixed parents;\n * `checkbox-independent`, any number, with a box on every item that checks\n * that item alone.\n */\nexport type TreeViewSelectionMode =\n 'none' | 'single' | 'checkbox' | 'checkbox-independent';\n\nconst validTreeViewSizes = ['small', 'medium', 'large'] as const;\n\n/** What an open item's load says in the tree's live region. */\ninterface LoadAnnouncement {\n /** The item's key, so what it says next replaces this. */\n key: string;\n /** The key and the kind: the region says it once each time it appears. */\n id: string;\n kind: 'loading' | 'loaded' | 'error';\n /** The item's name, read off its label. */\n name: string;\n /** A failed load's message, read off its row. */\n message: string;\n}\n\n/** What the root hands its items: the engine, the live region, and the rows' words. */\ninterface TreeContextValue extends TreeViewEngine {\n /** Puts what an item's load says in the live region, or takes it out with `null`. */\n announce: (key: string, announcement: LoadAnnouncement | null) => void;\n loadingLabel: string;\n retryLabel: string;\n}\n\n// Not exported, so they stay out of the public API that `index.ts` re-exports.\nconst TreeViewContext = createContext<TreeContextValue | null>(null);\n\nconst sayLoading = (name: string) => `Loading ${name}`;\nconst sayLoaded = (name: string) => `${name} loaded`;\n\n/** Where an item sits: the values of the items above it, and whether one of them is closed. */\ninterface Branch {\n path: string[];\n hidden: boolean;\n}\n\nconst TOP: Branch = { path: [], hidden: false };\nconst BranchContext = createContext<Branch>(TOP);\n\n/** The box's input lets the row's click toggle it, so a change on its own does nothing. */\nconst ignoreChange = () => {};\n\n/** Whether an `icon` was given something to render. */\nconst isGiven = (node: React.ReactNode) =>\n node !== undefined &&\n node !== null &&\n typeof node !== 'boolean' &&\n node !== '';\n\n/**\n * Props for the TreeView component. The helper props, the other attributes\n * and the `ref` land on the `<ul role=\"tree\">`.\n *\n * @extraProp {string} [aria-label] - Names the tree, such as \"Files\". A tree needs a name, so pass this or `aria-labelledby`, and a development build warns when it has neither.\n * @extraProp {string} [aria-labelledby] - The id of a visible heading or label that names the tree, in place of `aria-label`.\n * @extraProp {React.Ref<HTMLUListElement>} [ref] - Ref forwarded to the `<ul>`.\n */\nexport interface TreeViewProps\n extends\n Omit<\n React.HTMLAttributes<HTMLUListElement>,\n | keyof BulmaClassesProps\n | 'role'\n | 'onSelect'\n | 'defaultValue'\n | 'defaultChecked'\n >,\n BulmaClassesProps {\n /**\n * `TreeView.Item`s, nested inside each other for their children. Render\n * an item's children whenever you have them, open or not: the tree hides\n * them while it's closed.\n */\n children?: React.ReactNode;\n /**\n * `none`: nothing is picked, and Enter and Space open and close a parent.\n * `single`: one item, picked with Enter, Space or a click.\n * `checkbox`: any number, checked with Space or a click. A check reaches\n * every enabled item under it, and a parent with some of them checked is mixed.\n * `checkbox-independent`: any number, checked with Space or a click, each\n * box for its own item. A check reaches nothing under it, and no parent is\n * mixed (Mantine's and Ant Design's `checkStrictly`).\n */\n selectionMode?: TreeViewSelectionMode;\n /**\n * The selected item's value when you hold the state, or `null` for none.\n * Read with `single` only. Picking an item then only calls\n * `onSelectedChange`, and nothing changes until you pass the new value.\n */\n selected?: string | null;\n /** The item selected to begin with, when the tree holds its own state. Read with `single` only. */\n defaultSelected?: string | null;\n /**\n * Called with the value of the item picked. Not called for the one\n * already selected, and moving focus never calls it.\n */\n onSelectedChange?: (value: string) => void;\n /**\n * The checked items' values when you hold the state. Read with `checkbox`\n * and `checkbox-independent` only. A value checks its item. In `checkbox`,\n * an enabled item also counts as checked when any item above it is in the\n * list, so a parent's value stands for its whole branch, loaded or not, and\n * a disabled item is checked only by its own value. In\n * `checkbox-independent`, a value checks its own item and nothing else.\n */\n checked?: string[];\n /** The values checked to begin with, when the tree holds its own state. Read with `checkbox` and `checkbox-independent` only. */\n defaultChecked?: string[];\n /**\n * Called after a check or an uncheck. In `checkbox`, with every item that\n * now shows checked, parents included, plus any earlier value that matches\n * no item the tree knows, left as it was, and the order means nothing. In\n * `checkbox-independent`, with the list as it was, the item's value added\n * at the end or every copy of it taken out, and everything else in the\n * same order. Passed back as `checked`, the list shows the same boxes.\n */\n onCheckedChange?: (checked: string[]) => void;\n /**\n * The open items' values when you hold the state. A value stays in the\n * list while its item's parent is closed, so the item reopens as it was.\n */\n expanded?: string[];\n /** The items open to begin with, when the tree holds its own state. */\n defaultExpanded?: string[];\n /** Called with the new list whenever an item opens or closes, `*` included. */\n onExpandedChange?: (expanded: string[]) => void;\n /** The text size, as Bulma's menu sizes it. The rows, the indent and the chevron scale with it. */\n size?: 'small' | 'medium' | 'large';\n /** What the row in a loading item's group says. In your app's language. */\n loadingLabel?: string;\n /** The Retry button's text on a failed load's row. In your app's language. */\n retryLabel?: string;\n /**\n * What the live region says when an open item starts loading, built from\n * the item's name. In your app's language. Default: `` `Loading ${name}` ``.\n */\n loadingAnnouncement?: (name: string) => string;\n /**\n * What the live region says when that load finishes. In your app's\n * language. Default: `` `${name} loaded` ``.\n */\n loadedAnnouncement?: (name: string) => string;\n}\n\n/**\n * Props for TreeView.Item, one row and, nested in it, its children. The other\n * attributes and the `ref` land on its `<li role=\"treeitem\">`.\n *\n * @extraProp {number} [aria-posinset] - The item's number among the items beside it. The tree declares it, and `aria-setsize`, from the items on the page once it mounts. When the page holds only part of a set, such as the first page of a long folder, pass both on every item of that set: yours win, and the tree's own stay on any item without them.\n * @extraProp {number} [aria-setsize] - How many items sit beside it, itself included. Declared by the tree like `aria-posinset`, and `-1` says the count isn't known.\n * @extraProp {React.Ref<HTMLLIElement>} [ref] - Ref forwarded to the `<li>`.\n */\nexport interface TreeViewItemProps extends Omit<\n React.LiHTMLAttributes<HTMLLIElement>,\n 'role' | 'value' | 'onSelect' | 'children'\n> {\n /** **Required.** Identifies the item in `selected`, `checked` and `expanded`. Unique in the tree. */\n value: string;\n /**\n * **Required.** What the row shows, and the item's name for assistive\n * tech. Nothing in it should be a link or a button: a tree item does one\n * thing, and nothing else in its row takes focus.\n */\n label: React.ReactNode;\n /** A picture before the label: an `Icon` name, or a node. Hidden from assistive tech. */\n icon?: React.ReactNode;\n /**\n * `TreeView.Item`s under this one. Render them whenever you have them,\n * open or not: the tree hides them while it's closed, and a `checkbox` tree\n * needs them to know what a check reaches.\n */\n children?: React.ReactNode;\n /** Shows the item as a parent before its children are known, such as a folder that loads when it opens. */\n hasChildren?: boolean;\n /**\n * Its children are on their way. While it's open, its group ends in a row\n * that says so, and the tree's live region says it's loading, then that\n * it's loaded once this goes back to `false`. A parent only: pair it with\n * `hasChildren`, or with the children it already has.\n */\n isLoading?: boolean;\n /**\n * Its children didn't load. While it's open, its group ends in a row with\n * this message, and a Retry button when there's an `onRetry`, and the live\n * region reads the message out, so name the item in it (\"Couldn't load\n * src\"), then says it's loaded once this goes with the item still open. A\n * parent only, like `isLoading`. Nothing in it should be a link or a\n * button: the row is what's pressed. `isLoading` wins while both are given.\n */\n loadError?: React.ReactNode;\n /**\n * Called by the Retry button on a failed load's row, and by Enter or Space\n * there. Set `isLoading` while the retry runs, so the live region says it's\n * loading, and reads the message out again if it fails again. The same\n * message passed a second time with no loading between is no change the\n * tree can see.\n */\n onRetry?: () => void;\n /**\n * Reachable with the arrow keys, Home, End and type-ahead, so a screen\n * reader finds it, but never selected, checked, opened or closed. One\n * that's already open stays open.\n */\n disabled?: boolean;\n}\n\n/**\n * The `TreeView` component renders a tree of items you browse and pick from, the way a file explorer works: one tab stop, the arrow keys to move, and Right and Left to open and close.\n *\n * It's the APG Tree View pattern, drawn to look like Bulma's menu. It isn't\n * for site navigation: items aren't links, and a sidebar whose sections open\n * and close is `Menu`'s job. The root owns which items are open, through\n * `expanded`, `defaultExpanded` and `onExpandedChange`.\n *\n * `selectionMode` picks the kind of tree. With `none`, nothing is picked.\n * With `single`, one item is, and `selected` says which. With `checkbox`,\n * each item has a box, a check reaches every enabled item under it, closed\n * branches included, and a parent with some of its items checked is mixed.\n * With `checkbox-independent`, each item has a box that checks that item\n * alone, so a parent means only itself and is never mixed. `selected` is\n * read in a `single` tree only, and `checked` in the two checkbox trees only.\n * Selection never follows focus.\n *\n * Disabled items stay reachable from the keys, so a screen reader finds\n * them. The tree needs a name, from `aria-label` or `aria-labelledby`, and a\n * development build warns when it has neither.\n *\n * @function\n * @param {TreeViewProps} props - Props for the TreeView component.\n * @param {React.Ref<HTMLUListElement>} ref - Forwarded ref to the `<ul>`.\n * @returns {JSX.Element} The rendered tree.\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/treeview/ | APG Tree View Pattern}\n *\n * @example\n * <TreeView aria-label=\"Files\" selectionMode=\"single\" defaultExpanded={['src']}>\n * <TreeView.Item value=\"src\" label=\"src\" icon=\"folder\">\n * <TreeView.Item value=\"src/index.ts\" label=\"index.ts\" icon=\"file\" />\n * </TreeView.Item>\n * <TreeView.Item value=\"package.json\" label=\"package.json\" icon=\"file\" />\n * </TreeView>\n */\nconst TreeViewRoot = forwardRef<HTMLUListElement, TreeViewProps>(\n function TreeView(\n {\n children,\n selectionMode = 'none',\n selected,\n defaultSelected = null,\n onSelectedChange,\n checked,\n defaultChecked = [],\n onCheckedChange,\n expanded,\n defaultExpanded = [],\n onExpandedChange,\n size,\n loadingLabel = 'Loading…',\n retryLabel = 'Retry',\n loadingAnnouncement,\n loadedAnnouncement,\n className,\n ...props\n },\n ref\n ) {\n const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });\n const engine = useTreeView({\n mode: selectionMode,\n selected,\n defaultSelected,\n onSelectedChange,\n checked,\n defaultChecked,\n onCheckedChange,\n expanded,\n defaultExpanded,\n onExpandedChange,\n });\n\n const { treeRef } = engine;\n const setRefs = useCallback(\n (node: HTMLUListElement | null) => {\n treeRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [ref, treeRef]\n );\n\n const named = Boolean(rest['aria-label'] || rest['aria-labelledby']);\n useEffect(() => {\n if (!named) {\n warnOnce(\n 'TreeView:unnamed',\n '[bestax-bulma] <TreeView> has no accessible name. Pass ' +\n 'aria-label or aria-labelledby, so a screen reader can say what ' +\n 'the tree holds.'\n );\n }\n }, [named]);\n\n const rootClass = usePrefixedClassNames('tree-view', {\n [`is-${size}`]:\n !!size && (validTreeViewSizes as readonly string[]).includes(size),\n });\n\n // What each open item's load says, in the order they started saying it.\n const [announcements, setAnnouncements] = useState<LoadAnnouncement[]>([]);\n const announce = useCallback(\n (key: string, announcement: LoadAnnouncement | null) => {\n setAnnouncements(current => {\n const others = current.filter(said => said.key !== key);\n return announcement ? [...others, announcement] : others;\n });\n },\n []\n );\n const describe = useCallback(\n ({ kind, name, message }: LoadAnnouncement) => {\n if (kind === 'error') return message;\n const say =\n kind === 'loading'\n ? (loadingAnnouncement ?? sayLoading)\n : (loadedAnnouncement ?? sayLoaded);\n return say(name);\n },\n [loadingAnnouncement, loadedAnnouncement]\n );\n\n // The props are spread first, so the role and the attributes the tree\n // owns win over anything a caller passes along. The live region sits\n // beside the tree, since a tree holds items and groups only, and it's\n // there from the start, so a screen reader is listening to it before\n // anything is written into it.\n return (\n <TreeViewContext.Provider\n value={{ ...engine, announce, loadingLabel, retryLabel }}\n >\n <BranchContext.Provider value={TOP}>\n <ul\n {...rest}\n ref={setRefs}\n className={classNames(rootClass, bulmaHelperClasses, className)}\n role=\"tree\"\n aria-multiselectable={engine.multiselectable || undefined}\n >\n {children}\n </ul>\n </BranchContext.Provider>\n <StatusRegion items={announcements} describe={describe} />\n </TreeViewContext.Provider>\n );\n }\n);\n\n/**\n * One item in the tree: a row with its chevron, its box, its icon and its label, and, while it's open, a group of the items under it.\n *\n * @function\n * @param {TreeViewItemProps} props - Props for TreeView.Item.\n * @param {React.Ref<HTMLLIElement>} ref - Forwarded ref to the `<li>`.\n * @returns {JSX.Element | null} The rendered item, or nothing under a closed one.\n */\nexport const TreeViewItem = forwardRef<HTMLLIElement, TreeViewItemProps>(\n function TreeViewItem(\n {\n value,\n label,\n icon,\n children,\n hasChildren = false,\n isLoading = false,\n loadError,\n onRetry,\n disabled = false,\n className,\n onClick,\n onKeyDown,\n onFocus,\n onBlur,\n ...props\n },\n ref\n ) {\n const tree = useContext(TreeViewContext);\n const branch = useContext(BranchContext);\n // Also the item's key in the live region.\n const labelId = useId();\n const hasItems = React.Children.toArray(children).length > 0;\n const isParent = hasItems || hasChildren;\n const open = isParent && !!tree?.isOpen(value);\n const parent = branch.path[branch.path.length - 1] ?? null;\n\n // The row at the end of its group, while it's open and on the page.\n const shown = open && !branch.hidden;\n const status = !shown\n ? null\n : isLoading\n ? 'loading'\n : isGiven(loadError)\n ? 'error'\n : null;\n const labelRef = useRef<HTMLSpanElement | null>(null);\n const statusLabelRef = useRef<HTMLSpanElement | null>(null);\n\n // What the live region says follows the row: it's loading, or it failed,\n // while the row says so, and it's loaded once the row goes with the item\n // still open, whichever row it was, until the item closes or loads again.\n // A closed item says nothing, loading or not.\n const phase = shown ? (status ?? 'open') : 'closed';\n const lastPhaseRef = useRef(phase);\n const announce = tree?.announce;\n useEffect(() => {\n const was = lastPhaseRef.current;\n lastPhaseRef.current = phase;\n const kind =\n phase === 'loading' || phase === 'error'\n ? phase\n : phase === 'open' && (was === 'loading' || was === 'error')\n ? 'loaded'\n : null;\n if (!kind) return undefined;\n // Only an item inside a tree can be open.\n announce!(labelId, {\n key: labelId,\n id: `${labelId}:${kind}`,\n kind,\n name: spokenText(labelRef.current!),\n message: kind === 'error' ? spokenText(statusLabelRef.current!) : '',\n });\n return () => announce!(labelId, null);\n }, [phase, announce, labelId]);\n\n const itemClass = usePrefixedClassNames('tree-view-item');\n const groupClass = usePrefixedClassNames('tree-view-group');\n const toggleClass = usePrefixedClassNames('tree-view-toggle');\n const checkClass = usePrefixedClassNames('tree-view-check');\n const iconClass = usePrefixedClassNames('tree-view-icon');\n const labelClass = usePrefixedClassNames('tree-view-label');\n\n const register = tree?.register;\n useClientLayoutEffect(() => {\n if (!register) {\n warnOnce(\n 'TreeView.Item:outside',\n '[bestax-bulma] <TreeView.Item> is outside a <TreeView>, so it ' +\n 'renders nothing. Put it inside one.'\n );\n return undefined;\n }\n return register(value, { parent, disabled, isParent });\n }, [register, value, parent, disabled, isParent]);\n\n const setElement = tree?.setElement;\n const setRefs = useCallback(\n (node: HTMLLIElement | null) => {\n // Only an item inside a tree renders an element to hand over.\n setElement!(value, node);\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [setElement, value, ref]\n );\n const rowRef = useRef<HTMLDivElement | null>(null);\n const toggleRef = useRef<HTMLSpanElement | null>(null);\n\n const childBranch = useMemo(\n () => ({\n path: [...branch.path, value],\n hidden: branch.hidden || !open,\n }),\n [branch, value, open]\n );\n\n const { selected, checked } =\n tree?.stateOf(value, branch.path, disabled) ?? {};\n const rowClass = usePrefixedClassNames('tree-view-row', {\n 'is-selected': selected,\n 'is-disabled': disabled,\n });\n\n if (!tree) return null;\n\n // While it's open the children render in its group. In a `checkbox` tree\n // they render while it's closed too, drawing nothing, so a check knows\n // what's under it.\n const items = (open || tree.rendersClosed) && (\n <BranchContext.Provider value={childBranch}>\n {children}\n </BranchContext.Provider>\n );\n if (branch.hidden) return <>{items}</>;\n\n const info = { value, parent, disabled, isParent, open };\n // A position the caller gives wins, for a set the page holds only part of.\n const position = tree.positionOf(value);\n\n return (\n <li\n {...props}\n ref={setRefs}\n className={classNames(itemClass, className)}\n role=\"treeitem\"\n aria-labelledby={labelId}\n aria-level={branch.path.length + 1}\n aria-posinset={props['aria-posinset'] ?? position?.posinset}\n aria-setsize={props['aria-setsize'] ?? position?.setsize}\n aria-expanded={isParent ? open : undefined}\n aria-disabled={disabled || undefined}\n aria-selected={selected}\n aria-checked={checked}\n tabIndex={tree.tabStop === value ? 0 : -1}\n onKeyDown={event => {\n onKeyDown?.(event);\n tree.onKeyDown(event, info);\n }}\n onFocus={event => {\n onFocus?.(event);\n if (event.target === event.currentTarget) {\n tree.onFocus(value, event.currentTarget);\n }\n }}\n onBlur={event => {\n onBlur?.(event);\n if (event.target === event.currentTarget) tree.onBlur();\n }}\n onClick={event => {\n onClick?.(event);\n // A click in its row is its own, and so is one on the item itself,\n // as a test's click on the treeitem is. One in its group belongs\n // to the item inside it, or to nothing. The chevron's box is on\n // every row, but it's a chevron only on a parent: on a leaf it's\n // more of the row.\n const target = event.target as Node;\n if (\n target === event.currentTarget ||\n rowRef.current!.contains(target)\n ) {\n tree.onClick(\n event.currentTarget,\n info,\n isParent && toggleRef.current!.contains(target)\n );\n }\n }}\n >\n <div className={rowClass} ref={rowRef}>\n <span className={toggleClass} aria-hidden=\"true\" ref={toggleRef} />\n {checked !== undefined && (\n <span\n className={checkClass}\n aria-hidden=\"true\"\n onClick={event => {\n // A click on the box's label is followed by one on its\n // input, and both reach the item. The label's is cancelled,\n // so the item toggles once.\n if (!(event.target instanceof HTMLInputElement)) {\n event.preventDefault();\n }\n }}\n >\n <Checkbox\n tabIndex={-1}\n checked={checked === true}\n indeterminate={checked === 'mixed'}\n disabled={disabled}\n onChange={ignoreChange}\n />\n </span>\n )}\n {isGiven(icon) && (\n <span className={iconClass} aria-hidden=\"true\">\n {typeof icon === 'string' ? <Icon name={icon} /> : icon}\n </span>\n )}\n <span className={labelClass} id={labelId} ref={labelRef}>\n {label}\n </span>\n </div>\n {open && (hasItems || status) ? (\n <ul className={groupClass} role=\"group\">\n {items}\n {status && (\n <StatusRow\n kind={status}\n parent={value}\n level={branch.path.length + 2}\n message={loadError}\n onRetry={onRetry}\n labelRef={statusLabelRef}\n />\n )}\n </ul>\n ) : (\n items\n )}\n </li>\n );\n }\n);\n\nTreeViewItem.displayName = 'TreeView.Item';\n\n/** Props for the row at the end of a loading item's group, or a failed load's. */\ninterface StatusRowProps {\n /** `loading`, or `error` for a load that failed. */\n kind: 'loading' | 'error';\n /** The value of the item it's in. */\n parent: string;\n /** Its `aria-level`, one under the item it's in. */\n level: number;\n /** A failed load's message. */\n message: React.ReactNode;\n /** Retries a failed load. */\n onRetry?: () => void;\n /** For its label, which the item reads a failed load's message off. */\n labelRef: React.Ref<HTMLSpanElement>;\n}\n\n/**\n * The row at the end of a loading item's group, or of one whose load failed.\n * It's a `treeitem` the keys reach, the way they reach a disabled item, so a\n * screen reader finds it. It has no value and no record, so it's never\n * selected or checked, and a check never counts it. A failed load's row with\n * `onRetry` retries with Enter, Space or a click, and any other is disabled.\n * The Retry button is drawn, hidden from assistive tech and out of the tab\n * order, the way an item's box is: the row is what's pressed, and its name\n * says so. Rendered in one place, a failed load's row that starts loading\n * again is the same element, so focus stays on it.\n */\nfunction StatusRow({\n kind,\n parent,\n level,\n message,\n onRetry,\n labelRef,\n}: StatusRowProps) {\n // Only an item inside a tree renders a group.\n const tree = useContext(TreeViewContext)!;\n // Also its key in the registry and for the tab stop, where an item has its value.\n const labelId = useId();\n const retryId = useId();\n const retry = kind === 'error' ? onRetry : undefined;\n\n const itemClass = usePrefixedClassNames('tree-view-item');\n const rowClass = usePrefixedClassNames('tree-view-row', {\n 'is-disabled': !retry,\n });\n const toggleClass = usePrefixedClassNames('tree-view-toggle');\n const labelClass = usePrefixedClassNames('tree-view-label');\n const loaderClass = usePrefixedClassNames('loader');\n const retryClass = usePrefixedClassNames('button', { 'is-small': true });\n\n const { setElement } = tree;\n const setRef = useCallback(\n (node: HTMLLIElement | null) => setElement(labelId, node),\n [setElement, labelId]\n );\n const info = {\n value: labelId,\n parent,\n disabled: !retry,\n isParent: false,\n open: false,\n retry,\n };\n const position = tree.positionOf(labelId);\n\n return (\n <li\n ref={setRef}\n className={itemClass}\n role=\"treeitem\"\n aria-labelledby={retry ? `${labelId} ${retryId}` : labelId}\n aria-level={level}\n aria-posinset={position?.posinset}\n aria-setsize={position?.setsize}\n aria-disabled={!retry || undefined}\n tabIndex={tree.tabStop === labelId ? 0 : -1}\n onKeyDown={event => tree.onKeyDown(event, info)}\n onFocus={event => {\n // Focus in something the message holds isn't the row's.\n if (event.target === event.currentTarget) {\n tree.onFocus(labelId, event.currentTarget);\n }\n }}\n onBlur={event => {\n if (event.target === event.currentTarget) tree.onBlur();\n }}\n onClick={event => tree.onClick(event.currentTarget, info, false)}\n >\n <div className={rowClass}>\n <span className={toggleClass} aria-hidden=\"true\">\n {kind === 'loading' && <span className={loaderClass} />}\n </span>\n <span className={labelClass} id={labelId} ref={labelRef}>\n {kind === 'loading' ? tree.loadingLabel : message}\n </span>\n {retry && (\n <span className={retryClass} id={retryId} aria-hidden=\"true\">\n {tree.retryLabel}\n </span>\n )}\n </div>\n </li>\n );\n}\n\nexport const TreeView = withSubComponents(\n TreeViewRoot,\n { Item: TreeViewItem },\n 'TreeView'\n);\n\nexport default TreeView;\n"],"names":["isGiven","_jsxs","_jsx","_Fragment"],"mappings":";;;;;;;;;;;;;;AA8BA,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAU;AAuBhE;AACA,MAAM,eAAe,GAAG,aAAa,CAA0B,IAAI,CAAC;AAEpE,MAAM,UAAU,GAAG,CAAC,IAAY,KAAK,CAAA,QAAA,EAAW,IAAI,CAAA,CAAE;AACtD,MAAM,SAAS,GAAG,CAAC,IAAY,KAAK,CAAA,EAAG,IAAI,CAAA,OAAA,CAAS;AAQpD,MAAM,GAAG,GAAW,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;AAC/C,MAAM,aAAa,GAAG,aAAa,CAAS,GAAG,CAAC;AAEhD;AACA,MAAM,YAAY,GAAG,MAAK,EAAE,CAAC;AAE7B;AACA,MAAMA,SAAO,GAAG,CAAC,IAAqB,KACpC,IAAI,KAAK,SAAS;AAClB,IAAA,IAAI,KAAK,IAAI;IACb,OAAO,IAAI,KAAK,SAAS;IACzB,IAAI,KAAK,EAAE;AA+Jb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;AACH,MAAM,YAAY,GAAG,UAAU,CAC7B,SAAS,QAAQ,CACf,EACE,QAAQ,EACR,aAAa,GAAG,MAAM,EACtB,QAAQ,EACR,eAAe,GAAG,IAAI,EACtB,gBAAgB,EAChB,OAAO,EACP,cAAc,GAAG,EAAE,EACnB,eAAe,EACf,QAAQ,EACR,eAAe,GAAG,EAAE,EACpB,gBAAgB,EAChB,IAAI,EACJ,YAAY,GAAG,UAAU,EACzB,UAAU,GAAG,OAAO,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,SAAS,EACT,GAAG,KAAK,EACT,EACD,GAAG,EAAA;AAEH,IAAA,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;IAClE,MAAM,MAAM,GAAG,WAAW,CAAC;AACzB,QAAA,IAAI,EAAE,aAAa;QACnB,QAAQ;QACR,eAAe;QACf,gBAAgB;QAChB,OAAO;QACP,cAAc;QACd,eAAe;QACf,QAAQ;QACR,eAAe;QACf,gBAAgB;AACjB,KAAA,CAAC;AAEF,IAAA,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM;AAC1B,IAAA,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,IAA6B,KAAI;AAChC,QAAA,OAAO,CAAC,OAAO,GAAG,IAAI;QACtB,IAAI,OAAO,GAAG,KAAK,UAAU;YAAE,GAAG,CAAC,IAAI,CAAC;AACnC,aAAA,IAAI,GAAG;AAAE,YAAA,GAAG,CAAC,OAAO,GAAG,IAAI;AAClC,IAAA,CAAC,EACD,CAAC,GAAG,EAAE,OAAO,CAAC,CACf;AAED,IAAA,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACpE,SAAS,CAAC,MAAK;QACb,IAAI,CAAC,KAAK,EAAE;YACV,QAAQ,CACN,kBAAkB,EAClB,yDAAyD;gBACvD,iEAAiE;AACjE,gBAAA,iBAAiB,CACpB;QACH;AACF,IAAA,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AAEX,IAAA,MAAM,SAAS,GAAG,qBAAqB,CAAC,WAAW,EAAE;AACnD,QAAA,CAAC,CAAA,GAAA,EAAM,IAAI,CAAA,CAAE,GACX,CAAC,CAAC,IAAI,IAAK,kBAAwC,CAAC,QAAQ,CAAC,IAAI,CAAC;AACrE,KAAA,CAAC;;IAGF,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAqB,EAAE,CAAC;IAC1E,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,GAAW,EAAE,YAAqC,KAAI;QACrD,gBAAgB,CAAC,OAAO,IAAG;AACzB,YAAA,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC;AACvD,YAAA,OAAO,YAAY,GAAG,CAAC,GAAG,MAAM,EAAE,YAAY,CAAC,GAAG,MAAM;AAC1D,QAAA,CAAC,CAAC;IACJ,CAAC,EACD,EAAE,CACH;AACD,IAAA,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAoB,KAAI;QAC5C,IAAI,IAAI,KAAK,OAAO;AAAE,YAAA,OAAO,OAAO;AACpC,QAAA,MAAM,GAAG,GACP,IAAI,KAAK;AACP,eAAG,mBAAmB,IAAI,UAAU;AACpC,eAAG,kBAAkB,IAAI,SAAS,CAAC;AACvC,QAAA,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,IAAA,CAAC,EACD,CAAC,mBAAmB,EAAE,kBAAkB,CAAC,CAC1C;;;;;;AAOD,IAAA,QACEC,IAAA,CAAC,eAAe,CAAC,QAAQ,EAAA,EACvB,KAAK,EAAE,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,EAAA,QAAA,EAAA,CAExDC,GAAA,CAAC,aAAa,CAAC,QAAQ,IAAC,KAAK,EAAE,GAAG,EAAA,QAAA,EAChCA,eACM,IAAI,EACR,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,kBAAkB,EAAE,SAAS,CAAC,EAC/D,IAAI,EAAC,MAAM,EAAA,sBAAA,EACW,MAAM,CAAC,eAAe,IAAI,SAAS,EAAA,QAAA,EAExD,QAAQ,GACN,EAAA,CACkB,EACzBA,GAAA,CAAC,YAAY,IAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAA,CAAI,CAAA,EAAA,CACjC;AAE/B,CAAC,CACF;AAED;;;;;;;AAOG;MACU,YAAY,GAAG,UAAU,CACpC,SAAS,YAAY,CACnB,EACE,KAAK,EACL,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,WAAW,GAAG,KAAK,EACnB,SAAS,GAAG,KAAK,EACjB,SAAS,EACT,OAAO,EACP,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,OAAO,EACP,SAAS,EACT,OAAO,EACP,MAAM,EACN,GAAG,KAAK,EACT,EACD,GAAG,EAAA;AAEH,IAAA,MAAM,IAAI,GAAG,UAAU,CAAC,eAAe,CAAC;AACxC,IAAA,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC;;AAExC,IAAA,MAAM,OAAO,GAAG,KAAK,EAAE;AACvB,IAAA,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC;AAC5D,IAAA,MAAM,QAAQ,GAAG,QAAQ,IAAI,WAAW;AACxC,IAAA,MAAM,IAAI,GAAG,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC;AAC9C,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI;;IAG1D,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM;IACpC,MAAM,MAAM,GAAG,CAAC;AACd,UAAE;AACF,UAAE;AACA,cAAE;AACF,cAAEF,SAAO,CAAC,SAAS;AACjB,kBAAE;kBACA,IAAI;AACZ,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAyB,IAAI,CAAC;AACrD,IAAA,MAAM,cAAc,GAAG,MAAM,CAAyB,IAAI,CAAC;;;;;AAM3D,IAAA,MAAM,KAAK,GAAG,KAAK,IAAI,MAAM,IAAI,MAAM,IAAI,QAAQ;AACnD,IAAA,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC;AAClC,IAAA,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ;IAC/B,SAAS,CAAC,MAAK;AACb,QAAA,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO;AAChC,QAAA,YAAY,CAAC,OAAO,GAAG,KAAK;QAC5B,MAAM,IAAI,GACR,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK;AAC/B,cAAE;AACF,cAAE,KAAK,KAAK,MAAM,KAAK,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,OAAO;AACzD,kBAAE;kBACA,IAAI;AACZ,QAAA,IAAI,CAAC,IAAI;AAAE,YAAA,OAAO,SAAS;;QAE3B,QAAS,CAAC,OAAO,EAAE;AACjB,YAAA,GAAG,EAAE,OAAO;AACZ,YAAA,EAAE,EAAE,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE;YACxB,IAAI;AACJ,YAAA,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,OAAQ,CAAC;AACnC,YAAA,OAAO,EAAE,IAAI,KAAK,OAAO,GAAG,UAAU,CAAC,cAAc,CAAC,OAAQ,CAAC,GAAG,EAAE;AACrE,SAAA,CAAC;QACF,OAAO,MAAM,QAAS,CAAC,OAAO,EAAE,IAAI,CAAC;IACvC,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAE9B,IAAA,MAAM,SAAS,GAAG,qBAAqB,CAAC,gBAAgB,CAAC;AACzD,IAAA,MAAM,UAAU,GAAG,qBAAqB,CAAC,iBAAiB,CAAC;AAC3D,IAAA,MAAM,WAAW,GAAG,qBAAqB,CAAC,kBAAkB,CAAC;AAC7D,IAAA,MAAM,UAAU,GAAG,qBAAqB,CAAC,iBAAiB,CAAC;AAC3D,IAAA,MAAM,SAAS,GAAG,qBAAqB,CAAC,gBAAgB,CAAC;AACzD,IAAA,MAAM,UAAU,GAAG,qBAAqB,CAAC,iBAAiB,CAAC;AAE3D,IAAA,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ;IAC/B,qBAAqB,CAAC,MAAK;QACzB,IAAI,CAAC,QAAQ,EAAE;YACb,QAAQ,CACN,uBAAuB,EACvB,gEAAgE;AAC9D,gBAAA,qCAAqC,CACxC;AACD,YAAA,OAAO,SAAS;QAClB;AACA,QAAA,OAAO,QAAQ,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AACxD,IAAA,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAEjD,IAAA,MAAM,UAAU,GAAG,IAAI,EAAE,UAAU;AACnC,IAAA,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,IAA0B,KAAI;;AAE7B,QAAA,UAAW,CAAC,KAAK,EAAE,IAAI,CAAC;QACxB,IAAI,OAAO,GAAG,KAAK,UAAU;YAAE,GAAG,CAAC,IAAI,CAAC;AACnC,aAAA,IAAI,GAAG;AAAE,YAAA,GAAG,CAAC,OAAO,GAAG,IAAI;IAClC,CAAC,EACD,CAAC,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,CACzB;AACD,IAAA,MAAM,MAAM,GAAG,MAAM,CAAwB,IAAI,CAAC;AAClD,IAAA,MAAM,SAAS,GAAG,MAAM,CAAyB,IAAI,CAAC;AAEtD,IAAA,MAAM,WAAW,GAAG,OAAO,CACzB,OAAO;QACL,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;AAC7B,QAAA,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI;KAC/B,CAAC,EACF,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CACtB;IAED,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GACzB,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE;AACnD,IAAA,MAAM,QAAQ,GAAG,qBAAqB,CAAC,eAAe,EAAE;AACtD,QAAA,aAAa,EAAE,QAAQ;AACvB,QAAA,aAAa,EAAE,QAAQ;AACxB,KAAA,CAAC;AAEF,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,IAAI;;;;IAKtB,MAAM,KAAK,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,MACvCE,IAAC,aAAa,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,WAAW,EAAA,QAAA,EACvC,QAAQ,EAAA,CACc,CAC1B;IACD,IAAI,MAAM,CAAC,MAAM;QAAE,OAAOA,GAAA,CAAAC,QAAA,EAAA,EAAA,QAAA,EAAG,KAAK,EAAA,CAAI;AAEtC,IAAA,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;;IAExD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;AAEvC,IAAA,QACEF,IAAA,CAAA,IAAA,EAAA,EAAA,GACM,KAAK,EACT,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,EAC3C,IAAI,EAAC,UAAU,EAAA,iBAAA,EACE,OAAO,EAAA,YAAA,EACZ,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAA,eAAA,EACnB,KAAK,CAAC,eAAe,CAAC,IAAI,QAAQ,EAAE,QAAQ,EAAA,cAAA,EAC7C,KAAK,CAAC,cAAc,CAAC,IAAI,QAAQ,EAAE,OAAO,EAAA,eAAA,EACzC,QAAQ,GAAG,IAAI,GAAG,SAAS,mBAC3B,QAAQ,IAAI,SAAS,EAAA,eAAA,EACrB,QAAQ,kBACT,OAAO,EACrB,QAAQ,EAAE,IAAI,CAAC,OAAO,KAAK,KAAK,GAAG,CAAC,GAAG,EAAE,EACzC,SAAS,EAAE,KAAK,IAAG;AACjB,YAAA,SAAS,GAAG,KAAK,CAAC;AAClB,YAAA,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC;AAC7B,QAAA,CAAC,EACD,OAAO,EAAE,KAAK,IAAG;AACf,YAAA,OAAO,GAAG,KAAK,CAAC;YAChB,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa,EAAE;gBACxC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC;YAC1C;AACF,QAAA,CAAC,EACD,MAAM,EAAE,KAAK,IAAG;AACd,YAAA,MAAM,GAAG,KAAK,CAAC;AACf,YAAA,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa;gBAAE,IAAI,CAAC,MAAM,EAAE;AACzD,QAAA,CAAC,EACD,OAAO,EAAE,KAAK,IAAG;AACf,YAAA,OAAO,GAAG,KAAK,CAAC;;;;;;AAMhB,YAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAc;AACnC,YAAA,IACE,MAAM,KAAK,KAAK,CAAC,aAAa;gBAC9B,MAAM,CAAC,OAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAChC;gBACA,IAAI,CAAC,OAAO,CACV,KAAK,CAAC,aAAa,EACnB,IAAI,EACJ,QAAQ,IAAI,SAAS,CAAC,OAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAChD;YACH;AACF,QAAA,CAAC,aAEDA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAA,QAAA,EAAA,CACnCC,cAAM,SAAS,EAAE,WAAW,EAAA,aAAA,EAAc,MAAM,EAAC,GAAG,EAAE,SAAS,EAAA,CAAI,EAClE,OAAO,KAAK,SAAS,KACpBA,GAAA,CAAA,MAAA,EAAA,EACE,SAAS,EAAE,UAAU,iBACT,MAAM,EAClB,OAAO,EAAE,KAAK,IAAG;;;;4BAIf,IAAI,EAAE,KAAK,CAAC,MAAM,YAAY,gBAAgB,CAAC,EAAE;gCAC/C,KAAK,CAAC,cAAc,EAAE;4BACxB;AACF,wBAAA,CAAC,EAAA,QAAA,EAEDA,GAAA,CAAC,QAAQ,EAAA,EACP,QAAQ,EAAE,EAAE,EACZ,OAAO,EAAE,OAAO,KAAK,IAAI,EACzB,aAAa,EAAE,OAAO,KAAK,OAAO,EAClC,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,YAAY,EAAA,CACtB,GACG,CACR,EACAF,SAAO,CAAC,IAAI,CAAC,KACZE,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAE,SAAS,EAAA,aAAA,EAAc,MAAM,EAAA,QAAA,EAC3C,OAAO,IAAI,KAAK,QAAQ,GAAGA,GAAA,CAAC,IAAI,EAAA,EAAC,IAAI,EAAE,IAAI,GAAI,GAAG,IAAI,GAClD,CACR,EACDA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAA,QAAA,EACpD,KAAK,EAAA,CACD,CAAA,EAAA,CACH,EACL,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAC3BD,IAAA,CAAA,IAAA,EAAA,EAAI,SAAS,EAAE,UAAU,EAAE,IAAI,EAAC,OAAO,aACpC,KAAK,EACL,MAAM,KACLC,GAAA,CAAC,SAAS,EAAA,EACR,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,KAAK,EACb,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAC7B,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,EAAA,CACxB,CACH,CAAA,EAAA,CACE,KAEL,KAAK,CACN,CAAA,EAAA,CACE;AAET,CAAC;AAGH,YAAY,CAAC,WAAW,GAAG,eAAe;AAkB1C;;;;;;;;;;AAUG;AACH,SAAS,SAAS,CAAC,EACjB,IAAI,EACJ,MAAM,EACN,KAAK,EACL,OAAO,EACP,OAAO,EACP,QAAQ,GACO,EAAA;;AAEf,IAAA,MAAM,IAAI,GAAG,UAAU,CAAC,eAAe,CAAE;;AAEzC,IAAA,MAAM,OAAO,GAAG,KAAK,EAAE;AACvB,IAAA,MAAM,OAAO,GAAG,KAAK,EAAE;AACvB,IAAA,MAAM,KAAK,GAAG,IAAI,KAAK,OAAO,GAAG,OAAO,GAAG,SAAS;AAEpD,IAAA,MAAM,SAAS,GAAG,qBAAqB,CAAC,gBAAgB,CAAC;AACzD,IAAA,MAAM,QAAQ,GAAG,qBAAqB,CAAC,eAAe,EAAE;QACtD,aAAa,EAAE,CAAC,KAAK;AACtB,KAAA,CAAC;AACF,IAAA,MAAM,WAAW,GAAG,qBAAqB,CAAC,kBAAkB,CAAC;AAC7D,IAAA,MAAM,UAAU,GAAG,qBAAqB,CAAC,iBAAiB,CAAC;AAC3D,IAAA,MAAM,WAAW,GAAG,qBAAqB,CAAC,QAAQ,CAAC;AACnD,IAAA,MAAM,UAAU,GAAG,qBAAqB,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAExE,IAAA,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI;IAC3B,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,IAA0B,KAAK,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,EACzD,CAAC,UAAU,EAAE,OAAO,CAAC,CACtB;AACD,IAAA,MAAM,IAAI,GAAG;AACX,QAAA,KAAK,EAAE,OAAO;QACd,MAAM;QACN,QAAQ,EAAE,CAAC,KAAK;AAChB,QAAA,QAAQ,EAAE,KAAK;AACf,QAAA,IAAI,EAAE,KAAK;QACX,KAAK;KACN;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;AAEzC,IAAA,QACEA,GAAA,CAAA,IAAA,EAAA,EACE,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,SAAS,EACpB,IAAI,EAAC,UAAU,EAAA,iBAAA,EACE,KAAK,GAAG,CAAA,EAAG,OAAO,IAAI,OAAO,CAAA,CAAE,GAAG,OAAO,EAAA,YAAA,EAC9C,KAAK,EAAA,eAAA,EACF,QAAQ,EAAE,QAAQ,kBACnB,QAAQ,EAAE,OAAO,EAAA,eAAA,EAChB,CAAC,KAAK,IAAI,SAAS,EAClC,QAAQ,EAAE,IAAI,CAAC,OAAO,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,EAC3C,SAAS,EAAE,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,EAC/C,OAAO,EAAE,KAAK,IAAG;;YAEf,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa,EAAE;gBACxC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC;YAC5C;AACF,QAAA,CAAC,EACD,MAAM,EAAE,KAAK,IAAG;AACd,YAAA,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa;gBAAE,IAAI,CAAC,MAAM,EAAE;QACzD,CAAC,EACD,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,CAAC,YAEhED,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,QAAQ,EAAA,QAAA,EAAA,CACtBC,cAAM,SAAS,EAAE,WAAW,EAAA,aAAA,EAAc,MAAM,YAC7C,IAAI,KAAK,SAAS,IAAIA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAE,WAAW,GAAI,EAAA,CAClD,EACPA,cAAM,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,YACpD,IAAI,KAAK,SAAS,GAAG,IAAI,CAAC,YAAY,GAAG,OAAO,EAAA,CAC5C,EACN,KAAK,KACJA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,iBAAc,MAAM,EAAA,QAAA,EACzD,IAAI,CAAC,UAAU,GACX,CACR,CAAA,EAAA,CACG,EAAA,CACH;AAET;AAEO,MAAM,QAAQ,GAAG,iBAAiB,CACvC,YAAY,EACZ,EAAE,IAAI,EAAE,YAAY,EAAE,EACtB,UAAU;;"}
|
|
@@ -5,7 +5,7 @@ import { prefixedClassNames } from '../helpers/classNames.js';
|
|
|
5
5
|
import { useClassPrefix } from '../helpers/Config.js';
|
|
6
6
|
import { warnOnce, isDev } from '../helpers/devWarnings.js';
|
|
7
7
|
import { useLocale } from '../helpers/LocaleProvider.js';
|
|
8
|
-
import { useLocaleMatcher,
|
|
8
|
+
import { useLocaleMatcher, useScopedNumberFormat } from '../helpers/localeFormat.js';
|
|
9
9
|
import { useClientLayoutEffect } from '../helpers/useClientLayoutEffect.js';
|
|
10
10
|
import { useLatestRef } from '../helpers/useLatestRef.js';
|
|
11
11
|
|
|
@@ -134,7 +134,7 @@ function useDataTable(options) {
|
|
|
134
134
|
const prefix = useClassPrefix();
|
|
135
135
|
const { locale } = useLocale();
|
|
136
136
|
const matchText = useLocaleMatcher();
|
|
137
|
-
const formatNumber =
|
|
137
|
+
const formatNumber = useScopedNumberFormat();
|
|
138
138
|
const collator = useMemo(() => new Intl.Collator(locale, { numeric: true }), [locale]);
|
|
139
139
|
const pageSize = pageSizeProp !== undefined &&
|
|
140
140
|
Number.isFinite(pageSizeProp) &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDataTable.js","sources":["../../../src/components/useDataTable.ts"],"sourcesContent":["import React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { prefixedClassNames } from '../helpers/classNames';\nimport { useClassPrefix } from '../helpers/Config';\nimport { isDev, warnOnce } from '../helpers/devWarnings';\nimport { useLocale } from '../helpers/LocaleProvider';\nimport { useLocaleMatcher, useNumberFormat } from '../helpers/localeFormat';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport { useLatestRef } from '../helpers/useLatestRef';\nimport type { TableAlignment } from '../elements/tableAlignment';\n\n/**\n * Carries a row type and adds nothing, so `DataTableColumnMeta` can take the\n * row type for the fields an add-on merges in while it has none of its own.\n */\ntype CarriesRow<TRow> = { [K in never]?: TRow };\n\n/**\n * Options of its own an add-on gives a column, read from the column's\n * `meta`. Empty in bestax: an add-on, such as a spreadsheet exporter, adds\n * its fields by declaration merging, and every column then takes them. Every\n * declaration of it names the row type the same way, `TRow`.\n *\n * @example\n * declare module '@allxsmith/bestax-bulma' {\n * interface DataTableColumnMeta<TRow> {\n * exportValue?: (row: TRow) => string | number;\n * }\n * }\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- empty so an add-on can merge into it\nexport interface DataTableColumnMeta<TRow = unknown> extends CarriesRow<TRow> {}\n\n/** What a column's `cell` is given beside the row. */\nexport interface DataTableCellContext {\n /** The column's raw value for the row, from its `accessor`. */\n value: unknown;\n /** The column's text for the row, from its `format`. */\n text: string;\n /** The row's id, from `getRowId`. */\n rowId: string;\n}\n\n/**\n * One column of a DataTable. A column keeps three things apart: its raw\n * value (`accessor`), which sorting and `filterFn` read; its text\n * (`format`), which the cell shows, the search matches and an export\n * writes; and its rich content (`cell`), which only the screen sees.\n */\nexport interface DataTableColumn<TRow> {\n /**\n * Names the column for good: the sort, the filters and an export refer to\n * it by this id. Unique within the table, and stable across renders.\n */\n id: string;\n /**\n * The column's name, as text: the header, the sort button's name, the\n * row checkboxes' names when it's the row header, and the header an\n * export writes.\n */\n header: string;\n /**\n * The raw value, for sorting and filtering: a key of the row, or a\n * function of it. Left out, it's the row's property named `id`.\n */\n accessor?: keyof TRow | ((row: TRow) => unknown);\n /**\n * The text for the value: what the cell shows when there's no `cell`, what\n * the search matches, and what an export writes. Left out, it's the value\n * as a string, and nothing for `null` or `undefined`. Give one for\n * numbers and dates you want written a certain way.\n */\n format?: (value: unknown, row: TRow) => string;\n /**\n * Rich content for the cell, such as a tag or a link. Only the screen\n * reads it: sorting, the search and an export use the value and its text.\n */\n cell?: (row: TRow, context: DataTableCellContext) => React.ReactNode;\n /**\n * Makes the header a button that sorts by this column: ascending, then\n * descending, then unsorted.\n */\n sortable?: boolean;\n /** Sorts descending on the first press, for a column read from the top, such as a score. */\n sortDescFirst?: boolean;\n /**\n * Compares two rows for an ascending sort, returning a negative number,\n * zero or a positive one. Descending reverses it. Without it, numbers,\n * dates and booleans compare by value, anything else by its text in the\n * `LocaleProvider`'s locale with numbers inside it read as numbers (\"Item\n * 9\" before \"Item 10\"), and an empty value goes last either way.\n */\n sortFn?: (a: TRow, b: TRow) => number;\n /**\n * Whether the column takes part in filtering: the search matches its\n * text, and `filters` can hold a value for it. `false` leaves it out of\n * both, as for a column of actions.\n */\n filterable?: boolean;\n /**\n * Decides whether a row passes this column's value in `filters`. Without\n * it, the column's text has to contain the value's text, compared as the\n * search compares.\n */\n filterFn?: (row: TRow, filterValue: unknown) => boolean;\n /** Aligns the header and the cells (`isAligned` on `Th` and `Td`). */\n align?: TableAlignment;\n /** The column's width, on its header cell: a number is pixels, a string any CSS length. */\n width?: string | number;\n /**\n * Renders this column's cells as row headers (`th scope=\"row\"`), which a\n * screen reader reads out with the other cells of the row. The row's\n * checkbox is named from it. Mark one column, usually the first.\n */\n isRowHeader?: boolean;\n /** Options of an add-on's own, as `DataTableColumnMeta` declares them. */\n meta?: DataTableColumnMeta<TRow>;\n}\n\n/** The direction of a sort, in `aria-sort`'s words. */\nexport type DataTableSortDirection = 'ascending' | 'descending';\n\n/** One column a DataTable sorts by. */\nexport interface DataTableSort {\n /** The column's `id`. */\n id: string;\n /** Which way it sorts. */\n direction: DataTableSortDirection;\n}\n\n/** The values per column `filters` holds, keyed by column `id`. */\nexport type DataTableFilters = Record<string, unknown>;\n\n/**\n * Which of a table's rows to read: `all` of `data`, `filtered` (the ones the\n * search and the filters let through, from every page), the `page` shown,\n * or the `selected` ones the filters let through. Each comes in the order\n * the table shows them.\n */\nexport type DataTableRowScope = 'all' | 'filtered' | 'page' | 'selected';\n\n/** Whether a DataTable has row checkboxes. */\nexport type DataTableSelectionMode = 'none' | 'multiple';\n\n/**\n * The words a DataTable writes. Each is English unless you give your own,\n * and the numbers in the default messages are written in the\n * `LocaleProvider`'s locale.\n */\nexport interface DataTableLabels {\n /**\n * The header checkbox's name. \"Select all rows\", or \"Select all rows on\n * this page\" when there's more than one page, since it then covers the\n * page shown.\n */\n selectAll?: string;\n /** A row checkbox's name, from the row's label (`label => 'Select ' + label`). */\n selectRow?: (rowLabel: string) => string;\n /**\n * Says that headers with buttons sort: hidden at the end of the caption,\n * after a comma, or as a hidden caption of its own. \"column headers with\n * buttons are sortable\".\n */\n sortHint?: string;\n /** The search field's label. \"Search\". */\n search?: string;\n /** Announced after the search or a filter changes (\"12 rows match\"). */\n results?: (count: number) => string;\n /** Announced after the page changes (\"Showing 11 to 20 of 57\"). */\n pageRange?: (first: number, last: number, total: number) => string;\n /** Announced while `loading`, once the search, a filter or the page has changed. \"Loading\". */\n loading?: string;\n /**\n * The pager's name. \"{the table's name} pages\" when the table is named by\n * `aria-label` or a text `caption`, so two tables' pagers have different\n * names, else `Pagination`'s own.\n */\n pagination?: string;\n /** What the table shows with no rows at all. \"No rows to show.\" */\n empty?: string;\n /** What the table shows when the search and filters let no row through. \"No rows match.\" */\n noResults?: string;\n}\n\n/** The words a DataTable writes, with every default filled in. */\nexport interface DataTableResolvedLabels extends Required<\n Omit<DataTableLabels, 'pagination'>\n> {\n /** The pager's name, when one was given. */\n pagination?: string;\n}\n\n/**\n * The options `useDataTable` and `DataTable` share, beside the columns and\n * the data. Each piece of state is yours when you pass its value (and its\n * `on…Change`), or the table's own, starting from its `default…`.\n */\nexport interface DataTableStateOptions<TRow> {\n /**\n * A row's id, unique and stable, which the selection is a list of. Left\n * out, it's the row's `id` property as a string. A development build\n * warns about a missing or repeated id, and a row with none falls back to\n * its index, which doesn't survive the data changing.\n */\n getRowId?: (row: TRow, index: number) => string;\n /**\n * The sort when you hold it: an array of `{ id, direction }`, the first\n * deciding and each next one breaking ties. The headers set one at a time.\n */\n sort?: DataTableSort[];\n /**\n * The sort to start with when the table holds it. Text sorts in the\n * `LocaleProvider`'s locale, or the runtime's own outside one, which can\n * differ between a server and the browser, so put a table rendered on the\n * server sorted inside a `LocaleProvider`.\n */\n defaultSort?: DataTableSort[];\n /** Called with the new sort when a header is pressed. */\n onSortChange?: (sort: DataTableSort[]) => void;\n /**\n * `multiple` adds a checkbox to each row and a \"select all\" checkbox to the header.\n *\n * @defaultValue 'none'\n */\n selectionMode?: DataTableSelectionMode;\n /**\n * The selected rows' ids when you hold them. They stay selected while the\n * search, a filter or the page hides them.\n */\n selected?: string[];\n /** The rows selected to begin with, by id, when the table holds them. */\n defaultSelected?: string[];\n /** Called with every selected id after a checkbox changes. */\n onSelectedChange?: (selected: string[]) => void;\n /** Rows per page. Set, the table pages through `Pagination`; left out, it shows every row. */\n pageSize?: number;\n /**\n * The page shown when you hold it, counting from 1. A page past the end\n * shows the last.\n */\n page?: number;\n /**\n * The page to start on when the table holds it.\n *\n * @defaultValue 1\n */\n defaultPage?: number;\n /**\n * Called with the page chosen in the pager, and with 1 when the search or\n * a filter changes through the table while the page held isn't 1, even\n * when a page past the end shows as the last.\n */\n onPageChange?: (page: number) => void;\n /**\n * The search when you hold it, matched against every filterable column's\n * text: in the `LocaleProvider`'s locale, ignoring case and the accents\n * the language ignores, or a case-insensitive substring outside one.\n */\n search?: string;\n /** The search to start with when the table holds it. */\n defaultSearch?: string;\n /** Called with the search as it changes through the table. */\n onSearchChange?: (search: string) => void;\n /**\n * A value per column, by `id`, when you hold them. A row passes when every\n * column with a value passes it: the column's `filterFn` if it has one,\n * given the value as it is, or else the column's text has to contain the\n * value's text, compared as the search compares. An array is a choice of\n * values, as a multiple-choice filter gives, and passes a row whose text\n * contains any of them. A value of `undefined`, `null`, `''` or an empty\n * array is no filter.\n */\n filters?: DataTableFilters;\n /** The filters to start with when the table holds them. */\n defaultFilters?: DataTableFilters;\n /** Called with every filter value after one changes through the table. */\n onFiltersChange?: (filters: DataTableFilters) => void;\n /**\n * Hands sorting, filtering and paging to a server: the table shows `data`\n * as given, as the current page, and only reports the state as it\n * changes.\n */\n manual?: boolean;\n /**\n * With `manual`, how many rows match in all, which sets the page count and\n * the announced count. Without it, the table counts the rows in `data`,\n * which with a `pageSize` is one page and no pager, and a development\n * build warns.\n */\n rowCount?: number;\n /** The words the table writes, in your app's language. */\n labels?: DataTableLabels;\n}\n\n/** What `useDataTable` takes. */\nexport interface UseDataTableOptions<TRow> extends DataTableStateOptions<TRow> {\n /**\n * The columns, in the order they're shown. Keep the array the same from\n * one render to the next, defined outside the component or in `useMemo`:\n * a new one has every cell's text worked out again.\n */\n columns: DataTableColumn<TRow>[];\n /** The rows, as records of your own. */\n data: TRow[];\n}\n\n/** The table's state, as it stands. */\nexport interface DataTableState {\n /** The sort, the first entry deciding. */\n sort: DataTableSort[];\n /** The selected rows' ids. */\n selected: string[];\n /** The page shown, counting from 1. */\n page: number;\n /** Rows per page, or `undefined` when it doesn't page. */\n pageSize: number | undefined;\n /** The search. */\n search: string;\n /** The filter values, by column id. */\n filters: DataTableFilters;\n}\n\n/** The props `getSortButtonProps` gives a header's `<button>`. */\nexport interface DataTableSortButtonProps {\n type: 'button';\n className: string;\n onClick: () => void;\n}\n\n/** The props `getSearchProps` gives a search `<input>` or bestax `Input`. */\nexport interface DataTableSearchProps {\n type: 'search';\n value: string;\n onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;\n}\n\n/** The props `getHeaderCellProps` gives a column's `Th`. */\nexport interface DataTableHeaderCellProps {\n scope: 'col';\n 'aria-sort'?: DataTableSortDirection;\n isAligned?: TableAlignment;\n width?: string | number;\n}\n\n/** The props `getCellProps` gives a row's `Td`, or its `Th` for the row header. */\nexport interface DataTableCellProps {\n scope?: 'row';\n isAligned?: TableAlignment;\n}\n\n/** The props `getSelectAllProps` and `getSelectRowProps` give a `Checkbox`. */\nexport interface DataTableCheckboxProps {\n 'aria-label': string;\n checked: boolean;\n indeterminate?: boolean;\n disabled?: boolean;\n onChange: () => void;\n}\n\n/** The props `getPaginationProps` gives `Pagination`. */\nexport interface DataTablePaginationProps {\n total: number;\n current: number;\n onPageChange: (page: number) => void;\n}\n\n/** What `toCSV` writes. */\nexport interface DataTableCSVOptions {\n /**\n * Which rows, in the order the table shows them: the ones the search and\n * filters let through, from every page, by default, or `all`, `page` or\n * `selected`.\n *\n * @defaultValue 'filtered'\n */\n rows?: DataTableRowScope;\n /** The ids of the columns to write, in that order. Every column, in the order shown, by default. */\n columns?: string[];\n /**\n * Writes the columns' headers as the first line.\n *\n * @defaultValue true\n */\n header?: boolean;\n /**\n * What separates the fields. A semicolon suits a spreadsheet that reads\n * a comma as the decimal point, as Excel does in much of Europe.\n *\n * @defaultValue ','\n */\n delimiter?: string;\n}\n\n/**\n * A table: what `useDataTable` returns, what `DataTable`'s `toolbar` is\n * given, and what its `table` takes. It reads the rows and the state, changes\n * the state, and hands out props for bestax's own `Th`, `Tr`, `Td`,\n * `Checkbox` and `Pagination`, so markup of your own behaves as DataTable's\n * does.\n */\nexport interface DataTableModel<TRow> {\n /** The columns, in the order they're shown. */\n columns: DataTableColumn<TRow>[];\n /** The state as it stands. */\n state: DataTableState;\n /** Whether rows have checkboxes. */\n selectionMode: DataTableSelectionMode;\n /** Whether a server sorts, filters and pages (`manual`). */\n manual: boolean;\n /** How many rows the search and filters let through, or `rowCount` with `manual`. */\n rowCount: number;\n /** How many pages there are, at least 1. */\n pageCount: number;\n /** The words the table writes, with the defaults filled in. */\n labels: DataTableResolvedLabels;\n /** The rows in `scope` (`filtered` by default), in the order the table shows them. */\n getRows: (scope?: DataTableRowScope) => TRow[];\n /** A row's id. */\n getRowId: (row: TRow) => string;\n /** A column's raw value for a row, or `undefined` for a column it doesn't have. */\n getValue: (row: TRow, columnId: string) => unknown;\n /** A column's text for a row, or `''` for a column it doesn't have. */\n getText: (row: TRow, columnId: string) => string;\n /** What names a row: its row header's text, or its first column's. */\n getRowLabel: (row: TRow) => string;\n /**\n * The rows as CSV, from the columns' text (`format`, not `cell`), with a\n * line break of `\\r\\n` between rows and fields quoted as RFC 4180 asks.\n * A field that starts with `=`, `+`, `-`, `@`, a tab or a carriage return\n * gets a `'` in front, so a spreadsheet shows it as text rather than\n * running it as a formula, unless it's a plain number such as `-12.5`.\n * Excel takes a file as UTF-8 only when it starts with a byte order mark,\n * so put `\\uFEFF` in front of the text when you save it for Excel.\n */\n toCSV: (options?: DataTableCSVOptions) => string;\n /** Whether a row is selected. */\n isSelected: (row: TRow) => boolean;\n /** Sets the sort. */\n setSort: (sort: DataTableSort[]) => void;\n /** Moves a column through its sort, as its header button does. */\n toggleSort: (columnId: string) => void;\n /** Sets the selected ids. */\n setSelected: (selected: string[]) => void;\n /**\n * Selects a row, or clears it, or with no `selected` flips it. Called\n * twice in one handler, the second call builds on the first while the\n * table holds the selection. While you hold it, each call builds on the\n * selection as rendered, so make several changes at once with\n * `setSelected`.\n */\n toggleRowSelected: (row: TRow, selected?: boolean) => void;\n /**\n * Selects every row on the page, or clears them, or with no `selected`\n * does what the header checkbox does. It builds on earlier calls as\n * `toggleRowSelected` does.\n */\n togglePageSelected: (selected?: boolean) => void;\n /** Goes to a page, counting from 1. */\n setPage: (page: number) => void;\n /**\n * Sets the search, and goes back to page 1, calling `onPageChange` with 1\n * unless the page held is 1 already.\n */\n setSearch: (search: string) => void;\n /**\n * Sets one column's filter value, and goes back to page 1. Called twice in\n * one handler, the second call builds on the first while the table holds\n * the filters. While you hold them, each call builds on the filters as\n * rendered, so set several at once with `setFilters`.\n */\n setFilter: (columnId: string, value: unknown) => void;\n /** Sets every filter value, and goes back to page 1, as `setSearch` does. */\n setFilters: (filters: DataTableFilters) => void;\n /** Props for a column's `Th`: its scope, its `aria-sort` while sorted, its alignment and width. */\n getHeaderCellProps: (\n column: DataTableColumn<TRow>\n ) => DataTableHeaderCellProps;\n /** Props for the `<button>` in a sortable column's header. */\n getSortButtonProps: (\n column: DataTableColumn<TRow>\n ) => DataTableSortButtonProps;\n /** Props for a row's `Tr`: Bulma's selected look while it's selected. */\n getRowProps: (row: TRow) => { isSelected: boolean };\n /** Props for a row's cell in a column: its alignment, and `scope=\"row\"` for the row header. */\n getCellProps: (\n row: TRow,\n column: DataTableColumn<TRow>\n ) => DataTableCellProps;\n /** Props for the header's \"select all\" `Checkbox`, which covers the page shown. */\n getSelectAllProps: () => DataTableCheckboxProps;\n /** Props for a row's `Checkbox`, named for the row. */\n getSelectRowProps: (row: TRow) => DataTableCheckboxProps;\n /** Props for `Pagination`: the page count, the page and the handler. */\n getPaginationProps: () => DataTablePaginationProps;\n /** Props for a search field, bound to the search. */\n getSearchProps: () => DataTableSearchProps;\n}\n\n/** A column's raw value for a row. */\nfunction readValue<TRow>(column: DataTableColumn<TRow>, row: TRow): unknown {\n const { accessor } = column;\n if (typeof accessor === 'function') return accessor(row);\n if (row === null || typeof row !== 'object') return undefined;\n return (row as Record<PropertyKey, unknown>)[\n (accessor ?? column.id) as PropertyKey\n ];\n}\n\n/** A column's text for a row. */\nfunction readText<TRow>(column: DataTableColumn<TRow>, row: TRow): string {\n const value = readValue(column, row);\n if (column.format) return column.format(value, row);\n return value === null || value === undefined ? '' : String(value);\n}\n\n/** Whether a value sorts as empty: nothing, no text, or no number or date. */\nfunction isEmptyValue(value: unknown): boolean {\n return (\n value === null ||\n value === undefined ||\n value === '' ||\n (typeof value === 'number' && Number.isNaN(value)) ||\n (value instanceof Date && Number.isNaN(value.getTime()))\n );\n}\n\n/** Compares two values that aren't empty, for an ascending sort. */\nfunction compareValues(a: unknown, b: unknown, collator: Intl.Collator) {\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return Number(a) - Number(b);\n }\n return collator.compare(String(a), String(b));\n}\n\n/** Whether a filter value filters anything. */\nfunction isActiveFilter(value: unknown): boolean {\n return (\n value !== undefined &&\n value !== null &&\n value !== '' &&\n !(Array.isArray(value) && value.length === 0)\n );\n}\n\n/** A field a spreadsheet would read as the start of a formula. */\nconst formulaStart = /^[=+\\-@\\t\\r]/;\n/** A plain number, signed, with any grouping, which no spreadsheet runs. */\nconst plainNumber = /^[+-]?\\d[\\d.,]*$/;\n\n/**\n * One CSV field: a `'` in front of what would start a formula, then quoted\n * when it holds the delimiter, a quote or a line break, its quotes doubled.\n */\nfunction csvField(text: string, delimiter: string): string {\n const safe =\n formulaStart.test(text) && !plainNumber.test(text) ? `'${text}` : text;\n return safe.includes(delimiter) || /[\"\\r\\n]/.test(safe)\n ? `\"${safe.replace(/\"/g, '\"\"')}\"`\n : safe;\n}\n\n/**\n * Whether a search or a filter value is narrowing the rows. Used by\n * DataTable to tell an empty table from one with no matches.\n */\nexport function isFiltering(search: string, filters: DataTableFilters) {\n return search.trim() !== '' || Object.values(filters).some(isActiveFilter);\n}\n\n/** A row's id from its `id` property, or nothing when it has none. */\nfunction idOf(row: unknown): string | undefined {\n if (row === null || typeof row !== 'object') return undefined;\n const id = (row as { id?: unknown }).id;\n return id === undefined || id === null || id === '' ? undefined : String(id);\n}\n\n/**\n * A piece of state that's the caller's when they pass its value, and the\n * table's own otherwise. Setting it calls the change handler either way.\n *\n * It also returns `latest`, what a change should build on. While the table\n * holds the state, that's the value last set, even before React renders it,\n * so two changes in one handler build on each other. While the caller holds\n * it, it's the value as rendered, since only the caller knows what it made\n * of a change.\n */\nfunction useTableState<T>(\n value: T | undefined,\n initial: T,\n onChange: ((next: T) => void) | undefined\n): [T, (next: T) => void, () => T] {\n const [own, setOwn] = useState(initial);\n const held = value !== undefined;\n const current = held ? value : own;\n const rendered = useLatestRef(current);\n // A value set since the last commit, cleared once a commit shows it.\n const pendingRef = useRef<{ value: T } | null>(null);\n useClientLayoutEffect(() => {\n pendingRef.current = null;\n });\n const set = useCallback(\n (next: T) => {\n if (!held) {\n pendingRef.current = { value: next };\n setOwn(next);\n }\n onChange?.(next);\n },\n [held, onChange]\n );\n const latest = useCallback(\n () => (pendingRef.current ? pendingRef.current.value : rendered.current),\n [rendered]\n );\n return [current, set, latest];\n}\n\nconst noSort: DataTableSort[] = [];\nconst noIds: string[] = [];\nconst noFilters: DataTableFilters = {};\n\n/**\n * `useDataTable` holds a table's sort, selection, page, search and filters,\n * works out its rows, and hands out props for bestax's own table parts, so\n * custom markup behaves as `DataTable` does. Pass its result to\n * `<DataTable table={table} />` to render it with DataTable's own markup,\n * with a toolbar or an export button elsewhere on the page.\n *\n * @example\n * const table = useDataTable({ columns, data: users, pageSize: 10 });\n *\n * <DataTable table={table} caption=\"Users\" hasSearch />\n */\nexport function useDataTable<TRow>(\n options: UseDataTableOptions<TRow>\n): DataTableModel<TRow> {\n const {\n columns,\n data,\n getRowId: rowIdOf,\n sort: sortProp,\n defaultSort = noSort,\n onSortChange,\n selectionMode = 'none',\n selected: selectedProp,\n defaultSelected = noIds,\n onSelectedChange,\n pageSize: pageSizeProp,\n page: pageProp,\n defaultPage = 1,\n onPageChange,\n search: searchProp,\n defaultSearch = '',\n onSearchChange,\n filters: filtersProp,\n defaultFilters = noFilters,\n onFiltersChange,\n manual = false,\n rowCount: rowCountProp,\n labels,\n } = options;\n\n const [sort, setSort] = useTableState(sortProp, defaultSort, onSortChange);\n const [selected, setSelected, latestSelected] = useTableState(\n selectedProp,\n defaultSelected,\n onSelectedChange\n );\n const [pageState, setPageState, latestPage] = useTableState(\n pageProp,\n defaultPage,\n onPageChange\n );\n const [search, setSearchState] = useTableState(\n searchProp,\n defaultSearch,\n onSearchChange\n );\n const [filters, setFiltersState, latestFilters] = useTableState(\n filtersProp,\n defaultFilters,\n onFiltersChange\n );\n\n const prefix = useClassPrefix();\n const { locale } = useLocale();\n const matchText = useLocaleMatcher();\n const formatNumber = useNumberFormat();\n const collator = useMemo(\n () => new Intl.Collator(locale, { numeric: true }),\n [locale]\n );\n\n const pageSize =\n pageSizeProp !== undefined &&\n Number.isFinite(pageSizeProp) &&\n pageSizeProp >= 1\n ? Math.floor(pageSizeProp)\n : undefined;\n\n const columnsById = useMemo(() => {\n const byId = new Map<string, DataTableColumn<TRow>>();\n for (const column of columns) {\n if (byId.has(column.id)) {\n warnOnce(\n 'DataTable:duplicate-column',\n `[bestax-bulma] DataTable has two columns with the id \"${column.id}\". ` +\n 'Give each column its own id: the sort, the filters and an export ' +\n 'find a column by it.'\n );\n } else {\n byId.set(column.id, column);\n }\n }\n return byId;\n }, [columns]);\n\n // Each row's id, by its index in `data`.\n const ids = useMemo(() => {\n const out = data.map((row, index) => {\n const id = rowIdOf ? rowIdOf(row, index) : idOf(row);\n if (id === undefined || id === '') {\n warnOnce(\n 'DataTable:missing-row-id',\n '[bestax-bulma] A DataTable row has no id, so it falls back to its ' +\n \"index, which doesn't survive the data changing. Give each row \" +\n 'an `id`, or pass `getRowId`.'\n );\n return String(index);\n }\n return id;\n });\n if (isDev() && new Set(out).size < out.length) {\n warnOnce(\n 'DataTable:duplicate-row-id',\n '[bestax-bulma] Two DataTable rows have the same id, so selecting ' +\n 'one selects both. Make the ids unique, or pass a `getRowId` ' +\n 'that does.'\n );\n }\n return out;\n }, [data, rowIdOf]);\n\n const indexOf = useMemo(() => {\n const map = new Map<TRow, number>();\n data.forEach((row, index) => {\n if (!map.has(row)) map.set(row, index);\n });\n return map;\n }, [data]);\n\n /** A row's id, from its index when the row is one of `data`. */\n const getRowId = useCallback(\n (row: TRow) => {\n const index = indexOf.get(row);\n if (index !== undefined) return ids[index];\n const id = rowIdOf ? rowIdOf(row, -1) : idOf(row);\n return id ?? '';\n },\n [indexOf, ids, rowIdOf]\n );\n\n // Every column's text for every row, worked out once per data and\n // columns, since the search reads them on every keystroke.\n const texts = useMemo(\n () => data.map(row => columns.map(column => readText(column, row))),\n [data, columns]\n );\n\n const sortedIndexes = useMemo(() => {\n const all = data.map((_, index) => index);\n if (manual) return all;\n const keys = sort\n .map(entry => ({\n column: columnsById.get(entry.id),\n descending: entry.direction === 'descending',\n }))\n .filter(\n (key): key is { column: DataTableColumn<TRow>; descending: boolean } =>\n key.column !== undefined\n );\n if (keys.length === 0) return all;\n const values = keys.map(({ column }) =>\n column.sortFn ? null : data.map(row => readValue(column, row))\n );\n return all.sort((x, y) => {\n for (let k = 0; k < keys.length; k++) {\n const { column, descending } = keys[k];\n let result: number;\n if (column.sortFn) {\n result = column.sortFn(data[x], data[y]);\n if (descending) result = -result;\n } else {\n const a = values[k]![x];\n const b = values[k]![y];\n const aEmpty = isEmptyValue(a);\n const bEmpty = isEmptyValue(b);\n if (aEmpty || bEmpty) {\n // Empty values go last whichever way the column sorts.\n result = Number(aEmpty) - Number(bEmpty);\n } else {\n result = compareValues(a, b, collator);\n if (descending) result = -result;\n }\n }\n if (result) return result;\n }\n // Ties keep the order of `data`.\n return x - y;\n });\n }, [data, sort, columnsById, collator, manual]);\n\n const filteredIndexes = useMemo(() => {\n if (manual) return sortedIndexes;\n const query = search.trim();\n const holds = matchText\n ? (text: string, needle: string) => matchText(text, needle)\n : (text: string, needle: string) =>\n text.toLowerCase().includes(needle.toLowerCase());\n const searched = columns\n .map((column, index) => ({ column, index }))\n .filter(({ column }) => column.filterable !== false);\n const filtered = Object.entries(filters)\n .filter(([, value]) => isActiveFilter(value))\n .map(([id, value]) => ({\n column: columnsById.get(id),\n index: columns.findIndex(column => column.id === id),\n value,\n }))\n .filter(\n ({ column }) => column !== undefined && column.filterable !== false\n );\n if (query === '' && filtered.length === 0) return sortedIndexes;\n return sortedIndexes.filter(rowIndex => {\n const row = data[rowIndex];\n const rowTexts = texts[rowIndex];\n for (const { column, index, value } of filtered) {\n // An array is any of its entries, as a multiple-choice filter gives.\n const passes = column!.filterFn\n ? column!.filterFn(row, value)\n : Array.isArray(value)\n ? value.some(entry => holds(rowTexts[index], String(entry)))\n : holds(rowTexts[index], String(value));\n if (!passes) return false;\n }\n return (\n query === '' ||\n searched.some(({ index }) => holds(rowTexts[index], query))\n );\n });\n }, [\n manual,\n sortedIndexes,\n search,\n filters,\n matchText,\n columns,\n columnsById,\n data,\n texts,\n ]);\n\n const knowsCount =\n rowCountProp !== undefined && Number.isFinite(rowCountProp);\n if (manual && pageSize !== undefined && !knowsCount) {\n warnOnce(\n 'DataTable:manual-row-count',\n '[bestax-bulma] A DataTable with `manual` and a `pageSize` has no ' +\n '`rowCount`, so it counts only the rows in `data`, makes one page ' +\n 'of them and shows no pager. Pass `rowCount`, how many rows match ' +\n 'on the server.'\n );\n }\n const rowCount = manual\n ? Math.max(\n Math.floor(knowsCount ? (rowCountProp as number) : data.length),\n 0\n )\n : filteredIndexes.length;\n const pageCount = pageSize ? Math.max(Math.ceil(rowCount / pageSize), 1) : 1;\n const page = Math.min(\n Math.max(Number.isFinite(pageState) ? Math.floor(pageState) : 1, 1),\n pageCount\n );\n\n const pageIndexes = useMemo(() => {\n if (manual || !pageSize) return filteredIndexes;\n return filteredIndexes.slice((page - 1) * pageSize, page * pageSize);\n }, [manual, pageSize, filteredIndexes, page]);\n\n const selectedSet = useMemo(() => new Set(selected), [selected]);\n const selectable = selectionMode === 'multiple';\n\n const rowsOf = useCallback(\n (indexes: number[]) => indexes.map(index => data[index]),\n [data]\n );\n\n const getRows = useCallback(\n (scope: DataTableRowScope = 'filtered') => {\n switch (scope) {\n case 'all':\n return rowsOf(sortedIndexes);\n case 'page':\n return rowsOf(pageIndexes);\n case 'selected':\n return rowsOf(\n filteredIndexes.filter(index => selectedSet.has(ids[index]))\n );\n default:\n return rowsOf(filteredIndexes);\n }\n },\n [rowsOf, sortedIndexes, pageIndexes, filteredIndexes, selectedSet, ids]\n );\n\n const getValue = useCallback(\n (row: TRow, columnId: string) => {\n const column = columnsById.get(columnId);\n return column ? readValue(column, row) : undefined;\n },\n [columnsById]\n );\n\n const getText = useCallback(\n (row: TRow, columnId: string) => {\n const column = columnsById.get(columnId);\n if (!column) return '';\n const index = indexOf.get(row);\n return index !== undefined\n ? texts[index][columns.indexOf(column)]\n : readText(column, row);\n },\n [columnsById, indexOf, columns, texts]\n );\n\n const labelColumn = columns.find(column => column.isRowHeader) ?? columns[0];\n const getRowLabel = useCallback(\n (row: TRow) =>\n (labelColumn && getText(row, labelColumn.id)) || getRowId(row),\n [labelColumn, getText, getRowId]\n );\n\n const isSelected = useCallback(\n (row: TRow) => selectable && selectedSet.has(getRowId(row)),\n [selectable, selectedSet, getRowId]\n );\n\n const setPage = useCallback(\n (next: number) => {\n if (next !== page) setPageState(next);\n },\n [page, setPageState]\n );\n\n // A new search or filter starts from the first page. It's measured against\n // the page as stored, not as shown: a page past the end shows the last,\n // and left stored it would come back once the rows grew again.\n const resetPage = useCallback(() => {\n if (latestPage() !== 1) setPageState(1);\n }, [latestPage, setPageState]);\n\n const setSearch = useCallback(\n (next: string) => {\n setSearchState(next);\n resetPage();\n },\n [setSearchState, resetPage]\n );\n\n const setFilters = useCallback(\n (next: DataTableFilters) => {\n setFiltersState(next);\n resetPage();\n },\n [setFiltersState, resetPage]\n );\n\n const setFilter = useCallback(\n (columnId: string, value: unknown) => {\n const next = { ...latestFilters() };\n if (isActiveFilter(value)) next[columnId] = value;\n else delete next[columnId];\n setFilters(next);\n },\n [latestFilters, setFilters]\n );\n\n const toggleSort = useCallback(\n (columnId: string) => {\n const column = columnsById.get(columnId);\n if (!column) return;\n const first: DataTableSortDirection = column.sortDescFirst\n ? 'descending'\n : 'ascending';\n const current = sort[0]?.id === columnId ? sort[0].direction : undefined;\n if (current === undefined) {\n setSort([{ id: columnId, direction: first }]);\n } else if (current === first) {\n setSort([\n {\n id: columnId,\n direction: first === 'ascending' ? 'descending' : 'ascending',\n },\n ]);\n } else {\n setSort([]);\n }\n },\n [columnsById, sort, setSort]\n );\n\n const toggleRowSelected = useCallback(\n (row: TRow, value?: boolean) => {\n const id = getRowId(row);\n const current = latestSelected();\n const has = current.includes(id);\n const on = value ?? !has;\n if (on === has) return;\n setSelected(on ? [...current, id] : current.filter(s => s !== id));\n },\n [getRowId, latestSelected, setSelected]\n );\n\n const pageIds = useMemo(\n () => pageIndexes.map(index => ids[index]),\n [pageIndexes, ids]\n );\n const pageSelectedCount = pageIds.filter(id => selectedSet.has(id)).length;\n const allPageSelected =\n pageIds.length > 0 && pageSelectedCount === pageIds.length;\n\n const togglePageSelected = useCallback(\n (value?: boolean) => {\n const current = latestSelected();\n const has = new Set(current);\n const on =\n value ?? !(pageIds.length > 0 && pageIds.every(id => has.has(id)));\n if (on) {\n const adding = pageIds.filter(id => !has.has(id));\n if (adding.length > 0) setSelected([...current, ...adding]);\n } else {\n const onPage = new Set(pageIds);\n const kept = current.filter(id => !onPage.has(id));\n if (kept.length !== current.length) setSelected(kept);\n }\n },\n [latestSelected, pageIds, setSelected]\n );\n\n const count = useCallback(\n (value: number) => (formatNumber ? formatNumber(value) : String(value)),\n [formatNumber]\n );\n\n const resolvedLabels: DataTableResolvedLabels = {\n selectAll:\n labels?.selectAll ||\n (pageCount > 1 ? 'Select all rows on this page' : 'Select all rows'),\n selectRow: labels?.selectRow ?? (label => `Select ${label}`),\n sortHint: labels?.sortHint || 'column headers with buttons are sortable',\n search: labels?.search || 'Search',\n results:\n labels?.results ??\n (total =>\n total === 0\n ? 'No rows match'\n : `${count(total)} ${total === 1 ? 'row matches' : 'rows match'}`),\n pageRange:\n labels?.pageRange ??\n ((first, last, total) =>\n `Showing ${count(first)} to ${count(last)} of ${count(total)}`),\n loading: labels?.loading || 'Loading',\n pagination: labels?.pagination || undefined,\n empty: labels?.empty || 'No rows to show.',\n noResults: labels?.noResults || 'No rows match.',\n };\n\n const toCSV = useCallback(\n ({\n rows = 'filtered',\n columns: ids,\n header = true,\n delimiter = ',',\n }: DataTableCSVOptions = {}) => {\n const written = ids\n ? ids\n .map(id => columnsById.get(id))\n .filter(\n (column): column is DataTableColumn<TRow> => column !== undefined\n )\n : columns;\n const line = (fields: string[]) =>\n fields.map(field => csvField(field, delimiter)).join(delimiter);\n const lines = getRows(rows).map(row =>\n line(written.map(column => getText(row, column.id)))\n );\n if (header) lines.unshift(line(written.map(column => column.header)));\n return lines.join('\\r\\n');\n },\n [columnsById, columns, getRows, getText]\n );\n\n const sortButtonClass = prefixedClassNames(prefix, 'data-table-sort');\n\n return {\n columns,\n state: { sort, selected, page, pageSize, search, filters },\n selectionMode,\n manual,\n rowCount,\n pageCount,\n labels: resolvedLabels,\n getRows,\n getRowId,\n getValue,\n getText,\n getRowLabel,\n toCSV,\n isSelected,\n setSort,\n toggleSort,\n setSelected,\n toggleRowSelected,\n togglePageSelected,\n setPage,\n setSearch,\n setFilter,\n setFilters,\n getHeaderCellProps: column => ({\n scope: 'col',\n 'aria-sort': sort[0]?.id === column.id ? sort[0].direction : undefined,\n isAligned: column.align,\n width: column.width,\n }),\n getSortButtonProps: column => ({\n type: 'button',\n className: sortButtonClass,\n onClick: () => toggleSort(column.id),\n }),\n getRowProps: row => ({ isSelected: isSelected(row) }),\n getCellProps: (_row, column) => ({\n scope: column.isRowHeader ? 'row' : undefined,\n isAligned: column.align,\n }),\n getSelectAllProps: () => ({\n 'aria-label': resolvedLabels.selectAll,\n checked: allPageSelected,\n indeterminate: pageSelectedCount > 0 && !allPageSelected,\n disabled: pageIds.length === 0,\n onChange: () => togglePageSelected(),\n }),\n getSelectRowProps: row => ({\n 'aria-label': resolvedLabels.selectRow(getRowLabel(row)),\n checked: selectedSet.has(getRowId(row)),\n onChange: () => toggleRowSelected(row),\n }),\n getPaginationProps: () => ({\n total: pageCount,\n current: page,\n onPageChange: setPage,\n }),\n getSearchProps: () => ({\n type: 'search',\n value: search,\n onChange: event => setSearch(event.target.value),\n }),\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAifA;AACA,SAAS,SAAS,CAAO,MAA6B,EAAE,GAAS,EAAA;AAC/D,IAAA,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM;IAC3B,IAAI,OAAO,QAAQ,KAAK,UAAU;AAAE,QAAA,OAAO,QAAQ,CAAC,GAAG,CAAC;AACxD,IAAA,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;AAAE,QAAA,OAAO,SAAS;IAC7D,OAAQ,GAAoC,EACzC,QAAQ,IAAI,MAAM,CAAC,EAAE,EACvB;AACH;AAEA;AACA,SAAS,QAAQ,CAAO,MAA6B,EAAE,GAAS,EAAA;IAC9D,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC;AACnD,IAAA,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC;AACnE;AAEA;AACA,SAAS,YAAY,CAAC,KAAc,EAAA;IAClC,QACE,KAAK,KAAK,IAAI;AACd,QAAA,KAAK,KAAK,SAAS;AACnB,QAAA,KAAK,KAAK,EAAE;SACX,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAClD,SAAC,KAAK,YAAY,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;AAE5D;AAEA;AACA,SAAS,aAAa,CAAC,CAAU,EAAE,CAAU,EAAE,QAAuB,EAAA;IACpE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,GAAG,CAAC;AAChE,IAAA,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,IAAI;QAAE,OAAO,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE;IAC5E,IAAI,OAAO,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,SAAS,EAAE;QACpD,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IAC9B;AACA,IAAA,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAC/C;AAEA;AACA,SAAS,cAAc,CAAC,KAAc,EAAA;IACpC,QACE,KAAK,KAAK,SAAS;AACnB,QAAA,KAAK,KAAK,IAAI;AACd,QAAA,KAAK,KAAK,EAAE;AACZ,QAAA,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;AAEjD;AAEA;AACA,MAAM,YAAY,GAAG,cAAc;AACnC;AACA,MAAM,WAAW,GAAG,kBAAkB;AAEtC;;;AAGG;AACH,SAAS,QAAQ,CAAC,IAAY,EAAE,SAAiB,EAAA;IAC/C,MAAM,IAAI,GACR,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,GAAG,IAAI;AACxE,IAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI;UAClD,CAAA,CAAA,EAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA,CAAA;UAC5B,IAAI;AACV;AAEA;;;AAGG;AACG,SAAU,WAAW,CAAC,MAAc,EAAE,OAAyB,EAAA;AACnE,IAAA,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;AAC5E;AAEA;AACA,SAAS,IAAI,CAAC,GAAY,EAAA;AACxB,IAAA,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;AAAE,QAAA,OAAO,SAAS;AAC7D,IAAA,MAAM,EAAE,GAAI,GAAwB,CAAC,EAAE;IACvC,OAAO,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,EAAE,GAAG,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC;AAC9E;AAEA;;;;;;;;;AASG;AACH,SAAS,aAAa,CACpB,KAAoB,EACpB,OAAU,EACV,QAAyC,EAAA;IAEzC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC;AACvC,IAAA,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS;IAChC,MAAM,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,GAAG;AAClC,IAAA,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC;;AAEtC,IAAA,MAAM,UAAU,GAAG,MAAM,CAAsB,IAAI,CAAC;IACpD,qBAAqB,CAAC,MAAK;AACzB,QAAA,UAAU,CAAC,OAAO,GAAG,IAAI;AAC3B,IAAA,CAAC,CAAC;AACF,IAAA,MAAM,GAAG,GAAG,WAAW,CACrB,CAAC,IAAO,KAAI;QACV,IAAI,CAAC,IAAI,EAAE;YACT,UAAU,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;YACpC,MAAM,CAAC,IAAI,CAAC;QACd;AACA,QAAA,QAAQ,GAAG,IAAI,CAAC;AAClB,IAAA,CAAC,EACD,CAAC,IAAI,EAAE,QAAQ,CAAC,CACjB;AACD,IAAA,MAAM,MAAM,GAAG,WAAW,CACxB,OAAO,UAAU,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,EACxE,CAAC,QAAQ,CAAC,CACX;AACD,IAAA,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC;AAC/B;AAEA,MAAM,MAAM,GAAoB,EAAE;AAClC,MAAM,KAAK,GAAa,EAAE;AAC1B,MAAM,SAAS,GAAqB,EAAE;AAEtC;;;;;;;;;;;AAWG;AACG,SAAU,YAAY,CAC1B,OAAkC,EAAA;AAElC,IAAA,MAAM,EACJ,OAAO,EACP,IAAI,EACJ,QAAQ,EAAE,OAAO,EACjB,IAAI,EAAE,QAAQ,EACd,WAAW,GAAG,MAAM,EACpB,YAAY,EACZ,aAAa,GAAG,MAAM,EACtB,QAAQ,EAAE,YAAY,EACtB,eAAe,GAAG,KAAK,EACvB,gBAAgB,EAChB,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,QAAQ,EACd,WAAW,GAAG,CAAC,EACf,YAAY,EACZ,MAAM,EAAE,UAAU,EAClB,aAAa,GAAG,EAAE,EAClB,cAAc,EACd,OAAO,EAAE,WAAW,EACpB,cAAc,GAAG,SAAS,EAC1B,eAAe,EACf,MAAM,GAAG,KAAK,EACd,QAAQ,EAAE,YAAY,EACtB,MAAM,GACP,GAAG,OAAO;AAEX,IAAA,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAC;AAC1E,IAAA,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,cAAc,CAAC,GAAG,aAAa,CAC3D,YAAY,EACZ,eAAe,EACf,gBAAgB,CACjB;AACD,IAAA,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,UAAU,CAAC,GAAG,aAAa,CACzD,QAAQ,EACR,WAAW,EACX,YAAY,CACb;AACD,IAAA,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,aAAa,CAC5C,UAAU,EACV,aAAa,EACb,cAAc,CACf;AACD,IAAA,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,aAAa,CAAC,GAAG,aAAa,CAC7D,WAAW,EACX,cAAc,EACd,eAAe,CAChB;AAED,IAAA,MAAM,MAAM,GAAG,cAAc,EAAE;AAC/B,IAAA,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE;AAC9B,IAAA,MAAM,SAAS,GAAG,gBAAgB,EAAE;AACpC,IAAA,MAAM,YAAY,GAAG,eAAe,EAAE;IACtC,MAAM,QAAQ,GAAG,OAAO,CACtB,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAClD,CAAC,MAAM,CAAC,CACT;AAED,IAAA,MAAM,QAAQ,GACZ,YAAY,KAAK,SAAS;AAC1B,QAAA,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC;AAC7B,QAAA,YAAY,IAAI;AACd,UAAE,IAAI,CAAC,KAAK,CAAC,YAAY;UACvB,SAAS;AAEf,IAAA,MAAM,WAAW,GAAG,OAAO,CAAC,MAAK;AAC/B,QAAA,MAAM,IAAI,GAAG,IAAI,GAAG,EAAiC;AACrD,QAAA,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;YAC5B,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;AACvB,gBAAA,QAAQ,CACN,4BAA4B,EAC5B,yDAAyD,MAAM,CAAC,EAAE,CAAA,GAAA,CAAK;oBACrE,mEAAmE;AACnE,oBAAA,sBAAsB,CACzB;YACH;iBAAO;gBACL,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC;YAC7B;QACF;AACA,QAAA,OAAO,IAAI;AACb,IAAA,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;;AAGb,IAAA,MAAM,GAAG,GAAG,OAAO,CAAC,MAAK;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,KAAI;AAClC,YAAA,MAAM,EAAE,GAAG,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;YACpD,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,EAAE;gBACjC,QAAQ,CACN,0BAA0B,EAC1B,oEAAoE;oBAClE,gEAAgE;AAChE,oBAAA,8BAA8B,CACjC;AACD,gBAAA,OAAO,MAAM,CAAC,KAAK,CAAC;YACtB;AACA,YAAA,OAAO,EAAE;AACX,QAAA,CAAC,CAAC;AACF,QAAA,IAAI,KAAK,EAAE,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,EAAE;YAC7C,QAAQ,CACN,4BAA4B,EAC5B,mEAAmE;gBACjE,8DAA8D;AAC9D,gBAAA,YAAY,CACf;QACH;AACA,QAAA,OAAO,GAAG;AACZ,IAAA,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAEnB,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,MAAK;AAC3B,QAAA,MAAM,GAAG,GAAG,IAAI,GAAG,EAAgB;QACnC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,KAAI;AAC1B,YAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;AAAE,gBAAA,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC;AACxC,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,GAAG;AACZ,IAAA,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;;AAGV,IAAA,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,GAAS,KAAI;QACZ,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QAC9B,IAAI,KAAK,KAAK,SAAS;AAAE,YAAA,OAAO,GAAG,CAAC,KAAK,CAAC;QAC1C,MAAM,EAAE,GAAG,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;QACjD,OAAO,EAAE,IAAI,EAAE;IACjB,CAAC,EACD,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CACxB;;;AAID,IAAA,MAAM,KAAK,GAAG,OAAO,CACnB,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EACnE,CAAC,IAAI,EAAE,OAAO,CAAC,CAChB;AAED,IAAA,MAAM,aAAa,GAAG,OAAO,CAAC,MAAK;AACjC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,KAAK,CAAC;AACzC,QAAA,IAAI,MAAM;AAAE,YAAA,OAAO,GAAG;QACtB,MAAM,IAAI,GAAG;AACV,aAAA,GAAG,CAAC,KAAK,KAAK;YACb,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;AACjC,YAAA,UAAU,EAAE,KAAK,CAAC,SAAS,KAAK,YAAY;AAC7C,SAAA,CAAC;AACD,aAAA,MAAM,CACL,CAAC,GAAG,KACF,GAAG,CAAC,MAAM,KAAK,SAAS,CAC3B;AACH,QAAA,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;AAAE,YAAA,OAAO,GAAG;AACjC,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,KACjC,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAC/D;QACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAI;AACvB,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBACpC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;AACtC,gBAAA,IAAI,MAAc;AAClB,gBAAA,IAAI,MAAM,CAAC,MAAM,EAAE;AACjB,oBAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AACxC,oBAAA,IAAI,UAAU;wBAAE,MAAM,GAAG,CAAC,MAAM;gBAClC;qBAAO;oBACL,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC;oBACvB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC;AACvB,oBAAA,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC;AAC9B,oBAAA,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC;AAC9B,oBAAA,IAAI,MAAM,IAAI,MAAM,EAAE;;wBAEpB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;oBAC1C;yBAAO;wBACL,MAAM,GAAG,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AACtC,wBAAA,IAAI,UAAU;4BAAE,MAAM,GAAG,CAAC,MAAM;oBAClC;gBACF;AACA,gBAAA,IAAI,MAAM;AAAE,oBAAA,OAAO,MAAM;YAC3B;;YAEA,OAAO,CAAC,GAAG,CAAC;AACd,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AAE/C,IAAA,MAAM,eAAe,GAAG,OAAO,CAAC,MAAK;AACnC,QAAA,IAAI,MAAM;AAAE,YAAA,OAAO,aAAa;AAChC,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE;QAC3B,MAAM,KAAK,GAAG;AACZ,cAAE,CAAC,IAAY,EAAE,MAAc,KAAK,SAAS,CAAC,IAAI,EAAE,MAAM;cACxD,CAAC,IAAY,EAAE,MAAc,KAC3B,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACvD,MAAM,QAAQ,GAAG;AACd,aAAA,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC1C,aAAA,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC,UAAU,KAAK,KAAK,CAAC;AACtD,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO;AACpC,aAAA,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,cAAc,CAAC,KAAK,CAAC;aAC3C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM;AACrB,YAAA,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;AAC3B,YAAA,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,MAAM,IAAI,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;YACpD,KAAK;AACN,SAAA,CAAC;AACD,aAAA,MAAM,CACL,CAAC,EAAE,MAAM,EAAE,KAAK,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,KAAK,KAAK,CACpE;QACH,IAAI,KAAK,KAAK,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;AAAE,YAAA,OAAO,aAAa;AAC/D,QAAA,OAAO,aAAa,CAAC,MAAM,CAAC,QAAQ,IAAG;AACrC,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC;AAC1B,YAAA,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;YAChC,KAAK,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,QAAQ,EAAE;;AAE/C,gBAAA,MAAM,MAAM,GAAG,MAAO,CAAC;sBACnB,MAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK;AAC7B,sBAAE,KAAK,CAAC,OAAO,CAAC,KAAK;0BACjB,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AAC3D,0BAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AAC3C,gBAAA,IAAI,CAAC,MAAM;AAAE,oBAAA,OAAO,KAAK;YAC3B;YACA,QACE,KAAK,KAAK,EAAE;gBACZ,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;AAE/D,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC,EAAE;QACD,MAAM;QACN,aAAa;QACb,MAAM;QACN,OAAO;QACP,SAAS;QACT,OAAO;QACP,WAAW;QACX,IAAI;QACJ,KAAK;AACN,KAAA,CAAC;AAEF,IAAA,MAAM,UAAU,GACd,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC;IAC7D,IAAI,MAAM,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,UAAU,EAAE;QACnD,QAAQ,CACN,4BAA4B,EAC5B,mEAAmE;YACjE,mEAAmE;YACnE,mEAAmE;AACnE,YAAA,gBAAgB,CACnB;IACH;IACA,MAAM,QAAQ,GAAG;UACb,IAAI,CAAC,GAAG,CACN,IAAI,CAAC,KAAK,CAAC,UAAU,GAAI,YAAuB,GAAG,IAAI,CAAC,MAAM,CAAC,EAC/D,CAAC;AAEL,UAAE,eAAe,CAAC,MAAM;IAC1B,MAAM,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC;AAC5E,IAAA,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CACnB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EACnE,SAAS,CACV;AAED,IAAA,MAAM,WAAW,GAAG,OAAO,CAAC,MAAK;QAC/B,IAAI,MAAM,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,eAAe;AAC/C,QAAA,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,QAAQ,EAAE,IAAI,GAAG,QAAQ,CAAC;IACtE,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC;AAE7C,IAAA,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;AAChE,IAAA,MAAM,UAAU,GAAG,aAAa,KAAK,UAAU;IAE/C,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,OAAiB,KAAK,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EACxD,CAAC,IAAI,CAAC,CACP;IAED,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,KAAA,GAA2B,UAAU,KAAI;QACxC,QAAQ,KAAK;AACX,YAAA,KAAK,KAAK;AACR,gBAAA,OAAO,MAAM,CAAC,aAAa,CAAC;AAC9B,YAAA,KAAK,MAAM;AACT,gBAAA,OAAO,MAAM,CAAC,WAAW,CAAC;AAC5B,YAAA,KAAK,UAAU;gBACb,OAAO,MAAM,CACX,eAAe,CAAC,MAAM,CAAC,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAC7D;AACH,YAAA;AACE,gBAAA,OAAO,MAAM,CAAC,eAAe,CAAC;;AAEpC,IAAA,CAAC,EACD,CAAC,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,GAAG,CAAC,CACxE;IAED,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,GAAS,EAAE,QAAgB,KAAI;QAC9B,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC;AACxC,QAAA,OAAO,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS;AACpD,IAAA,CAAC,EACD,CAAC,WAAW,CAAC,CACd;IAED,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,GAAS,EAAE,QAAgB,KAAI;QAC9B,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC;AACxC,QAAA,IAAI,CAAC,MAAM;AAAE,YAAA,OAAO,EAAE;QACtB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QAC9B,OAAO,KAAK,KAAK;AACf,cAAE,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;AACtC,cAAE,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;IAC3B,CAAC,EACD,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CACvC;AAED,IAAA,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC;AAC5E,IAAA,MAAM,WAAW,GAAG,WAAW,CAC7B,CAAC,GAAS,KACR,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,EAChE,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CACjC;AAED,IAAA,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,GAAS,KAAK,UAAU,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAC3D,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,CAAC,CACpC;AAED,IAAA,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,IAAY,KAAI;QACf,IAAI,IAAI,KAAK,IAAI;YAAE,YAAY,CAAC,IAAI,CAAC;AACvC,IAAA,CAAC,EACD,CAAC,IAAI,EAAE,YAAY,CAAC,CACrB;;;;AAKD,IAAA,MAAM,SAAS,GAAG,WAAW,CAAC,MAAK;QACjC,IAAI,UAAU,EAAE,KAAK,CAAC;YAAE,YAAY,CAAC,CAAC,CAAC;AACzC,IAAA,CAAC,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AAE9B,IAAA,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,IAAY,KAAI;QACf,cAAc,CAAC,IAAI,CAAC;AACpB,QAAA,SAAS,EAAE;AACb,IAAA,CAAC,EACD,CAAC,cAAc,EAAE,SAAS,CAAC,CAC5B;AAED,IAAA,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,IAAsB,KAAI;QACzB,eAAe,CAAC,IAAI,CAAC;AACrB,QAAA,SAAS,EAAE;AACb,IAAA,CAAC,EACD,CAAC,eAAe,EAAE,SAAS,CAAC,CAC7B;IAED,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,QAAgB,EAAE,KAAc,KAAI;AACnC,QAAA,MAAM,IAAI,GAAG,EAAE,GAAG,aAAa,EAAE,EAAE;QACnC,IAAI,cAAc,CAAC,KAAK,CAAC;AAAE,YAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,KAAK;;AAC5C,YAAA,OAAO,IAAI,CAAC,QAAQ,CAAC;QAC1B,UAAU,CAAC,IAAI,CAAC;AAClB,IAAA,CAAC,EACD,CAAC,aAAa,EAAE,UAAU,CAAC,CAC5B;AAED,IAAA,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,QAAgB,KAAI;QACnB,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC;AACxC,QAAA,IAAI,CAAC,MAAM;YAAE;AACb,QAAA,MAAM,KAAK,GAA2B,MAAM,CAAC;AAC3C,cAAE;cACA,WAAW;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS;AACxE,QAAA,IAAI,OAAO,KAAK,SAAS,EAAE;AACzB,YAAA,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/C;AAAO,aAAA,IAAI,OAAO,KAAK,KAAK,EAAE;AAC5B,YAAA,OAAO,CAAC;AACN,gBAAA;AACE,oBAAA,EAAE,EAAE,QAAQ;oBACZ,SAAS,EAAE,KAAK,KAAK,WAAW,GAAG,YAAY,GAAG,WAAW;AAC9D,iBAAA;AACF,aAAA,CAAC;QACJ;aAAO;YACL,OAAO,CAAC,EAAE,CAAC;QACb;IACF,CAAC,EACD,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,CAC7B;IAED,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,GAAS,EAAE,KAAe,KAAI;AAC7B,QAAA,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC;AACxB,QAAA,MAAM,OAAO,GAAG,cAAc,EAAE;QAChC,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;AAChC,QAAA,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC,GAAG;QACxB,IAAI,EAAE,KAAK,GAAG;YAAE;QAChB,WAAW,CAAC,EAAE,GAAG,CAAC,GAAG,OAAO,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC,EACD,CAAC,QAAQ,EAAE,cAAc,EAAE,WAAW,CAAC,CACxC;IAED,MAAM,OAAO,GAAG,OAAO,CACrB,MAAM,WAAW,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAC1C,CAAC,WAAW,EAAE,GAAG,CAAC,CACnB;AACD,IAAA,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM;AAC1E,IAAA,MAAM,eAAe,GACnB,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,iBAAiB,KAAK,OAAO,CAAC,MAAM;AAE5D,IAAA,MAAM,kBAAkB,GAAG,WAAW,CACpC,CAAC,KAAe,KAAI;AAClB,QAAA,MAAM,OAAO,GAAG,cAAc,EAAE;AAChC,QAAA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;AAC5B,QAAA,MAAM,EAAE,GACN,KAAK,IAAI,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACpE,IAAI,EAAE,EAAE;AACN,YAAA,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACjD,YAAA,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;gBAAE,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC,CAAC;QAC7D;aAAO;AACL,YAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;AAC/B,YAAA,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClD,YAAA,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;gBAAE,WAAW,CAAC,IAAI,CAAC;QACvD;IACF,CAAC,EACD,CAAC,cAAc,EAAE,OAAO,EAAE,WAAW,CAAC,CACvC;AAED,IAAA,MAAM,KAAK,GAAG,WAAW,CACvB,CAAC,KAAa,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EACvE,CAAC,YAAY,CAAC,CACf;AAED,IAAA,MAAM,cAAc,GAA4B;QAC9C,SAAS,EACP,MAAM,EAAE,SAAS;aAChB,SAAS,GAAG,CAAC,GAAG,8BAA8B,GAAG,iBAAiB,CAAC;AACtE,QAAA,SAAS,EAAE,MAAM,EAAE,SAAS,KAAK,KAAK,IAAI,CAAA,OAAA,EAAU,KAAK,EAAE,CAAC;AAC5D,QAAA,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,0CAA0C;AACxE,QAAA,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,QAAQ;QAClC,OAAO,EACL,MAAM,EAAE,OAAO;AACf,aAAC,KAAK,IACJ,KAAK,KAAK;AACR,kBAAE;AACF,kBAAE,CAAA,EAAG,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,GAAG,aAAa,GAAG,YAAY,EAAE,CAAC;QACxE,SAAS,EACP,MAAM,EAAE,SAAS;aAChB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,KAClB,CAAA,QAAA,EAAW,KAAK,CAAC,KAAK,CAAC,CAAA,IAAA,EAAO,KAAK,CAAC,IAAI,CAAC,CAAA,IAAA,EAAO,KAAK,CAAC,KAAK,CAAC,CAAA,CAAE,CAAC;AACnE,QAAA,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,SAAS;AACrC,QAAA,UAAU,EAAE,MAAM,EAAE,UAAU,IAAI,SAAS;AAC3C,QAAA,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,kBAAkB;AAC1C,QAAA,SAAS,EAAE,MAAM,EAAE,SAAS,IAAI,gBAAgB;KACjD;IAED,MAAM,KAAK,GAAG,WAAW,CACvB,CAAC,EACC,IAAI,GAAG,UAAU,EACjB,OAAO,EAAE,GAAG,EACZ,MAAM,GAAG,IAAI,EACb,SAAS,GAAG,GAAG,GAAA,GACQ,EAAE,KAAI;QAC7B,MAAM,OAAO,GAAG;AACd,cAAE;iBACG,GAAG,CAAC,EAAE,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;iBAC7B,MAAM,CACL,CAAC,MAAM,KAAsC,MAAM,KAAK,SAAS;cAErE,OAAO;QACX,MAAM,IAAI,GAAG,CAAC,MAAgB,KAC5B,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACjE,QAAA,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,IACjC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CACrD;AACD,QAAA,IAAI,MAAM;AAAE,YAAA,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACrE,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;IAC3B,CAAC,EACD,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CACzC;IAED,MAAM,eAAe,GAAG,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAErE,OAAO;QACL,OAAO;AACP,QAAA,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;QAC1D,aAAa;QACb,MAAM;QACN,QAAQ;QACR,SAAS;AACT,QAAA,MAAM,EAAE,cAAc;QACtB,OAAO;QACP,QAAQ;QACR,QAAQ;QACR,OAAO;QACP,WAAW;QACX,KAAK;QACL,UAAU;QACV,OAAO;QACP,UAAU;QACV,WAAW;QACX,iBAAiB;QACjB,kBAAkB;QAClB,OAAO;QACP,SAAS;QACT,SAAS;QACT,UAAU;AACV,QAAA,kBAAkB,EAAE,MAAM,KAAK;AAC7B,YAAA,KAAK,EAAE,KAAK;YACZ,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS;YACtE,SAAS,EAAE,MAAM,CAAC,KAAK;YACvB,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC;AACF,QAAA,kBAAkB,EAAE,MAAM,KAAK;AAC7B,YAAA,IAAI,EAAE,QAAQ;AACd,YAAA,SAAS,EAAE,eAAe;YAC1B,OAAO,EAAE,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;SACrC,CAAC;AACF,QAAA,WAAW,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,MAAM;YAC/B,KAAK,EAAE,MAAM,CAAC,WAAW,GAAG,KAAK,GAAG,SAAS;YAC7C,SAAS,EAAE,MAAM,CAAC,KAAK;SACxB,CAAC;AACF,QAAA,iBAAiB,EAAE,OAAO;YACxB,YAAY,EAAE,cAAc,CAAC,SAAS;AACtC,YAAA,OAAO,EAAE,eAAe;AACxB,YAAA,aAAa,EAAE,iBAAiB,GAAG,CAAC,IAAI,CAAC,eAAe;AACxD,YAAA,QAAQ,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC;AAC9B,YAAA,QAAQ,EAAE,MAAM,kBAAkB,EAAE;SACrC,CAAC;AACF,QAAA,iBAAiB,EAAE,GAAG,KAAK;YACzB,YAAY,EAAE,cAAc,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YACxD,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACvC,YAAA,QAAQ,EAAE,MAAM,iBAAiB,CAAC,GAAG,CAAC;SACvC,CAAC;AACF,QAAA,kBAAkB,EAAE,OAAO;AACzB,YAAA,KAAK,EAAE,SAAS;AAChB,YAAA,OAAO,EAAE,IAAI;AACb,YAAA,YAAY,EAAE,OAAO;SACtB,CAAC;AACF,QAAA,cAAc,EAAE,OAAO;AACrB,YAAA,IAAI,EAAE,QAAQ;AACd,YAAA,KAAK,EAAE,MAAM;AACb,YAAA,QAAQ,EAAE,KAAK,IAAI,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;SACjD,CAAC;KACH;AACH;;"}
|
|
1
|
+
{"version":3,"file":"useDataTable.js","sources":["../../../src/components/useDataTable.ts"],"sourcesContent":["import React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { prefixedClassNames } from '../helpers/classNames';\nimport { useClassPrefix } from '../helpers/Config';\nimport { isDev, warnOnce } from '../helpers/devWarnings';\nimport { useLocale } from '../helpers/LocaleProvider';\nimport {\n useLocaleMatcher,\n useScopedNumberFormat,\n} from '../helpers/localeFormat';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport { useLatestRef } from '../helpers/useLatestRef';\nimport type { TableAlignment } from '../elements/tableAlignment';\n\n/**\n * Carries a row type and adds nothing, so `DataTableColumnMeta` can take the\n * row type for the fields an add-on merges in while it has none of its own.\n */\ntype CarriesRow<TRow> = { [K in never]?: TRow };\n\n/**\n * Options of its own an add-on gives a column, read from the column's\n * `meta`. Empty in bestax: an add-on, such as a spreadsheet exporter, adds\n * its fields by declaration merging, and every column then takes them. Every\n * declaration of it names the row type the same way, `TRow`.\n *\n * @example\n * declare module '@allxsmith/bestax-bulma' {\n * interface DataTableColumnMeta<TRow> {\n * exportValue?: (row: TRow) => string | number;\n * }\n * }\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- empty so an add-on can merge into it\nexport interface DataTableColumnMeta<TRow = unknown> extends CarriesRow<TRow> {}\n\n/** What a column's `cell` is given beside the row. */\nexport interface DataTableCellContext {\n /** The column's raw value for the row, from its `accessor`. */\n value: unknown;\n /** The column's text for the row, from its `format`. */\n text: string;\n /** The row's id, from `getRowId`. */\n rowId: string;\n}\n\n/**\n * One column of a DataTable. A column keeps three things apart: its raw\n * value (`accessor`), which sorting and `filterFn` read; its text\n * (`format`), which the cell shows, the search matches and an export\n * writes; and its rich content (`cell`), which only the screen sees.\n */\nexport interface DataTableColumn<TRow> {\n /**\n * Names the column for good: the sort, the filters and an export refer to\n * it by this id. Unique within the table, and stable across renders.\n */\n id: string;\n /**\n * The column's name, as text: the header, the sort button's name, the\n * row checkboxes' names when it's the row header, and the header an\n * export writes.\n */\n header: string;\n /**\n * The raw value, for sorting and filtering: a key of the row, or a\n * function of it. Left out, it's the row's property named `id`.\n */\n accessor?: keyof TRow | ((row: TRow) => unknown);\n /**\n * The text for the value: what the cell shows when there's no `cell`, what\n * the search matches, and what an export writes. Left out, it's the value\n * as a string, and nothing for `null` or `undefined`. Give one for\n * numbers and dates you want written a certain way.\n */\n format?: (value: unknown, row: TRow) => string;\n /**\n * Rich content for the cell, such as a tag or a link. Only the screen\n * reads it: sorting, the search and an export use the value and its text.\n */\n cell?: (row: TRow, context: DataTableCellContext) => React.ReactNode;\n /**\n * Makes the header a button that sorts by this column: ascending, then\n * descending, then unsorted.\n */\n sortable?: boolean;\n /** Sorts descending on the first press, for a column read from the top, such as a score. */\n sortDescFirst?: boolean;\n /**\n * Compares two rows for an ascending sort, returning a negative number,\n * zero or a positive one. Descending reverses it. Without it, numbers,\n * dates and booleans compare by value, anything else by its text in the\n * `LocaleProvider`'s locale with numbers inside it read as numbers (\"Item\n * 9\" before \"Item 10\"), and an empty value goes last either way.\n */\n sortFn?: (a: TRow, b: TRow) => number;\n /**\n * Whether the column takes part in filtering: the search matches its\n * text, and `filters` can hold a value for it. `false` leaves it out of\n * both, as for a column of actions.\n */\n filterable?: boolean;\n /**\n * Decides whether a row passes this column's value in `filters`. Without\n * it, the column's text has to contain the value's text, compared as the\n * search compares.\n */\n filterFn?: (row: TRow, filterValue: unknown) => boolean;\n /** Aligns the header and the cells (`isAligned` on `Th` and `Td`). */\n align?: TableAlignment;\n /** The column's width, on its header cell: a number is pixels, a string any CSS length. */\n width?: string | number;\n /**\n * Renders this column's cells as row headers (`th scope=\"row\"`), which a\n * screen reader reads out with the other cells of the row. The row's\n * checkbox is named from it. Mark one column, usually the first.\n */\n isRowHeader?: boolean;\n /** Options of an add-on's own, as `DataTableColumnMeta` declares them. */\n meta?: DataTableColumnMeta<TRow>;\n}\n\n/** The direction of a sort, in `aria-sort`'s words. */\nexport type DataTableSortDirection = 'ascending' | 'descending';\n\n/** One column a DataTable sorts by. */\nexport interface DataTableSort {\n /** The column's `id`. */\n id: string;\n /** Which way it sorts. */\n direction: DataTableSortDirection;\n}\n\n/** The values per column `filters` holds, keyed by column `id`. */\nexport type DataTableFilters = Record<string, unknown>;\n\n/**\n * Which of a table's rows to read: `all` of `data`, `filtered` (the ones the\n * search and the filters let through, from every page), the `page` shown,\n * or the `selected` ones the filters let through. Each comes in the order\n * the table shows them.\n */\nexport type DataTableRowScope = 'all' | 'filtered' | 'page' | 'selected';\n\n/** Whether a DataTable has row checkboxes. */\nexport type DataTableSelectionMode = 'none' | 'multiple';\n\n/**\n * The words a DataTable writes. Each is English unless you give your own,\n * and the numbers in the default messages are written in the\n * `LocaleProvider`'s locale.\n */\nexport interface DataTableLabels {\n /**\n * The header checkbox's name. \"Select all rows\", or \"Select all rows on\n * this page\" when there's more than one page, since it then covers the\n * page shown.\n */\n selectAll?: string;\n /** A row checkbox's name, from the row's label (`label => 'Select ' + label`). */\n selectRow?: (rowLabel: string) => string;\n /**\n * Says that headers with buttons sort: hidden at the end of the caption,\n * after a comma, or as a hidden caption of its own. \"column headers with\n * buttons are sortable\".\n */\n sortHint?: string;\n /** The search field's label. \"Search\". */\n search?: string;\n /** Announced after the search or a filter changes (\"12 rows match\"). */\n results?: (count: number) => string;\n /** Announced after the page changes (\"Showing 11 to 20 of 57\"). */\n pageRange?: (first: number, last: number, total: number) => string;\n /** Announced while `loading`, once the search, a filter or the page has changed. \"Loading\". */\n loading?: string;\n /**\n * The pager's name. \"{the table's name} pages\" when the table is named by\n * `aria-label` or a text `caption`, so two tables' pagers have different\n * names, else `Pagination`'s own.\n */\n pagination?: string;\n /** What the table shows with no rows at all. \"No rows to show.\" */\n empty?: string;\n /** What the table shows when the search and filters let no row through. \"No rows match.\" */\n noResults?: string;\n}\n\n/** The words a DataTable writes, with every default filled in. */\nexport interface DataTableResolvedLabels extends Required<\n Omit<DataTableLabels, 'pagination'>\n> {\n /** The pager's name, when one was given. */\n pagination?: string;\n}\n\n/**\n * The options `useDataTable` and `DataTable` share, beside the columns and\n * the data. Each piece of state is yours when you pass its value (and its\n * `on…Change`), or the table's own, starting from its `default…`.\n */\nexport interface DataTableStateOptions<TRow> {\n /**\n * A row's id, unique and stable, which the selection is a list of. Left\n * out, it's the row's `id` property as a string. A development build\n * warns about a missing or repeated id, and a row with none falls back to\n * its index, which doesn't survive the data changing.\n */\n getRowId?: (row: TRow, index: number) => string;\n /**\n * The sort when you hold it: an array of `{ id, direction }`, the first\n * deciding and each next one breaking ties. The headers set one at a time.\n */\n sort?: DataTableSort[];\n /**\n * The sort to start with when the table holds it. Text sorts in the\n * `LocaleProvider`'s locale, or the runtime's own outside one, which can\n * differ between a server and the browser, so put a table rendered on the\n * server sorted inside a `LocaleProvider`.\n */\n defaultSort?: DataTableSort[];\n /** Called with the new sort when a header is pressed. */\n onSortChange?: (sort: DataTableSort[]) => void;\n /**\n * `multiple` adds a checkbox to each row and a \"select all\" checkbox to the header.\n *\n * @defaultValue 'none'\n */\n selectionMode?: DataTableSelectionMode;\n /**\n * The selected rows' ids when you hold them. They stay selected while the\n * search, a filter or the page hides them.\n */\n selected?: string[];\n /** The rows selected to begin with, by id, when the table holds them. */\n defaultSelected?: string[];\n /** Called with every selected id after a checkbox changes. */\n onSelectedChange?: (selected: string[]) => void;\n /** Rows per page. Set, the table pages through `Pagination`; left out, it shows every row. */\n pageSize?: number;\n /**\n * The page shown when you hold it, counting from 1. A page past the end\n * shows the last.\n */\n page?: number;\n /**\n * The page to start on when the table holds it.\n *\n * @defaultValue 1\n */\n defaultPage?: number;\n /**\n * Called with the page chosen in the pager, and with 1 when the search or\n * a filter changes through the table while the page held isn't 1, even\n * when a page past the end shows as the last.\n */\n onPageChange?: (page: number) => void;\n /**\n * The search when you hold it, matched against every filterable column's\n * text: in the `LocaleProvider`'s locale, ignoring case and the accents\n * the language ignores, or a case-insensitive substring outside one.\n */\n search?: string;\n /** The search to start with when the table holds it. */\n defaultSearch?: string;\n /** Called with the search as it changes through the table. */\n onSearchChange?: (search: string) => void;\n /**\n * A value per column, by `id`, when you hold them. A row passes when every\n * column with a value passes it: the column's `filterFn` if it has one,\n * given the value as it is, or else the column's text has to contain the\n * value's text, compared as the search compares. An array is a choice of\n * values, as a multiple-choice filter gives, and passes a row whose text\n * contains any of them. A value of `undefined`, `null`, `''` or an empty\n * array is no filter.\n */\n filters?: DataTableFilters;\n /** The filters to start with when the table holds them. */\n defaultFilters?: DataTableFilters;\n /** Called with every filter value after one changes through the table. */\n onFiltersChange?: (filters: DataTableFilters) => void;\n /**\n * Hands sorting, filtering and paging to a server: the table shows `data`\n * as given, as the current page, and only reports the state as it\n * changes.\n */\n manual?: boolean;\n /**\n * With `manual`, how many rows match in all, which sets the page count and\n * the announced count. Without it, the table counts the rows in `data`,\n * which with a `pageSize` is one page and no pager, and a development\n * build warns.\n */\n rowCount?: number;\n /** The words the table writes, in your app's language. */\n labels?: DataTableLabels;\n}\n\n/** What `useDataTable` takes. */\nexport interface UseDataTableOptions<TRow> extends DataTableStateOptions<TRow> {\n /**\n * The columns, in the order they're shown. Keep the array the same from\n * one render to the next, defined outside the component or in `useMemo`:\n * a new one has every cell's text worked out again.\n */\n columns: DataTableColumn<TRow>[];\n /** The rows, as records of your own. */\n data: TRow[];\n}\n\n/** The table's state, as it stands. */\nexport interface DataTableState {\n /** The sort, the first entry deciding. */\n sort: DataTableSort[];\n /** The selected rows' ids. */\n selected: string[];\n /** The page shown, counting from 1. */\n page: number;\n /** Rows per page, or `undefined` when it doesn't page. */\n pageSize: number | undefined;\n /** The search. */\n search: string;\n /** The filter values, by column id. */\n filters: DataTableFilters;\n}\n\n/** The props `getSortButtonProps` gives a header's `<button>`. */\nexport interface DataTableSortButtonProps {\n type: 'button';\n className: string;\n onClick: () => void;\n}\n\n/** The props `getSearchProps` gives a search `<input>` or bestax `Input`. */\nexport interface DataTableSearchProps {\n type: 'search';\n value: string;\n onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;\n}\n\n/** The props `getHeaderCellProps` gives a column's `Th`. */\nexport interface DataTableHeaderCellProps {\n scope: 'col';\n 'aria-sort'?: DataTableSortDirection;\n isAligned?: TableAlignment;\n width?: string | number;\n}\n\n/** The props `getCellProps` gives a row's `Td`, or its `Th` for the row header. */\nexport interface DataTableCellProps {\n scope?: 'row';\n isAligned?: TableAlignment;\n}\n\n/** The props `getSelectAllProps` and `getSelectRowProps` give a `Checkbox`. */\nexport interface DataTableCheckboxProps {\n 'aria-label': string;\n checked: boolean;\n indeterminate?: boolean;\n disabled?: boolean;\n onChange: () => void;\n}\n\n/** The props `getPaginationProps` gives `Pagination`. */\nexport interface DataTablePaginationProps {\n total: number;\n current: number;\n onPageChange: (page: number) => void;\n}\n\n/** What `toCSV` writes. */\nexport interface DataTableCSVOptions {\n /**\n * Which rows, in the order the table shows them: the ones the search and\n * filters let through, from every page, by default, or `all`, `page` or\n * `selected`.\n *\n * @defaultValue 'filtered'\n */\n rows?: DataTableRowScope;\n /** The ids of the columns to write, in that order. Every column, in the order shown, by default. */\n columns?: string[];\n /**\n * Writes the columns' headers as the first line.\n *\n * @defaultValue true\n */\n header?: boolean;\n /**\n * What separates the fields. A semicolon suits a spreadsheet that reads\n * a comma as the decimal point, as Excel does in much of Europe.\n *\n * @defaultValue ','\n */\n delimiter?: string;\n}\n\n/**\n * A table: what `useDataTable` returns, what `DataTable`'s `toolbar` is\n * given, and what its `table` takes. It reads the rows and the state, changes\n * the state, and hands out props for bestax's own `Th`, `Tr`, `Td`,\n * `Checkbox` and `Pagination`, so markup of your own behaves as DataTable's\n * does.\n */\nexport interface DataTableModel<TRow> {\n /** The columns, in the order they're shown. */\n columns: DataTableColumn<TRow>[];\n /** The state as it stands. */\n state: DataTableState;\n /** Whether rows have checkboxes. */\n selectionMode: DataTableSelectionMode;\n /** Whether a server sorts, filters and pages (`manual`). */\n manual: boolean;\n /** How many rows the search and filters let through, or `rowCount` with `manual`. */\n rowCount: number;\n /** How many pages there are, at least 1. */\n pageCount: number;\n /** The words the table writes, with the defaults filled in. */\n labels: DataTableResolvedLabels;\n /** The rows in `scope` (`filtered` by default), in the order the table shows them. */\n getRows: (scope?: DataTableRowScope) => TRow[];\n /** A row's id. */\n getRowId: (row: TRow) => string;\n /** A column's raw value for a row, or `undefined` for a column it doesn't have. */\n getValue: (row: TRow, columnId: string) => unknown;\n /** A column's text for a row, or `''` for a column it doesn't have. */\n getText: (row: TRow, columnId: string) => string;\n /** What names a row: its row header's text, or its first column's. */\n getRowLabel: (row: TRow) => string;\n /**\n * The rows as CSV, from the columns' text (`format`, not `cell`), with a\n * line break of `\\r\\n` between rows and fields quoted as RFC 4180 asks.\n * A field that starts with `=`, `+`, `-`, `@`, a tab or a carriage return\n * gets a `'` in front, so a spreadsheet shows it as text rather than\n * running it as a formula, unless it's a plain number such as `-12.5`.\n * Excel takes a file as UTF-8 only when it starts with a byte order mark,\n * so put `\\uFEFF` in front of the text when you save it for Excel.\n */\n toCSV: (options?: DataTableCSVOptions) => string;\n /** Whether a row is selected. */\n isSelected: (row: TRow) => boolean;\n /** Sets the sort. */\n setSort: (sort: DataTableSort[]) => void;\n /** Moves a column through its sort, as its header button does. */\n toggleSort: (columnId: string) => void;\n /** Sets the selected ids. */\n setSelected: (selected: string[]) => void;\n /**\n * Selects a row, or clears it, or with no `selected` flips it. Called\n * twice in one handler, the second call builds on the first while the\n * table holds the selection. While you hold it, each call builds on the\n * selection as rendered, so make several changes at once with\n * `setSelected`.\n */\n toggleRowSelected: (row: TRow, selected?: boolean) => void;\n /**\n * Selects every row on the page, or clears them, or with no `selected`\n * does what the header checkbox does. It builds on earlier calls as\n * `toggleRowSelected` does.\n */\n togglePageSelected: (selected?: boolean) => void;\n /** Goes to a page, counting from 1. */\n setPage: (page: number) => void;\n /**\n * Sets the search, and goes back to page 1, calling `onPageChange` with 1\n * unless the page held is 1 already.\n */\n setSearch: (search: string) => void;\n /**\n * Sets one column's filter value, and goes back to page 1. Called twice in\n * one handler, the second call builds on the first while the table holds\n * the filters. While you hold them, each call builds on the filters as\n * rendered, so set several at once with `setFilters`.\n */\n setFilter: (columnId: string, value: unknown) => void;\n /** Sets every filter value, and goes back to page 1, as `setSearch` does. */\n setFilters: (filters: DataTableFilters) => void;\n /** Props for a column's `Th`: its scope, its `aria-sort` while sorted, its alignment and width. */\n getHeaderCellProps: (\n column: DataTableColumn<TRow>\n ) => DataTableHeaderCellProps;\n /** Props for the `<button>` in a sortable column's header. */\n getSortButtonProps: (\n column: DataTableColumn<TRow>\n ) => DataTableSortButtonProps;\n /** Props for a row's `Tr`: Bulma's selected look while it's selected. */\n getRowProps: (row: TRow) => { isSelected: boolean };\n /** Props for a row's cell in a column: its alignment, and `scope=\"row\"` for the row header. */\n getCellProps: (\n row: TRow,\n column: DataTableColumn<TRow>\n ) => DataTableCellProps;\n /** Props for the header's \"select all\" `Checkbox`, which covers the page shown. */\n getSelectAllProps: () => DataTableCheckboxProps;\n /** Props for a row's `Checkbox`, named for the row. */\n getSelectRowProps: (row: TRow) => DataTableCheckboxProps;\n /** Props for `Pagination`: the page count, the page and the handler. */\n getPaginationProps: () => DataTablePaginationProps;\n /** Props for a search field, bound to the search. */\n getSearchProps: () => DataTableSearchProps;\n}\n\n/** A column's raw value for a row. */\nfunction readValue<TRow>(column: DataTableColumn<TRow>, row: TRow): unknown {\n const { accessor } = column;\n if (typeof accessor === 'function') return accessor(row);\n if (row === null || typeof row !== 'object') return undefined;\n return (row as Record<PropertyKey, unknown>)[\n (accessor ?? column.id) as PropertyKey\n ];\n}\n\n/** A column's text for a row. */\nfunction readText<TRow>(column: DataTableColumn<TRow>, row: TRow): string {\n const value = readValue(column, row);\n if (column.format) return column.format(value, row);\n return value === null || value === undefined ? '' : String(value);\n}\n\n/** Whether a value sorts as empty: nothing, no text, or no number or date. */\nfunction isEmptyValue(value: unknown): boolean {\n return (\n value === null ||\n value === undefined ||\n value === '' ||\n (typeof value === 'number' && Number.isNaN(value)) ||\n (value instanceof Date && Number.isNaN(value.getTime()))\n );\n}\n\n/** Compares two values that aren't empty, for an ascending sort. */\nfunction compareValues(a: unknown, b: unknown, collator: Intl.Collator) {\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return Number(a) - Number(b);\n }\n return collator.compare(String(a), String(b));\n}\n\n/** Whether a filter value filters anything. */\nfunction isActiveFilter(value: unknown): boolean {\n return (\n value !== undefined &&\n value !== null &&\n value !== '' &&\n !(Array.isArray(value) && value.length === 0)\n );\n}\n\n/** A field a spreadsheet would read as the start of a formula. */\nconst formulaStart = /^[=+\\-@\\t\\r]/;\n/** A plain number, signed, with any grouping, which no spreadsheet runs. */\nconst plainNumber = /^[+-]?\\d[\\d.,]*$/;\n\n/**\n * One CSV field: a `'` in front of what would start a formula, then quoted\n * when it holds the delimiter, a quote or a line break, its quotes doubled.\n */\nfunction csvField(text: string, delimiter: string): string {\n const safe =\n formulaStart.test(text) && !plainNumber.test(text) ? `'${text}` : text;\n return safe.includes(delimiter) || /[\"\\r\\n]/.test(safe)\n ? `\"${safe.replace(/\"/g, '\"\"')}\"`\n : safe;\n}\n\n/**\n * Whether a search or a filter value is narrowing the rows. Used by\n * DataTable to tell an empty table from one with no matches.\n */\nexport function isFiltering(search: string, filters: DataTableFilters) {\n return search.trim() !== '' || Object.values(filters).some(isActiveFilter);\n}\n\n/** A row's id from its `id` property, or nothing when it has none. */\nfunction idOf(row: unknown): string | undefined {\n if (row === null || typeof row !== 'object') return undefined;\n const id = (row as { id?: unknown }).id;\n return id === undefined || id === null || id === '' ? undefined : String(id);\n}\n\n/**\n * A piece of state that's the caller's when they pass its value, and the\n * table's own otherwise. Setting it calls the change handler either way.\n *\n * It also returns `latest`, what a change should build on. While the table\n * holds the state, that's the value last set, even before React renders it,\n * so two changes in one handler build on each other. While the caller holds\n * it, it's the value as rendered, since only the caller knows what it made\n * of a change.\n */\nfunction useTableState<T>(\n value: T | undefined,\n initial: T,\n onChange: ((next: T) => void) | undefined\n): [T, (next: T) => void, () => T] {\n const [own, setOwn] = useState(initial);\n const held = value !== undefined;\n const current = held ? value : own;\n const rendered = useLatestRef(current);\n // A value set since the last commit, cleared once a commit shows it.\n const pendingRef = useRef<{ value: T } | null>(null);\n useClientLayoutEffect(() => {\n pendingRef.current = null;\n });\n const set = useCallback(\n (next: T) => {\n if (!held) {\n pendingRef.current = { value: next };\n setOwn(next);\n }\n onChange?.(next);\n },\n [held, onChange]\n );\n const latest = useCallback(\n () => (pendingRef.current ? pendingRef.current.value : rendered.current),\n [rendered]\n );\n return [current, set, latest];\n}\n\nconst noSort: DataTableSort[] = [];\nconst noIds: string[] = [];\nconst noFilters: DataTableFilters = {};\n\n/**\n * `useDataTable` holds a table's sort, selection, page, search and filters,\n * works out its rows, and hands out props for bestax's own table parts, so\n * custom markup behaves as `DataTable` does. Pass its result to\n * `<DataTable table={table} />` to render it with DataTable's own markup,\n * with a toolbar or an export button elsewhere on the page.\n *\n * @example\n * const table = useDataTable({ columns, data: users, pageSize: 10 });\n *\n * <DataTable table={table} caption=\"Users\" hasSearch />\n */\nexport function useDataTable<TRow>(\n options: UseDataTableOptions<TRow>\n): DataTableModel<TRow> {\n const {\n columns,\n data,\n getRowId: rowIdOf,\n sort: sortProp,\n defaultSort = noSort,\n onSortChange,\n selectionMode = 'none',\n selected: selectedProp,\n defaultSelected = noIds,\n onSelectedChange,\n pageSize: pageSizeProp,\n page: pageProp,\n defaultPage = 1,\n onPageChange,\n search: searchProp,\n defaultSearch = '',\n onSearchChange,\n filters: filtersProp,\n defaultFilters = noFilters,\n onFiltersChange,\n manual = false,\n rowCount: rowCountProp,\n labels,\n } = options;\n\n const [sort, setSort] = useTableState(sortProp, defaultSort, onSortChange);\n const [selected, setSelected, latestSelected] = useTableState(\n selectedProp,\n defaultSelected,\n onSelectedChange\n );\n const [pageState, setPageState, latestPage] = useTableState(\n pageProp,\n defaultPage,\n onPageChange\n );\n const [search, setSearchState] = useTableState(\n searchProp,\n defaultSearch,\n onSearchChange\n );\n const [filters, setFiltersState, latestFilters] = useTableState(\n filtersProp,\n defaultFilters,\n onFiltersChange\n );\n\n const prefix = useClassPrefix();\n const { locale } = useLocale();\n const matchText = useLocaleMatcher();\n const formatNumber = useScopedNumberFormat();\n const collator = useMemo(\n () => new Intl.Collator(locale, { numeric: true }),\n [locale]\n );\n\n const pageSize =\n pageSizeProp !== undefined &&\n Number.isFinite(pageSizeProp) &&\n pageSizeProp >= 1\n ? Math.floor(pageSizeProp)\n : undefined;\n\n const columnsById = useMemo(() => {\n const byId = new Map<string, DataTableColumn<TRow>>();\n for (const column of columns) {\n if (byId.has(column.id)) {\n warnOnce(\n 'DataTable:duplicate-column',\n `[bestax-bulma] DataTable has two columns with the id \"${column.id}\". ` +\n 'Give each column its own id: the sort, the filters and an export ' +\n 'find a column by it.'\n );\n } else {\n byId.set(column.id, column);\n }\n }\n return byId;\n }, [columns]);\n\n // Each row's id, by its index in `data`.\n const ids = useMemo(() => {\n const out = data.map((row, index) => {\n const id = rowIdOf ? rowIdOf(row, index) : idOf(row);\n if (id === undefined || id === '') {\n warnOnce(\n 'DataTable:missing-row-id',\n '[bestax-bulma] A DataTable row has no id, so it falls back to its ' +\n \"index, which doesn't survive the data changing. Give each row \" +\n 'an `id`, or pass `getRowId`.'\n );\n return String(index);\n }\n return id;\n });\n if (isDev() && new Set(out).size < out.length) {\n warnOnce(\n 'DataTable:duplicate-row-id',\n '[bestax-bulma] Two DataTable rows have the same id, so selecting ' +\n 'one selects both. Make the ids unique, or pass a `getRowId` ' +\n 'that does.'\n );\n }\n return out;\n }, [data, rowIdOf]);\n\n const indexOf = useMemo(() => {\n const map = new Map<TRow, number>();\n data.forEach((row, index) => {\n if (!map.has(row)) map.set(row, index);\n });\n return map;\n }, [data]);\n\n /** A row's id, from its index when the row is one of `data`. */\n const getRowId = useCallback(\n (row: TRow) => {\n const index = indexOf.get(row);\n if (index !== undefined) return ids[index];\n const id = rowIdOf ? rowIdOf(row, -1) : idOf(row);\n return id ?? '';\n },\n [indexOf, ids, rowIdOf]\n );\n\n // Every column's text for every row, worked out once per data and\n // columns, since the search reads them on every keystroke.\n const texts = useMemo(\n () => data.map(row => columns.map(column => readText(column, row))),\n [data, columns]\n );\n\n const sortedIndexes = useMemo(() => {\n const all = data.map((_, index) => index);\n if (manual) return all;\n const keys = sort\n .map(entry => ({\n column: columnsById.get(entry.id),\n descending: entry.direction === 'descending',\n }))\n .filter(\n (key): key is { column: DataTableColumn<TRow>; descending: boolean } =>\n key.column !== undefined\n );\n if (keys.length === 0) return all;\n const values = keys.map(({ column }) =>\n column.sortFn ? null : data.map(row => readValue(column, row))\n );\n return all.sort((x, y) => {\n for (let k = 0; k < keys.length; k++) {\n const { column, descending } = keys[k];\n let result: number;\n if (column.sortFn) {\n result = column.sortFn(data[x], data[y]);\n if (descending) result = -result;\n } else {\n const a = values[k]![x];\n const b = values[k]![y];\n const aEmpty = isEmptyValue(a);\n const bEmpty = isEmptyValue(b);\n if (aEmpty || bEmpty) {\n // Empty values go last whichever way the column sorts.\n result = Number(aEmpty) - Number(bEmpty);\n } else {\n result = compareValues(a, b, collator);\n if (descending) result = -result;\n }\n }\n if (result) return result;\n }\n // Ties keep the order of `data`.\n return x - y;\n });\n }, [data, sort, columnsById, collator, manual]);\n\n const filteredIndexes = useMemo(() => {\n if (manual) return sortedIndexes;\n const query = search.trim();\n const holds = matchText\n ? (text: string, needle: string) => matchText(text, needle)\n : (text: string, needle: string) =>\n text.toLowerCase().includes(needle.toLowerCase());\n const searched = columns\n .map((column, index) => ({ column, index }))\n .filter(({ column }) => column.filterable !== false);\n const filtered = Object.entries(filters)\n .filter(([, value]) => isActiveFilter(value))\n .map(([id, value]) => ({\n column: columnsById.get(id),\n index: columns.findIndex(column => column.id === id),\n value,\n }))\n .filter(\n ({ column }) => column !== undefined && column.filterable !== false\n );\n if (query === '' && filtered.length === 0) return sortedIndexes;\n return sortedIndexes.filter(rowIndex => {\n const row = data[rowIndex];\n const rowTexts = texts[rowIndex];\n for (const { column, index, value } of filtered) {\n // An array is any of its entries, as a multiple-choice filter gives.\n const passes = column!.filterFn\n ? column!.filterFn(row, value)\n : Array.isArray(value)\n ? value.some(entry => holds(rowTexts[index], String(entry)))\n : holds(rowTexts[index], String(value));\n if (!passes) return false;\n }\n return (\n query === '' ||\n searched.some(({ index }) => holds(rowTexts[index], query))\n );\n });\n }, [\n manual,\n sortedIndexes,\n search,\n filters,\n matchText,\n columns,\n columnsById,\n data,\n texts,\n ]);\n\n const knowsCount =\n rowCountProp !== undefined && Number.isFinite(rowCountProp);\n if (manual && pageSize !== undefined && !knowsCount) {\n warnOnce(\n 'DataTable:manual-row-count',\n '[bestax-bulma] A DataTable with `manual` and a `pageSize` has no ' +\n '`rowCount`, so it counts only the rows in `data`, makes one page ' +\n 'of them and shows no pager. Pass `rowCount`, how many rows match ' +\n 'on the server.'\n );\n }\n const rowCount = manual\n ? Math.max(\n Math.floor(knowsCount ? (rowCountProp as number) : data.length),\n 0\n )\n : filteredIndexes.length;\n const pageCount = pageSize ? Math.max(Math.ceil(rowCount / pageSize), 1) : 1;\n const page = Math.min(\n Math.max(Number.isFinite(pageState) ? Math.floor(pageState) : 1, 1),\n pageCount\n );\n\n const pageIndexes = useMemo(() => {\n if (manual || !pageSize) return filteredIndexes;\n return filteredIndexes.slice((page - 1) * pageSize, page * pageSize);\n }, [manual, pageSize, filteredIndexes, page]);\n\n const selectedSet = useMemo(() => new Set(selected), [selected]);\n const selectable = selectionMode === 'multiple';\n\n const rowsOf = useCallback(\n (indexes: number[]) => indexes.map(index => data[index]),\n [data]\n );\n\n const getRows = useCallback(\n (scope: DataTableRowScope = 'filtered') => {\n switch (scope) {\n case 'all':\n return rowsOf(sortedIndexes);\n case 'page':\n return rowsOf(pageIndexes);\n case 'selected':\n return rowsOf(\n filteredIndexes.filter(index => selectedSet.has(ids[index]))\n );\n default:\n return rowsOf(filteredIndexes);\n }\n },\n [rowsOf, sortedIndexes, pageIndexes, filteredIndexes, selectedSet, ids]\n );\n\n const getValue = useCallback(\n (row: TRow, columnId: string) => {\n const column = columnsById.get(columnId);\n return column ? readValue(column, row) : undefined;\n },\n [columnsById]\n );\n\n const getText = useCallback(\n (row: TRow, columnId: string) => {\n const column = columnsById.get(columnId);\n if (!column) return '';\n const index = indexOf.get(row);\n return index !== undefined\n ? texts[index][columns.indexOf(column)]\n : readText(column, row);\n },\n [columnsById, indexOf, columns, texts]\n );\n\n const labelColumn = columns.find(column => column.isRowHeader) ?? columns[0];\n const getRowLabel = useCallback(\n (row: TRow) =>\n (labelColumn && getText(row, labelColumn.id)) || getRowId(row),\n [labelColumn, getText, getRowId]\n );\n\n const isSelected = useCallback(\n (row: TRow) => selectable && selectedSet.has(getRowId(row)),\n [selectable, selectedSet, getRowId]\n );\n\n const setPage = useCallback(\n (next: number) => {\n if (next !== page) setPageState(next);\n },\n [page, setPageState]\n );\n\n // A new search or filter starts from the first page. It's measured against\n // the page as stored, not as shown: a page past the end shows the last,\n // and left stored it would come back once the rows grew again.\n const resetPage = useCallback(() => {\n if (latestPage() !== 1) setPageState(1);\n }, [latestPage, setPageState]);\n\n const setSearch = useCallback(\n (next: string) => {\n setSearchState(next);\n resetPage();\n },\n [setSearchState, resetPage]\n );\n\n const setFilters = useCallback(\n (next: DataTableFilters) => {\n setFiltersState(next);\n resetPage();\n },\n [setFiltersState, resetPage]\n );\n\n const setFilter = useCallback(\n (columnId: string, value: unknown) => {\n const next = { ...latestFilters() };\n if (isActiveFilter(value)) next[columnId] = value;\n else delete next[columnId];\n setFilters(next);\n },\n [latestFilters, setFilters]\n );\n\n const toggleSort = useCallback(\n (columnId: string) => {\n const column = columnsById.get(columnId);\n if (!column) return;\n const first: DataTableSortDirection = column.sortDescFirst\n ? 'descending'\n : 'ascending';\n const current = sort[0]?.id === columnId ? sort[0].direction : undefined;\n if (current === undefined) {\n setSort([{ id: columnId, direction: first }]);\n } else if (current === first) {\n setSort([\n {\n id: columnId,\n direction: first === 'ascending' ? 'descending' : 'ascending',\n },\n ]);\n } else {\n setSort([]);\n }\n },\n [columnsById, sort, setSort]\n );\n\n const toggleRowSelected = useCallback(\n (row: TRow, value?: boolean) => {\n const id = getRowId(row);\n const current = latestSelected();\n const has = current.includes(id);\n const on = value ?? !has;\n if (on === has) return;\n setSelected(on ? [...current, id] : current.filter(s => s !== id));\n },\n [getRowId, latestSelected, setSelected]\n );\n\n const pageIds = useMemo(\n () => pageIndexes.map(index => ids[index]),\n [pageIndexes, ids]\n );\n const pageSelectedCount = pageIds.filter(id => selectedSet.has(id)).length;\n const allPageSelected =\n pageIds.length > 0 && pageSelectedCount === pageIds.length;\n\n const togglePageSelected = useCallback(\n (value?: boolean) => {\n const current = latestSelected();\n const has = new Set(current);\n const on =\n value ?? !(pageIds.length > 0 && pageIds.every(id => has.has(id)));\n if (on) {\n const adding = pageIds.filter(id => !has.has(id));\n if (adding.length > 0) setSelected([...current, ...adding]);\n } else {\n const onPage = new Set(pageIds);\n const kept = current.filter(id => !onPage.has(id));\n if (kept.length !== current.length) setSelected(kept);\n }\n },\n [latestSelected, pageIds, setSelected]\n );\n\n const count = useCallback(\n (value: number) => (formatNumber ? formatNumber(value) : String(value)),\n [formatNumber]\n );\n\n const resolvedLabels: DataTableResolvedLabels = {\n selectAll:\n labels?.selectAll ||\n (pageCount > 1 ? 'Select all rows on this page' : 'Select all rows'),\n selectRow: labels?.selectRow ?? (label => `Select ${label}`),\n sortHint: labels?.sortHint || 'column headers with buttons are sortable',\n search: labels?.search || 'Search',\n results:\n labels?.results ??\n (total =>\n total === 0\n ? 'No rows match'\n : `${count(total)} ${total === 1 ? 'row matches' : 'rows match'}`),\n pageRange:\n labels?.pageRange ??\n ((first, last, total) =>\n `Showing ${count(first)} to ${count(last)} of ${count(total)}`),\n loading: labels?.loading || 'Loading',\n pagination: labels?.pagination || undefined,\n empty: labels?.empty || 'No rows to show.',\n noResults: labels?.noResults || 'No rows match.',\n };\n\n const toCSV = useCallback(\n ({\n rows = 'filtered',\n columns: ids,\n header = true,\n delimiter = ',',\n }: DataTableCSVOptions = {}) => {\n const written = ids\n ? ids\n .map(id => columnsById.get(id))\n .filter(\n (column): column is DataTableColumn<TRow> => column !== undefined\n )\n : columns;\n const line = (fields: string[]) =>\n fields.map(field => csvField(field, delimiter)).join(delimiter);\n const lines = getRows(rows).map(row =>\n line(written.map(column => getText(row, column.id)))\n );\n if (header) lines.unshift(line(written.map(column => column.header)));\n return lines.join('\\r\\n');\n },\n [columnsById, columns, getRows, getText]\n );\n\n const sortButtonClass = prefixedClassNames(prefix, 'data-table-sort');\n\n return {\n columns,\n state: { sort, selected, page, pageSize, search, filters },\n selectionMode,\n manual,\n rowCount,\n pageCount,\n labels: resolvedLabels,\n getRows,\n getRowId,\n getValue,\n getText,\n getRowLabel,\n toCSV,\n isSelected,\n setSort,\n toggleSort,\n setSelected,\n toggleRowSelected,\n togglePageSelected,\n setPage,\n setSearch,\n setFilter,\n setFilters,\n getHeaderCellProps: column => ({\n scope: 'col',\n 'aria-sort': sort[0]?.id === column.id ? sort[0].direction : undefined,\n isAligned: column.align,\n width: column.width,\n }),\n getSortButtonProps: column => ({\n type: 'button',\n className: sortButtonClass,\n onClick: () => toggleSort(column.id),\n }),\n getRowProps: row => ({ isSelected: isSelected(row) }),\n getCellProps: (_row, column) => ({\n scope: column.isRowHeader ? 'row' : undefined,\n isAligned: column.align,\n }),\n getSelectAllProps: () => ({\n 'aria-label': resolvedLabels.selectAll,\n checked: allPageSelected,\n indeterminate: pageSelectedCount > 0 && !allPageSelected,\n disabled: pageIds.length === 0,\n onChange: () => togglePageSelected(),\n }),\n getSelectRowProps: row => ({\n 'aria-label': resolvedLabels.selectRow(getRowLabel(row)),\n checked: selectedSet.has(getRowId(row)),\n onChange: () => toggleRowSelected(row),\n }),\n getPaginationProps: () => ({\n total: pageCount,\n current: page,\n onPageChange: setPage,\n }),\n getSearchProps: () => ({\n type: 'search',\n value: search,\n onChange: event => setSearch(event.target.value),\n }),\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
4
4
|
import { usePrefixedClassNames, classNames } from '../helpers/classNames.js';
|
|
5
5
|
import { withSubComponents } from '../helpers/withSubComponents.js';
|
|
6
6
|
import { Button } from './Button.js';
|
|
7
|
+
import { IconButton } from './IconButton.js';
|
|
7
8
|
import { LinkButton } from './LinkButton.js';
|
|
8
9
|
import { ToggleButton } from './ToggleButton.js';
|
|
9
10
|
import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
|
|
@@ -39,6 +40,7 @@ const Buttons = withSubComponents(ButtonsComponent, {
|
|
|
39
40
|
Button,
|
|
40
41
|
LinkButton,
|
|
41
42
|
ToggleButton,
|
|
43
|
+
IconButton,
|
|
42
44
|
}, 'Buttons');
|
|
43
45
|
|
|
44
46
|
export { Buttons };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Buttons.js","sources":["../../../src/elements/Buttons.tsx"],"sourcesContent":["import React from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { Button } from './Button';\nimport { LinkButton } from './LinkButton';\nimport { ToggleButton } from './ToggleButton';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\n\nconst validButtonsSizes = ['small', 'medium', 'large'] as const;\n/**\n * Valid size values for the Buttons component (Bulma button group sizes).\n */\nexport type ButtonsSize = (typeof validButtonsSizes)[number];\n\n/**\n * Props for the Buttons component.\n */\nexport interface ButtonsProps\n extends\n React.HTMLAttributes<HTMLDivElement>,\n Omit<BulmaClassesProps, 'size'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /** Text color helper for the button group. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /**\n * Text color alias: renders `has-text-<color>`, exactly like `textColor`.\n * Not a filled variant (no `.buttons.is-<color>` CSS exists; color the\n * individual `Button`s instead). Prefer `textColor`, which takes precedence\n * when both are set; use `bgColor` for a colored surface.\n */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color helper for the button group. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Center the group of buttons. */\n isCentered?: boolean;\n /** Align the group of buttons to the right. */\n isRight?: boolean;\n /** Group buttons together as addons (removes spacing between them). */\n hasAddons?: boolean;\n /** Size of the button group. */\n size?: ButtonsSize;\n /** The button elements to render inside the group. */\n children: React.ReactNode;\n}\n\n/**\n * The `Buttons` component lets you group multiple `Button` elements together with Bulma's spacing, alignment, and add-on features.\n *\n * @function\n * @param {ButtonsProps} props - Props for the Buttons component.\n * @returns {JSX.Element} The rendered group of buttons.\n * @see {@link https://bulma.io/documentation/elements/button/#group | Bulma Button Group documentation}\n */\nconst ButtonsComponent: React.FC<ButtonsProps> = ({\n className,\n textColor,\n color,\n bgColor,\n isCentered,\n isRight,\n hasAddons,\n size,\n children,\n ...props\n}) => {\n const buttonsClasses = usePrefixedClassNames('buttons', {\n 'is-centered': isCentered,\n 'is-right': isRight,\n 'has-addons': hasAddons,\n [`are-${size}`]: size && validButtonsSizes.includes(size),\n });\n\n /**\n * Generates Bulma helper classes and separates out remaining props.\n */\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor ?? color,\n backgroundColor: bgColor,\n ...props,\n });\n\n const combinedClasses = classNames(\n buttonsClasses,\n className,\n bulmaHelperClasses\n );\n\n return (\n <div className={combinedClasses} {...rest}>\n {children}\n </div>\n );\n};\n\nexport const Buttons = withSubComponents(\n ButtonsComponent,\n {\n Button,\n LinkButton,\n ToggleButton,\n },\n 'Buttons'\n);\n"],"names":["_jsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Buttons.js","sources":["../../../src/elements/Buttons.tsx"],"sourcesContent":["import React from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { Button } from './Button';\nimport { IconButton } from './IconButton';\nimport { LinkButton } from './LinkButton';\nimport { ToggleButton } from './ToggleButton';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\n\nconst validButtonsSizes = ['small', 'medium', 'large'] as const;\n/**\n * Valid size values for the Buttons component (Bulma button group sizes).\n */\nexport type ButtonsSize = (typeof validButtonsSizes)[number];\n\n/**\n * Props for the Buttons component.\n */\nexport interface ButtonsProps\n extends\n React.HTMLAttributes<HTMLDivElement>,\n Omit<BulmaClassesProps, 'size'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /** Text color helper for the button group. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /**\n * Text color alias: renders `has-text-<color>`, exactly like `textColor`.\n * Not a filled variant (no `.buttons.is-<color>` CSS exists; color the\n * individual `Button`s instead). Prefer `textColor`, which takes precedence\n * when both are set; use `bgColor` for a colored surface.\n */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color helper for the button group. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Center the group of buttons. */\n isCentered?: boolean;\n /** Align the group of buttons to the right. */\n isRight?: boolean;\n /** Group buttons together as addons (removes spacing between them). */\n hasAddons?: boolean;\n /** Size of the button group. */\n size?: ButtonsSize;\n /** The button elements to render inside the group. */\n children: React.ReactNode;\n}\n\n/**\n * The `Buttons` component lets you group multiple `Button` elements together with Bulma's spacing, alignment, and add-on features.\n *\n * @function\n * @param {ButtonsProps} props - Props for the Buttons component.\n * @returns {JSX.Element} The rendered group of buttons.\n * @see {@link https://bulma.io/documentation/elements/button/#group | Bulma Button Group documentation}\n */\nconst ButtonsComponent: React.FC<ButtonsProps> = ({\n className,\n textColor,\n color,\n bgColor,\n isCentered,\n isRight,\n hasAddons,\n size,\n children,\n ...props\n}) => {\n const buttonsClasses = usePrefixedClassNames('buttons', {\n 'is-centered': isCentered,\n 'is-right': isRight,\n 'has-addons': hasAddons,\n [`are-${size}`]: size && validButtonsSizes.includes(size),\n });\n\n /**\n * Generates Bulma helper classes and separates out remaining props.\n */\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor ?? color,\n backgroundColor: bgColor,\n ...props,\n });\n\n const combinedClasses = classNames(\n buttonsClasses,\n className,\n bulmaHelperClasses\n );\n\n return (\n <div className={combinedClasses} {...rest}>\n {children}\n </div>\n );\n};\n\nexport const Buttons = withSubComponents(\n ButtonsComponent,\n {\n Button,\n LinkButton,\n ToggleButton,\n IconButton,\n },\n 'Buttons'\n);\n"],"names":["_jsx"],"mappings":";;;;;;;;;;;AAaA,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAU;AAsC/D;;;;;;;AAOG;AACH,MAAM,gBAAgB,GAA2B,CAAC,EAChD,SAAS,EACT,SAAS,EACT,KAAK,EACL,OAAO,EACP,UAAU,EACV,OAAO,EACP,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,GAAG,KAAK,EACT,KAAI;AACH,IAAA,MAAM,cAAc,GAAG,qBAAqB,CAAC,SAAS,EAAE;AACtD,QAAA,aAAa,EAAE,UAAU;AACzB,QAAA,UAAU,EAAE,OAAO;AACnB,QAAA,YAAY,EAAE,SAAS;AACvB,QAAA,CAAC,CAAA,IAAA,EAAO,IAAI,CAAA,CAAE,GAAG,IAAI,IAAI,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC1D,KAAA,CAAC;AAEF;;AAEG;AACH,IAAA,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC;QACnD,KAAK,EAAE,SAAS,IAAI,KAAK;AACzB,QAAA,eAAe,EAAE,OAAO;AACxB,QAAA,GAAG,KAAK;AACT,KAAA,CAAC;IAEF,MAAM,eAAe,GAAG,UAAU,CAChC,cAAc,EACd,SAAS,EACT,kBAAkB,CACnB;IAED,QACEA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,eAAe,EAAA,GAAM,IAAI,EAAA,QAAA,EACtC,QAAQ,EAAA,CACL;AAEV,CAAC;AAEM,MAAM,OAAO,GAAG,iBAAiB,CACtC,gBAAgB,EAChB;IACE,MAAM;IACN,UAAU;IACV,YAAY;IACZ,UAAU;CACX,EACD,SAAS;;"}
|