@allxsmith/bestax-bulma 5.62.0 → 5.64.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/EmptyState.js +2 -6
- package/dist/esm/components/EmptyState.js.map +1 -1
- package/dist/esm/components/ScrollArea.js +7 -7
- package/dist/esm/components/ScrollArea.js.map +1 -1
- package/dist/esm/components/TableOfContents.js +85 -0
- package/dist/esm/components/TableOfContents.js.map +1 -0
- package/dist/esm/components/Timeline.js +5 -9
- package/dist/esm/components/Timeline.js.map +1 -1
- package/dist/esm/components/TreeView.js +3 -7
- package/dist/esm/components/TreeView.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/CopyButton.js +132 -0
- package/dist/esm/elements/CopyButton.js.map +1 -0
- package/dist/esm/elements/DescriptionList.js +1 -5
- package/dist/esm/elements/DescriptionList.js.map +1 -1
- package/dist/esm/elements/Stat.js +196 -0
- package/dist/esm/elements/Stat.js.map +1 -0
- package/dist/esm/elements/Stats.js +48 -0
- package/dist/esm/elements/Stats.js.map +1 -0
- package/dist/esm/elements/statContext.js +10 -0
- package/dist/esm/elements/statContext.js.map +1 -0
- package/dist/esm/form/Combobox.js +2 -1
- package/dist/esm/form/Combobox.js.map +1 -1
- package/dist/esm/form/PasswordInput.js +105 -0
- package/dist/esm/form/PasswordInput.js.map +1 -0
- package/dist/esm/form/PasswordInputBase.js +177 -0
- package/dist/esm/form/PasswordInputBase.js.map +1 -0
- package/dist/esm/helpers/checkIcon.js +20 -0
- package/dist/esm/helpers/checkIcon.js.map +1 -0
- package/dist/esm/helpers/isGiven.js +13 -0
- package/dist/esm/helpers/isGiven.js.map +1 -0
- package/dist/esm/helpers/statusRegion.js +3 -3
- package/dist/esm/helpers/useClipboard.js +176 -0
- package/dist/esm/helpers/useClipboard.js.map +1 -0
- package/dist/esm/helpers/useScrollSpy.js +286 -0
- package/dist/esm/helpers/useScrollSpy.js.map +1 -0
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +2671 -1544
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +8 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/TableOfContents.d.ts +87 -0
- package/dist/types/elements/Buttons.d.ts +1 -0
- package/dist/types/elements/CopyButton.d.ts +105 -0
- package/dist/types/elements/Stat.d.ts +242 -0
- package/dist/types/elements/Stats.d.ts +40 -0
- package/dist/types/elements/statContext.d.ts +18 -0
- package/dist/types/form/PasswordInput.d.ts +98 -0
- package/dist/types/form/PasswordInputBase.d.ts +91 -0
- package/dist/types/helpers/checkIcon.d.ts +10 -0
- package/dist/types/helpers/isGiven.d.ts +7 -0
- package/dist/types/helpers/useClipboard.d.ts +65 -0
- package/dist/types/helpers/useScrollSpy.d.ts +61 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types-cjs/components/TableOfContents.d.ts +87 -0
- package/dist/types-cjs/elements/Buttons.d.ts +1 -0
- package/dist/types-cjs/elements/CopyButton.d.ts +105 -0
- package/dist/types-cjs/elements/Stat.d.ts +242 -0
- package/dist/types-cjs/elements/Stats.d.ts +40 -0
- package/dist/types-cjs/elements/statContext.d.ts +18 -0
- package/dist/types-cjs/form/PasswordInput.d.ts +98 -0
- package/dist/types-cjs/form/PasswordInputBase.d.ts +91 -0
- package/dist/types-cjs/helpers/checkIcon.d.ts +10 -0
- package/dist/types-cjs/helpers/isGiven.d.ts +7 -0
- package/dist/types-cjs/helpers/useClipboard.d.ts +65 -0
- package/dist/types-cjs/helpers/useScrollSpy.d.ts +61 -0
- package/dist/types-cjs/index.d.ts +10 -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/CLAUDE.md +3 -0
- package/src/scss/_input-trigger.scss +76 -0
- package/src/scss/components/_index.scss +1 -0
- package/src/scss/components/_tableofcontents.scss +42 -0
- package/src/scss/elements/_index.scss +1 -0
- package/src/scss/elements/_stat.scss +153 -0
- package/src/scss/form/_index.scss +1 -0
- package/src/scss/form/_passwordinput.scss +112 -0
- package/src/scss/form/_picker-popover.scss +24 -63
|
@@ -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 {\n TreeViewHiddenContext,\n useTreeView,\n type TreeViewEngine,\n} 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 // Hidden by a component around the tree, such as TreeSelect's search,\n // it renders as an item under a closed parent does.\n const hiddenItems = useContext(TreeViewHiddenContext);\n const hiddenHere = branch.hidden || hiddenItems.has(value);\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 && !hiddenHere;\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: hiddenHere || !open,\n }),\n [branch, value, hiddenHere, 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 or hidden too, drawing nothing, so a\n // check knows what's under it.\n const items = (shown || tree.rendersClosed) && (\n <BranchContext.Provider value={childBranch}>\n {children}\n </BranchContext.Provider>\n );\n if (hiddenHere) 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":["ignoreChange","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 {\n TreeViewHiddenContext,\n useTreeView,\n type TreeViewEngine,\n} from '../helpers/useTreeView';\nimport { StatusRegion, spokenText } from '../helpers/statusRegion';\nimport { Checkbox } from '../form/Checkbox';\nimport { Icon } from '../elements/Icon';\nimport { isGiven } from '../helpers/isGiven';\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/**\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 // Hidden by a component around the tree, such as TreeSelect's search,\n // it renders as an item under a closed parent does.\n const hiddenItems = useContext(TreeViewHiddenContext);\n const hiddenHere = branch.hidden || hiddenItems.has(value);\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 && !hiddenHere;\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: hiddenHere || !open,\n }),\n [branch, value, hiddenHere, 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 or hidden too, drawing nothing, so a\n // check knows what's under it.\n const items = (shown || tree.rendersClosed) && (\n <BranchContext.Provider value={childBranch}>\n {children}\n </BranchContext.Provider>\n );\n if (hiddenHere) 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":["ignoreChange","_jsxs","_jsx","_Fragment"],"mappings":";;;;;;;;;;;;;;;AAmCA,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,MAAMA,cAAY,GAAG,MAAK,EAAE,CAAC;AA+J7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;;;AAGxC,IAAA,MAAM,WAAW,GAAG,UAAU,CAAC,qBAAqB,CAAC;AACrD,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;;AAE1D,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;;AAG1D,IAAA,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,UAAU;IACjC,MAAM,MAAM,GAAG,CAAC;AACd,UAAE;AACF,UAAE;AACA,cAAE;AACF,cAAE,OAAO,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,UAAU,IAAI,CAAC,IAAI;KAC5B,CAAC,EACF,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,CAClC;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,KAAK,IAAI,IAAI,CAAC,aAAa,MACxCA,IAAC,aAAa,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,WAAW,EAAA,QAAA,EACvC,QAAQ,EAAA,CACc,CAC1B;AACD,IAAA,IAAI,UAAU;QAAE,OAAOA,GAAA,CAAAC,QAAA,EAAA,EAAA,QAAA,EAAG,KAAK,EAAA,CAAI;AAEnC,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,EAAEF,cAAY,EAAA,CACtB,GACG,CACR,EACA,OAAO,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;;"}
|
|
@@ -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 { CopyButton } from './CopyButton.js';
|
|
7
8
|
import { IconButton } from './IconButton.js';
|
|
8
9
|
import { LinkButton } from './LinkButton.js';
|
|
9
10
|
import { ToggleButton } from './ToggleButton.js';
|
|
@@ -41,6 +42,7 @@ const Buttons = withSubComponents(ButtonsComponent, {
|
|
|
41
42
|
LinkButton,
|
|
42
43
|
ToggleButton,
|
|
43
44
|
IconButton,
|
|
45
|
+
CopyButton,
|
|
44
46
|
}, 'Buttons');
|
|
45
47
|
|
|
46
48
|
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 { 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":"
|
|
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 { CopyButton } from './CopyButton';\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 CopyButton,\n },\n 'Buttons'\n);\n"],"names":["_jsx"],"mappings":";;;;;;;;;;;;AAcA,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;IACV,UAAU;CACX,EACD,SAAS;;"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
'use client';
|
|
3
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import { forwardRef, useState, useRef } from 'react';
|
|
5
|
+
import { Button } from './Button.js';
|
|
6
|
+
import { Icon } from './Icon.js';
|
|
7
|
+
import { IconButton } from './IconButton.js';
|
|
8
|
+
import { buttonType } from '../helpers/buttonType.js';
|
|
9
|
+
import { CheckIcon } from '../helpers/checkIcon.js';
|
|
10
|
+
import { Portal } from '../helpers/portal.js';
|
|
11
|
+
import { StatusRegion } from '../helpers/statusRegion.js';
|
|
12
|
+
import { useClipboard } from '../helpers/useClipboard.js';
|
|
13
|
+
|
|
14
|
+
/** Two sheets, one over the other. */
|
|
15
|
+
const CopyGlyph = () => (jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinejoin: "round", width: "1em", height: "1em", focusable: "false", children: [jsx("path", { d: "M10.5 3.5v-1a1 1 0 0 0-1-1h-6a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h1" }), jsx("rect", { x: "5.5", y: "5.5", width: "8", height: "9", rx: "1" })] }));
|
|
16
|
+
const describeAnnouncement$1 = (announcement) => announcement.text;
|
|
17
|
+
const noAnnouncements$1 = [];
|
|
18
|
+
/** What marks an open modal dialog in ARIA. */
|
|
19
|
+
const modalDialog = '[aria-modal="true"]';
|
|
20
|
+
/**
|
|
21
|
+
* The open modal dialog an element is in: one marked `aria-modal="true"`, or
|
|
22
|
+
* a `<dialog>` opened with `showModal()`, which makes the rest of the page
|
|
23
|
+
* inert. An engine without the `:modal` selector throws on the whole list,
|
|
24
|
+
* so it then looks for the ARIA alone.
|
|
25
|
+
*
|
|
26
|
+
* @param element - Where to look up from.
|
|
27
|
+
* @returns The nearest open modal dialog around it, or `null`.
|
|
28
|
+
*/
|
|
29
|
+
function closestModalDialog(element) {
|
|
30
|
+
try {
|
|
31
|
+
return element.closest(`${modalDialog}, dialog:modal`);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return element.closest(modalDialog);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The `CopyButton` component renders a button that copies a piece of text to the clipboard, says "Copied" for a moment, and announces the result.
|
|
39
|
+
*
|
|
40
|
+
* It's a `Button` with a copy icon and "Copy", and takes everything `Button`
|
|
41
|
+
* takes. A click writes `value` through the Clipboard API, or through the
|
|
42
|
+
* older copy command where that's missing or refused, and reports a failure
|
|
43
|
+
* rather than showing "Copied". Each outcome is announced through a polite
|
|
44
|
+
* status region portaled out of the button's place, so it stays the last
|
|
45
|
+
* child of a `Control` or `Buttons`: into the open modal dialog the button is
|
|
46
|
+
* in, otherwise where `Portal` puts portaled content (the `ConfigProvider`'s
|
|
47
|
+
* `portalContainer`, or the end of the page). With `showLabel={false}` it's an
|
|
48
|
+
* `IconButton`. For a trigger of your own, use `useClipboard`, which it's
|
|
49
|
+
* built on.
|
|
50
|
+
*
|
|
51
|
+
* @function
|
|
52
|
+
* @param {CopyButtonProps} props - Props for the CopyButton component.
|
|
53
|
+
* @param {React.Ref<HTMLButtonElement>} ref - Forwarded ref to the `<button>`.
|
|
54
|
+
* @returns {JSX.Element} The rendered button.
|
|
55
|
+
* @see {@link https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html | WCAG 4.1.3 Status Messages}
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* <CopyButton value="https://bestax.io" />
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* <CopyButton value={apiKey} showLabel={false} size="small" />
|
|
62
|
+
*/
|
|
63
|
+
const CopyButton = forwardRef(function CopyButton({ value, duration = 2000, showLabel = true, labels, onCopiedChange, onCopyError, onClick, onFocus, ...props }, ref) {
|
|
64
|
+
const copyLabel = labels?.copy || 'Copy';
|
|
65
|
+
const copiedLabel = labels?.copied || 'Copied';
|
|
66
|
+
const copiedStatus = labels?.copiedStatus || 'Copied to the clipboard';
|
|
67
|
+
const failedStatus = labels?.failedStatus || "Couldn't copy to the clipboard";
|
|
68
|
+
// The latest outcome. Each gets a new id, so the region announces a
|
|
69
|
+
// repeat too.
|
|
70
|
+
const [announcements, setAnnouncements] = useState(noAnnouncements$1);
|
|
71
|
+
const countRef = useRef(0);
|
|
72
|
+
const announce = (text) => {
|
|
73
|
+
countRef.current += 1;
|
|
74
|
+
setAnnouncements([{ id: String(countRef.current), text }]);
|
|
75
|
+
};
|
|
76
|
+
// The open modal dialog the button is in, which the region goes inside:
|
|
77
|
+
// a screen reader ignores a live region behind one. It's looked up when
|
|
78
|
+
// the button takes focus or a click, rather than once as it mounts,
|
|
79
|
+
// since Modal and Sidebar keep their content mounted while closed, and
|
|
80
|
+
// only an open one is `aria-modal`. A region that moves starts empty, so
|
|
81
|
+
// it doesn't say the last outcome again. This lookup can go once the
|
|
82
|
+
// overlays hand their content their own root as its portal container
|
|
83
|
+
// (#1471).
|
|
84
|
+
const [dialog, setDialog] = useState(null);
|
|
85
|
+
const placeRegion = (button) => {
|
|
86
|
+
const next = closestModalDialog(button);
|
|
87
|
+
if (next === dialog)
|
|
88
|
+
return;
|
|
89
|
+
setDialog(next);
|
|
90
|
+
setAnnouncements(noAnnouncements$1);
|
|
91
|
+
};
|
|
92
|
+
// The hook fires nothing once this has unmounted, so neither does the
|
|
93
|
+
// announcement.
|
|
94
|
+
const { copy, copied } = useClipboard({
|
|
95
|
+
duration,
|
|
96
|
+
onCopiedChange: next => {
|
|
97
|
+
if (next)
|
|
98
|
+
announce(copiedStatus);
|
|
99
|
+
onCopiedChange?.(next);
|
|
100
|
+
},
|
|
101
|
+
onCopyError: error => {
|
|
102
|
+
announce(failedStatus);
|
|
103
|
+
onCopyError?.(error);
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
// The caller's onClick runs first, so a `preventDefault()` there stops
|
|
107
|
+
// the copy, as it stops ToggleButton's toggle.
|
|
108
|
+
const handleClick = (event) => {
|
|
109
|
+
onClick?.(event);
|
|
110
|
+
if (event.defaultPrevented)
|
|
111
|
+
return;
|
|
112
|
+
placeRegion(event.currentTarget);
|
|
113
|
+
void copy(value);
|
|
114
|
+
};
|
|
115
|
+
const handleFocus = (event) => {
|
|
116
|
+
onFocus?.(event);
|
|
117
|
+
placeRegion(event.currentTarget);
|
|
118
|
+
};
|
|
119
|
+
const glyph = jsx(Icon, { children: copied ? jsx(CheckIcon, {}) : jsx(CopyGlyph, {}) });
|
|
120
|
+
// The props are spread first, so it stays a `<button>` that doesn't
|
|
121
|
+
// submit by accident, whatever a JavaScript caller or a spread object
|
|
122
|
+
// passes along.
|
|
123
|
+
const button = showLabel ? (jsxs(Button, { ...props, ref: ref, as: "button", type: buttonType(props.type), onClick: handleClick, onFocus: handleFocus, children: [glyph, jsx("span", { children: copied ? copiedLabel : copyLabel })] })) : (jsx(IconButton, { ...{
|
|
124
|
+
...props,
|
|
125
|
+
'aria-label': props['aria-label'] || copyLabel,
|
|
126
|
+
}, ref: ref, as: "button", onClick: handleClick, onFocus: handleFocus, children: glyph }));
|
|
127
|
+
return (jsxs(Fragment, { children: [button, jsx(Portal, { container: dialog || undefined, children: jsx(StatusRegion, { items: announcements, describe: describeAnnouncement$1 }) })] }));
|
|
128
|
+
});
|
|
129
|
+
CopyButton.displayName = 'CopyButton';
|
|
130
|
+
|
|
131
|
+
export { CopyButton };
|
|
132
|
+
//# sourceMappingURL=CopyButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CopyButton.js","sources":["../../../src/elements/CopyButton.tsx"],"sourcesContent":["import React, { forwardRef, useRef, useState } from 'react';\nimport { Button, type ButtonOwnProps } from './Button';\nimport { Icon } from './Icon';\nimport { IconButton, type IconButtonProps } from './IconButton';\nimport { buttonType } from '../helpers/buttonType';\nimport { CheckIcon } from '../helpers/checkIcon';\nimport { Portal } from '../helpers/portal';\nimport { StatusRegion } from '../helpers/statusRegion';\nimport { useClipboard } from '../helpers/useClipboard';\n\n/**\n * The strings CopyButton shows and announces, each with an English default. A\n * key left out, or set to an empty string, keeps its default.\n */\nexport interface CopyButtonLabels {\n /**\n * The button's label, and so its name, until a copy. With `showLabel` off\n * it's the name in both states, given as `aria-label`.\n * @defaultValue 'Copy'\n */\n copy?: string;\n /**\n * The label shown for `duration` after a copy, and so the name meanwhile.\n * Not used with `showLabel` off, where only the glyph changes.\n * @defaultValue 'Copied'\n */\n copied?: string;\n /**\n * Announced after a copy.\n * @defaultValue 'Copied to the clipboard'\n */\n copiedStatus?: string;\n /**\n * Announced when the copy fails.\n * @defaultValue \"Couldn't copy to the clipboard\"\n */\n failedStatus?: string;\n}\n\n/**\n * Props for the CopyButton component. The helper props, the other button\n * attributes and the `ref` land on the `<button>`.\n *\n * @extraProp {'button' | 'submit' | 'reset'} [type=button] - `button` unless you pass `submit` or `reset`.\n * @extraProp {React.MouseEventHandler<HTMLButtonElement>} [onClick] - Runs before the copy. An `onClick` that calls `preventDefault()` stops the copy, and neither `onCopiedChange` nor `onCopyError` fires.\n * @extraProp {React.Ref<HTMLButtonElement>} [ref] - Ref forwarded to the `<button>`.\n */\nexport interface CopyButtonProps\n extends\n Omit<ButtonOwnProps, 'children'>,\n Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n keyof ButtonOwnProps | 'value'\n > {\n /**\n * The text it copies. This is not the `<button>`'s form value, which it\n * doesn't render.\n */\n value: string;\n /**\n * How long the \"Copied\" label stays, in milliseconds. Another copy\n * restarts it. `0` turns the reset off, as Toast's `0` turns off its\n * auto-close, so \"Copied\" stays until a later copy fails. A missing or `NaN`\n * value uses the default, a negative one ends it at once, and `Infinity`,\n * or anything longer than the longest delay `setTimeout` takes (about 24.8\n * days), is that longest delay.\n * @defaultValue 2000\n */\n duration?: number;\n /**\n * Shows the label beside the icon, which is then the button's name: it\n * carries no `aria-label`, so the name reads \"Copy\" and then \"Copied\" as\n * the words on it do. Turned off, it's a square icon-only button named by\n * `labels.copy` through `aria-label` in both states, and only the glyph\n * changes. An `aria-label` you pass yourself names it in either form.\n * @defaultValue true\n */\n showLabel?: boolean;\n /** Translations for the label and the announcements. */\n labels?: CopyButtonLabels;\n /**\n * Called with `true` after each copy that worked, a repeat included, and\n * with `false` when `duration` runs out or a later copy fails.\n */\n onCopiedChange?: (copied: boolean) => void;\n /**\n * Called when neither the Clipboard API nor the fallback could write. A\n * copy field can select its text from here, so the reader can copy it\n * themselves.\n */\n onCopyError?: (error: Error) => void;\n}\n\n/** Two sheets, one over the other. */\nconst CopyGlyph = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n width=\"1em\"\n height=\"1em\"\n focusable=\"false\"\n >\n <path d=\"M10.5 3.5v-1a1 1 0 0 0-1-1h-6a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h1\" />\n <rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"9\" rx=\"1\" />\n </svg>\n);\n\n/** One copy's outcome, as the status region announces it. */\ninterface Announcement {\n id: string;\n text: string;\n}\n\nconst describeAnnouncement = (announcement: Announcement) => announcement.text;\nconst noAnnouncements: Announcement[] = [];\n\n/** What marks an open modal dialog in ARIA. */\nconst modalDialog = '[aria-modal=\"true\"]';\n\n/**\n * The open modal dialog an element is in: one marked `aria-modal=\"true\"`, or\n * a `<dialog>` opened with `showModal()`, which makes the rest of the page\n * inert. An engine without the `:modal` selector throws on the whole list,\n * so it then looks for the ARIA alone.\n *\n * @param element - Where to look up from.\n * @returns The nearest open modal dialog around it, or `null`.\n */\nfunction closestModalDialog(element: Element): HTMLElement | null {\n try {\n return element.closest<HTMLElement>(`${modalDialog}, dialog:modal`);\n } catch {\n return element.closest<HTMLElement>(modalDialog);\n }\n}\n\n/**\n * The `CopyButton` component renders a button that copies a piece of text to the clipboard, says \"Copied\" for a moment, and announces the result.\n *\n * It's a `Button` with a copy icon and \"Copy\", and takes everything `Button`\n * takes. A click writes `value` through the Clipboard API, or through the\n * older copy command where that's missing or refused, and reports a failure\n * rather than showing \"Copied\". Each outcome is announced through a polite\n * status region portaled out of the button's place, so it stays the last\n * child of a `Control` or `Buttons`: into the open modal dialog the button is\n * in, otherwise where `Portal` puts portaled content (the `ConfigProvider`'s\n * `portalContainer`, or the end of the page). With `showLabel={false}` it's an\n * `IconButton`. For a trigger of your own, use `useClipboard`, which it's\n * built on.\n *\n * @function\n * @param {CopyButtonProps} props - Props for the CopyButton component.\n * @param {React.Ref<HTMLButtonElement>} ref - Forwarded ref to the `<button>`.\n * @returns {JSX.Element} The rendered button.\n * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html | WCAG 4.1.3 Status Messages}\n *\n * @example\n * <CopyButton value=\"https://bestax.io\" />\n *\n * @example\n * <CopyButton value={apiKey} showLabel={false} size=\"small\" />\n */\nexport const CopyButton = forwardRef<HTMLButtonElement, CopyButtonProps>(\n function CopyButton(\n {\n value,\n duration = 2000,\n showLabel = true,\n labels,\n onCopiedChange,\n onCopyError,\n onClick,\n onFocus,\n ...props\n },\n ref\n ) {\n const copyLabel = labels?.copy || 'Copy';\n const copiedLabel = labels?.copied || 'Copied';\n const copiedStatus = labels?.copiedStatus || 'Copied to the clipboard';\n const failedStatus =\n labels?.failedStatus || \"Couldn't copy to the clipboard\";\n\n // The latest outcome. Each gets a new id, so the region announces a\n // repeat too.\n const [announcements, setAnnouncements] = useState(noAnnouncements);\n const countRef = useRef(0);\n const announce = (text: string) => {\n countRef.current += 1;\n setAnnouncements([{ id: String(countRef.current), text }]);\n };\n\n // The open modal dialog the button is in, which the region goes inside:\n // a screen reader ignores a live region behind one. It's looked up when\n // the button takes focus or a click, rather than once as it mounts,\n // since Modal and Sidebar keep their content mounted while closed, and\n // only an open one is `aria-modal`. A region that moves starts empty, so\n // it doesn't say the last outcome again. This lookup can go once the\n // overlays hand their content their own root as its portal container\n // (#1471).\n const [dialog, setDialog] = useState<HTMLElement | null>(null);\n const placeRegion = (button: HTMLElement) => {\n const next = closestModalDialog(button);\n if (next === dialog) return;\n setDialog(next);\n setAnnouncements(noAnnouncements);\n };\n\n // The hook fires nothing once this has unmounted, so neither does the\n // announcement.\n const { copy, copied } = useClipboard({\n duration,\n onCopiedChange: next => {\n if (next) announce(copiedStatus);\n onCopiedChange?.(next);\n },\n onCopyError: error => {\n announce(failedStatus);\n onCopyError?.(error);\n },\n });\n\n // The caller's onClick runs first, so a `preventDefault()` there stops\n // the copy, as it stops ToggleButton's toggle.\n const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n placeRegion(event.currentTarget);\n void copy(value);\n };\n\n const handleFocus = (event: React.FocusEvent<HTMLButtonElement>) => {\n onFocus?.(event);\n placeRegion(event.currentTarget);\n };\n\n const glyph = <Icon>{copied ? <CheckIcon /> : <CopyGlyph />}</Icon>;\n\n // The props are spread first, so it stays a `<button>` that doesn't\n // submit by accident, whatever a JavaScript caller or a spread object\n // passes along.\n const button = showLabel ? (\n <Button\n {...props}\n ref={ref}\n as=\"button\"\n type={buttonType(props.type)}\n onClick={handleClick}\n onFocus={handleFocus}\n >\n {glyph}\n <span>{copied ? copiedLabel : copyLabel}</span>\n </Button>\n ) : (\n // IconButton resolves `type` itself, from the same `buttonType`. Its\n // types refuse `aria-label` beside `aria-labelledby`, which a caller\n // here may pass, and the browser then names it by `aria-labelledby`.\n <IconButton\n {...({\n ...props,\n 'aria-label': props['aria-label'] || copyLabel,\n } as IconButtonProps)}\n ref={ref}\n as=\"button\"\n onClick={handleClick}\n onFocus={handleFocus}\n >\n {glyph}\n </IconButton>\n );\n\n return (\n <>\n {button}\n <Portal container={dialog || undefined}>\n <StatusRegion items={announcements} describe={describeAnnouncement} />\n </Portal>\n </>\n );\n }\n);\n\nCopyButton.displayName = 'CopyButton';\n\nexport default CopyButton;\n"],"names":["_jsxs","_jsx","describeAnnouncement","noAnnouncements","_Fragment"],"mappings":"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"}
|
|
@@ -5,15 +5,11 @@ import { forwardRef } from 'react';
|
|
|
5
5
|
import { usePrefixedClassNames, classNames } from '../helpers/classNames.js';
|
|
6
6
|
import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
|
|
7
7
|
import { withSubComponents } from '../helpers/withSubComponents.js';
|
|
8
|
+
import { isGiven } from '../helpers/isGiven.js';
|
|
8
9
|
|
|
9
10
|
const validDescriptionListOrientations = ['vertical', 'horizontal'];
|
|
10
11
|
const isOrientation = (orientation) => !!orientation &&
|
|
11
12
|
validDescriptionListOrientations.includes(orientation);
|
|
12
|
-
/** Whether a prop was given something to render. */
|
|
13
|
-
const isGiven = (node) => node !== undefined &&
|
|
14
|
-
node !== null &&
|
|
15
|
-
typeof node !== 'boolean' &&
|
|
16
|
-
node !== '';
|
|
17
13
|
/**
|
|
18
14
|
* A label, the name of a fact: a `<dt>`, in the weaker text color.
|
|
19
15
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DescriptionList.js","sources":["../../../src/elements/DescriptionList.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport { withSubComponents } from '../helpers/withSubComponents';\n\nconst validDescriptionListOrientations = ['vertical', 'horizontal'] as const;\n/** Whether each label sits above its value (`vertical`) or beside it (`horizontal`). */\nexport type DescriptionListOrientation =\n (typeof validDescriptionListOrientations)[number];\n\nconst isOrientation = (\n orientation?: string\n): orientation is DescriptionListOrientation =>\n !!orientation &&\n (validDescriptionListOrientations as readonly string[]).includes(orientation);\n\n/** Whether a prop 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 DescriptionList component. The helper props, the other\n * attributes and the `ref` land on the `<dl>`.\n *\n * @extraProp {React.Ref<HTMLDListElement>} [ref] - Ref forwarded to the `<dl>`.\n * @extraProp {string} [aria-labelledby] - The id of the heading above the list, which names it.\n */\nexport interface DescriptionListProps\n extends\n Omit<React.HTMLAttributes<HTMLDListElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /** `DescriptionList.Item`s, one for each fact. */\n children?: React.ReactNode;\n /**\n * Whether each label sits above its value or beside it, at every width no\n * `orientation<Viewport>` prop covers. Those props read the way a\n * `Column`'s `size<Viewport>` props do: `orientationMobile` applies below\n * Bulma's tablet breakpoint, each of the others from its own breakpoint\n * up, and where several apply the widest one wins. With none of them,\n * labels sit above their values below the tablet breakpoint and beside\n * them from it up. Beside, the labels share one column as wide as the\n * longest label, up to `--bulma-description-list-label-max-width`, so the\n * values line up.\n */\n orientation?: DescriptionListOrientation;\n /**\n * The orientation below Bulma's tablet breakpoint (769px). Falls back to\n * `orientation`, then to `vertical`.\n */\n orientationMobile?: DescriptionListOrientation;\n /**\n * The orientation from Bulma's tablet breakpoint (769px) up, until a wider\n * viewport's prop takes over. Falls back to `orientation`, then to\n * `horizontal`.\n */\n orientationTablet?: DescriptionListOrientation;\n /**\n * The orientation from Bulma's desktop breakpoint (1024px) up, until a\n * wider viewport's prop takes over. Falls back to `orientationTablet`, and\n * on down.\n */\n orientationDesktop?: DescriptionListOrientation;\n /**\n * The orientation from Bulma's widescreen breakpoint (1216px) up, until\n * `orientationFullhd` takes over. Falls back to `orientationDesktop`, and\n * on down.\n */\n orientationWidescreen?: DescriptionListOrientation;\n /**\n * The orientation from Bulma's fullhd breakpoint (1408px) up. Falls back to\n * `orientationWidescreen`, and on down.\n */\n orientationFullhd?: DescriptionListOrientation;\n /**\n * Draws a line between items, which helps the eye from a label to its\n * value across a wide list, and shows where each item ends to someone\n * zoomed in.\n */\n hasDividers?: boolean;\n /** Text color helper. It colors the values; the labels keep their own color. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color helper. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/**\n * Props for DescriptionList.Item, one fact. The helper props, the other\n * attributes and the `ref` land on its `<div>`.\n *\n * @extraProp {React.Ref<HTMLDivElement>} [ref] - Ref forwarded to the `<div>`.\n */\nexport interface DescriptionListItemProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /**\n * The label, such as \"Order\", as a `DescriptionList.Label` before the\n * children.\n */\n label?: React.ReactNode;\n /**\n * The value, such as \"#1234\", as a `DescriptionList.Value` after the\n * children. Text, a link, a `Tag`: anything that renders. `undefined`,\n * `null` and `''` render nothing, so when a value is missing, say so in\n * words, such as \"Not given\", rather than leave a label with nothing after\n * it.\n */\n value?: React.ReactNode;\n /**\n * `DescriptionList.Label`s and `DescriptionList.Value`s, for what `label`\n * and `value` don't cover, such as a label with an info tip or several\n * values. They render between the two, so a `Label` here reads before\n * `value`, and a `Value` here after `label`.\n */\n children?: React.ReactNode;\n /** Text color helper. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color helper. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/**\n * Props for DescriptionList.Label. The helper props, the other attributes and\n * the `ref` land on its `<dt>`.\n *\n * @extraProp {React.Ref<HTMLElement>} [ref] - Ref forwarded to the `<dt>`.\n */\nexport interface DescriptionListLabelProps\n extends\n Omit<React.HTMLAttributes<HTMLElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /**\n * The label. A button may sit in it, such as one that opens a `Popover`\n * about the label, but not a heading, which HTML doesn't allow here.\n */\n children?: React.ReactNode;\n /** Text color helper. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color helper. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/**\n * Props for DescriptionList.Value. The helper props, the other attributes and\n * the `ref` land on its `<dd>`.\n *\n * @extraProp {React.Ref<HTMLElement>} [ref] - Ref forwarded to the `<dd>`.\n */\nexport interface DescriptionListValueProps\n extends\n Omit<React.HTMLAttributes<HTMLElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /** The value. Anything goes, a list or a paragraph included. */\n children?: React.ReactNode;\n /** Text color helper. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color helper. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/**\n * A label, the name of a fact: a `<dt>`, in the weaker text color.\n *\n * @function\n * @param {DescriptionListLabelProps} props - Props for DescriptionList.Label.\n * @param {React.Ref<HTMLElement>} ref - Forwarded ref to the `<dt>`.\n * @returns {JSX.Element} The rendered label.\n *\n * @example\n * <DescriptionList.Label>Placed on</DescriptionList.Label>\n */\nexport const DescriptionListLabel = forwardRef<\n HTMLElement,\n DescriptionListLabelProps\n>(({ className, textColor, bgColor, children, ...props }, ref) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n const labelClass = usePrefixedClassNames('description-list-label');\n return (\n <dt\n ref={ref}\n className={classNames(labelClass, bulmaHelperClasses, className)}\n {...rest}\n >\n {children}\n </dt>\n );\n});\n\nDescriptionListLabel.displayName = 'DescriptionList.Label';\n\n/**\n * A value, what the label says about the thing: a `<dd>`. An item may have several.\n *\n * @function\n * @param {DescriptionListValueProps} props - Props for DescriptionList.Value.\n * @param {React.Ref<HTMLElement>} ref - Forwarded ref to the `<dd>`.\n * @returns {JSX.Element} The rendered value.\n *\n * @example\n * <DescriptionList.Value>14 October 2026</DescriptionList.Value>\n */\nexport const DescriptionListValue = forwardRef<\n HTMLElement,\n DescriptionListValueProps\n>(({ className, textColor, bgColor, children, ...props }, ref) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n const valueClass = usePrefixedClassNames('description-list-value');\n return (\n <dd\n ref={ref}\n className={classNames(valueClass, bulmaHelperClasses, className)}\n {...rest}\n >\n {children}\n </dd>\n );\n});\n\nDescriptionListValue.displayName = 'DescriptionList.Value';\n\n/**\n * One fact: its label and its value, in a `<div>`, from the `label` and `value` props or from `Label` and `Value` children.\n *\n * @function\n * @param {DescriptionListItemProps} props - Props for DescriptionList.Item.\n * @param {React.Ref<HTMLDivElement>} ref - Forwarded ref to the `<div>`.\n * @returns {JSX.Element} The rendered item.\n *\n * @example\n * <DescriptionList.Item label=\"Order\" value=\"#1234\" />\n *\n * @example\n * <DescriptionList.Item label=\"Tags\">\n * <DescriptionList.Value>Gift</DescriptionList.Value>\n * <DescriptionList.Value>Priority</DescriptionList.Value>\n * </DescriptionList.Item>\n */\nexport const DescriptionListItem = forwardRef<\n HTMLDivElement,\n DescriptionListItemProps\n>(\n (\n { className, label, value, textColor, bgColor, children, ...props },\n ref\n ) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n const itemClass = usePrefixedClassNames('description-list-item');\n return (\n <div\n ref={ref}\n className={classNames(itemClass, bulmaHelperClasses, className)}\n {...rest}\n >\n {isGiven(label) && <DescriptionListLabel>{label}</DescriptionListLabel>}\n {children}\n {isGiven(value) && <DescriptionListValue>{value}</DescriptionListValue>}\n </div>\n );\n }\n);\n\nDescriptionListItem.displayName = 'DescriptionList.Item';\n\n/**\n * The `DescriptionList` component lists facts about one thing, each a label and its value, such as an order's details or a profile.\n *\n * It's a `<dl>`, with a `<div>` for each item, a `<dt>` for each label and\n * a `<dd>` for each value, so assistive tech gets HTML's own list of terms\n * and definitions and no roles are added. Labels sit above their values on\n * a phone and beside them from Bulma's tablet breakpoint up, where every\n * label shares one column so the values line up. For data with two\n * dimensions, such as several records with the same fields, use a `Table`.\n *\n * @function\n * @param {DescriptionListProps} props - Props for the DescriptionList component.\n * @param {React.Ref<HTMLDListElement>} ref - Forwarded ref to the `<dl>`.\n * @returns {JSX.Element} The rendered list.\n *\n * @example\n * <DescriptionList aria-labelledby=\"order-heading\">\n * <DescriptionList.Item label=\"Order\" value=\"#1234\" />\n * <DescriptionList.Item label=\"Placed on\" value=\"14 October 2026\" />\n * </DescriptionList>\n */\nconst DescriptionListRoot = forwardRef<HTMLDListElement, DescriptionListProps>(\n (\n {\n className,\n orientation,\n orientationMobile,\n orientationTablet,\n orientationDesktop,\n orientationWidescreen,\n orientationFullhd,\n hasDividers,\n textColor,\n bgColor,\n children,\n ...props\n },\n ref\n ) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n // A class for each orientation given, which the stylesheet applies from\n // that viewport's breakpoint, so the layout is right on the first paint\n // and on the server. With none, the stylesheet's default is responsive.\n const rootClass = usePrefixedClassNames('description-list', {\n [`is-${orientation}`]: isOrientation(orientation),\n [`is-${orientationMobile}-mobile`]: isOrientation(orientationMobile),\n [`is-${orientationTablet}-tablet`]: isOrientation(orientationTablet),\n [`is-${orientationDesktop}-desktop`]: isOrientation(orientationDesktop),\n [`is-${orientationWidescreen}-widescreen`]: isOrientation(\n orientationWidescreen\n ),\n [`is-${orientationFullhd}-fullhd`]: isOrientation(orientationFullhd),\n 'has-dividers': !!hasDividers,\n });\n return (\n <dl\n ref={ref}\n className={classNames(rootClass, bulmaHelperClasses, className)}\n {...rest}\n >\n {children}\n </dl>\n );\n }\n);\n\nexport const DescriptionList = withSubComponents(\n DescriptionListRoot,\n {\n Item: DescriptionListItem,\n Label: DescriptionListLabel,\n Value: DescriptionListValue,\n },\n 'DescriptionList'\n);\n\nexport default DescriptionList;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DescriptionList.js","sources":["../../../src/elements/DescriptionList.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { isGiven } from '../helpers/isGiven';\n\nconst validDescriptionListOrientations = ['vertical', 'horizontal'] as const;\n/** Whether each label sits above its value (`vertical`) or beside it (`horizontal`). */\nexport type DescriptionListOrientation =\n (typeof validDescriptionListOrientations)[number];\n\nconst isOrientation = (\n orientation?: string\n): orientation is DescriptionListOrientation =>\n !!orientation &&\n (validDescriptionListOrientations as readonly string[]).includes(orientation);\n\n/**\n * Props for the DescriptionList component. The helper props, the other\n * attributes and the `ref` land on the `<dl>`.\n *\n * @extraProp {React.Ref<HTMLDListElement>} [ref] - Ref forwarded to the `<dl>`.\n * @extraProp {string} [aria-labelledby] - The id of the heading above the list, which names it.\n */\nexport interface DescriptionListProps\n extends\n Omit<React.HTMLAttributes<HTMLDListElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /** `DescriptionList.Item`s, one for each fact. */\n children?: React.ReactNode;\n /**\n * Whether each label sits above its value or beside it, at every width no\n * `orientation<Viewport>` prop covers. Those props read the way a\n * `Column`'s `size<Viewport>` props do: `orientationMobile` applies below\n * Bulma's tablet breakpoint, each of the others from its own breakpoint\n * up, and where several apply the widest one wins. With none of them,\n * labels sit above their values below the tablet breakpoint and beside\n * them from it up. Beside, the labels share one column as wide as the\n * longest label, up to `--bulma-description-list-label-max-width`, so the\n * values line up.\n */\n orientation?: DescriptionListOrientation;\n /**\n * The orientation below Bulma's tablet breakpoint (769px). Falls back to\n * `orientation`, then to `vertical`.\n */\n orientationMobile?: DescriptionListOrientation;\n /**\n * The orientation from Bulma's tablet breakpoint (769px) up, until a wider\n * viewport's prop takes over. Falls back to `orientation`, then to\n * `horizontal`.\n */\n orientationTablet?: DescriptionListOrientation;\n /**\n * The orientation from Bulma's desktop breakpoint (1024px) up, until a\n * wider viewport's prop takes over. Falls back to `orientationTablet`, and\n * on down.\n */\n orientationDesktop?: DescriptionListOrientation;\n /**\n * The orientation from Bulma's widescreen breakpoint (1216px) up, until\n * `orientationFullhd` takes over. Falls back to `orientationDesktop`, and\n * on down.\n */\n orientationWidescreen?: DescriptionListOrientation;\n /**\n * The orientation from Bulma's fullhd breakpoint (1408px) up. Falls back to\n * `orientationWidescreen`, and on down.\n */\n orientationFullhd?: DescriptionListOrientation;\n /**\n * Draws a line between items, which helps the eye from a label to its\n * value across a wide list, and shows where each item ends to someone\n * zoomed in.\n */\n hasDividers?: boolean;\n /** Text color helper. It colors the values; the labels keep their own color. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color helper. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/**\n * Props for DescriptionList.Item, one fact. The helper props, the other\n * attributes and the `ref` land on its `<div>`.\n *\n * @extraProp {React.Ref<HTMLDivElement>} [ref] - Ref forwarded to the `<div>`.\n */\nexport interface DescriptionListItemProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /**\n * The label, such as \"Order\", as a `DescriptionList.Label` before the\n * children.\n */\n label?: React.ReactNode;\n /**\n * The value, such as \"#1234\", as a `DescriptionList.Value` after the\n * children. Text, a link, a `Tag`: anything that renders. `undefined`,\n * `null` and `''` render nothing, so when a value is missing, say so in\n * words, such as \"Not given\", rather than leave a label with nothing after\n * it.\n */\n value?: React.ReactNode;\n /**\n * `DescriptionList.Label`s and `DescriptionList.Value`s, for what `label`\n * and `value` don't cover, such as a label with an info tip or several\n * values. They render between the two, so a `Label` here reads before\n * `value`, and a `Value` here after `label`.\n */\n children?: React.ReactNode;\n /** Text color helper. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color helper. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/**\n * Props for DescriptionList.Label. The helper props, the other attributes and\n * the `ref` land on its `<dt>`.\n *\n * @extraProp {React.Ref<HTMLElement>} [ref] - Ref forwarded to the `<dt>`.\n */\nexport interface DescriptionListLabelProps\n extends\n Omit<React.HTMLAttributes<HTMLElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /**\n * The label. A button may sit in it, such as one that opens a `Popover`\n * about the label, but not a heading, which HTML doesn't allow here.\n */\n children?: React.ReactNode;\n /** Text color helper. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color helper. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/**\n * Props for DescriptionList.Value. The helper props, the other attributes and\n * the `ref` land on its `<dd>`.\n *\n * @extraProp {React.Ref<HTMLElement>} [ref] - Ref forwarded to the `<dd>`.\n */\nexport interface DescriptionListValueProps\n extends\n Omit<React.HTMLAttributes<HTMLElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /** The value. Anything goes, a list or a paragraph included. */\n children?: React.ReactNode;\n /** Text color helper. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color helper. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/**\n * A label, the name of a fact: a `<dt>`, in the weaker text color.\n *\n * @function\n * @param {DescriptionListLabelProps} props - Props for DescriptionList.Label.\n * @param {React.Ref<HTMLElement>} ref - Forwarded ref to the `<dt>`.\n * @returns {JSX.Element} The rendered label.\n *\n * @example\n * <DescriptionList.Label>Placed on</DescriptionList.Label>\n */\nexport const DescriptionListLabel = forwardRef<\n HTMLElement,\n DescriptionListLabelProps\n>(({ className, textColor, bgColor, children, ...props }, ref) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n const labelClass = usePrefixedClassNames('description-list-label');\n return (\n <dt\n ref={ref}\n className={classNames(labelClass, bulmaHelperClasses, className)}\n {...rest}\n >\n {children}\n </dt>\n );\n});\n\nDescriptionListLabel.displayName = 'DescriptionList.Label';\n\n/**\n * A value, what the label says about the thing: a `<dd>`. An item may have several.\n *\n * @function\n * @param {DescriptionListValueProps} props - Props for DescriptionList.Value.\n * @param {React.Ref<HTMLElement>} ref - Forwarded ref to the `<dd>`.\n * @returns {JSX.Element} The rendered value.\n *\n * @example\n * <DescriptionList.Value>14 October 2026</DescriptionList.Value>\n */\nexport const DescriptionListValue = forwardRef<\n HTMLElement,\n DescriptionListValueProps\n>(({ className, textColor, bgColor, children, ...props }, ref) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n const valueClass = usePrefixedClassNames('description-list-value');\n return (\n <dd\n ref={ref}\n className={classNames(valueClass, bulmaHelperClasses, className)}\n {...rest}\n >\n {children}\n </dd>\n );\n});\n\nDescriptionListValue.displayName = 'DescriptionList.Value';\n\n/**\n * One fact: its label and its value, in a `<div>`, from the `label` and `value` props or from `Label` and `Value` children.\n *\n * @function\n * @param {DescriptionListItemProps} props - Props for DescriptionList.Item.\n * @param {React.Ref<HTMLDivElement>} ref - Forwarded ref to the `<div>`.\n * @returns {JSX.Element} The rendered item.\n *\n * @example\n * <DescriptionList.Item label=\"Order\" value=\"#1234\" />\n *\n * @example\n * <DescriptionList.Item label=\"Tags\">\n * <DescriptionList.Value>Gift</DescriptionList.Value>\n * <DescriptionList.Value>Priority</DescriptionList.Value>\n * </DescriptionList.Item>\n */\nexport const DescriptionListItem = forwardRef<\n HTMLDivElement,\n DescriptionListItemProps\n>(\n (\n { className, label, value, textColor, bgColor, children, ...props },\n ref\n ) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n const itemClass = usePrefixedClassNames('description-list-item');\n return (\n <div\n ref={ref}\n className={classNames(itemClass, bulmaHelperClasses, className)}\n {...rest}\n >\n {isGiven(label) && <DescriptionListLabel>{label}</DescriptionListLabel>}\n {children}\n {isGiven(value) && <DescriptionListValue>{value}</DescriptionListValue>}\n </div>\n );\n }\n);\n\nDescriptionListItem.displayName = 'DescriptionList.Item';\n\n/**\n * The `DescriptionList` component lists facts about one thing, each a label and its value, such as an order's details or a profile.\n *\n * It's a `<dl>`, with a `<div>` for each item, a `<dt>` for each label and\n * a `<dd>` for each value, so assistive tech gets HTML's own list of terms\n * and definitions and no roles are added. Labels sit above their values on\n * a phone and beside them from Bulma's tablet breakpoint up, where every\n * label shares one column so the values line up. For data with two\n * dimensions, such as several records with the same fields, use a `Table`.\n *\n * @function\n * @param {DescriptionListProps} props - Props for the DescriptionList component.\n * @param {React.Ref<HTMLDListElement>} ref - Forwarded ref to the `<dl>`.\n * @returns {JSX.Element} The rendered list.\n *\n * @example\n * <DescriptionList aria-labelledby=\"order-heading\">\n * <DescriptionList.Item label=\"Order\" value=\"#1234\" />\n * <DescriptionList.Item label=\"Placed on\" value=\"14 October 2026\" />\n * </DescriptionList>\n */\nconst DescriptionListRoot = forwardRef<HTMLDListElement, DescriptionListProps>(\n (\n {\n className,\n orientation,\n orientationMobile,\n orientationTablet,\n orientationDesktop,\n orientationWidescreen,\n orientationFullhd,\n hasDividers,\n textColor,\n bgColor,\n children,\n ...props\n },\n ref\n ) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n // A class for each orientation given, which the stylesheet applies from\n // that viewport's breakpoint, so the layout is right on the first paint\n // and on the server. With none, the stylesheet's default is responsive.\n const rootClass = usePrefixedClassNames('description-list', {\n [`is-${orientation}`]: isOrientation(orientation),\n [`is-${orientationMobile}-mobile`]: isOrientation(orientationMobile),\n [`is-${orientationTablet}-tablet`]: isOrientation(orientationTablet),\n [`is-${orientationDesktop}-desktop`]: isOrientation(orientationDesktop),\n [`is-${orientationWidescreen}-widescreen`]: isOrientation(\n orientationWidescreen\n ),\n [`is-${orientationFullhd}-fullhd`]: isOrientation(orientationFullhd),\n 'has-dividers': !!hasDividers,\n });\n return (\n <dl\n ref={ref}\n className={classNames(rootClass, bulmaHelperClasses, className)}\n {...rest}\n >\n {children}\n </dl>\n );\n }\n);\n\nexport const DescriptionList = withSubComponents(\n DescriptionListRoot,\n {\n Item: DescriptionListItem,\n Label: DescriptionListLabel,\n Value: DescriptionListValue,\n },\n 'DescriptionList'\n);\n\nexport default DescriptionList;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|