@allxsmith/bestax-bulma 5.51.0 → 5.52.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/Command.js +637 -0
- package/dist/esm/components/Command.js.map +1 -0
- package/dist/esm/form/Autocomplete.js +2 -2
- package/dist/esm/form/CheckboxCard.js +118 -0
- package/dist/esm/form/CheckboxCard.js.map +1 -0
- package/dist/esm/form/Checkboxes.js +14 -3
- package/dist/esm/form/Checkboxes.js.map +1 -1
- package/dist/esm/form/RadioCard.js +85 -0
- package/dist/esm/form/RadioCard.js.map +1 -0
- package/dist/esm/form/Radios.js +14 -3
- package/dist/esm/form/Radios.js.map +1 -1
- package/dist/esm/form/groupFieldset.js +38 -0
- package/dist/esm/form/groupFieldset.js.map +1 -0
- package/dist/esm/form/useAutoLabelId.js +1 -1
- package/dist/esm/helpers/useComboboxEngine.js +3 -3
- package/dist/esm/helpers/useFocusTrap.js +2 -2
- package/dist/esm/helpers/useFocusTrap.js.map +1 -1
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +2429 -1566
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +3 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/Command.d.ts +318 -0
- package/dist/types/form/CheckboxCard.d.ts +94 -0
- package/dist/types/form/Checkboxes.d.ts +13 -0
- package/dist/types/form/RadioCard.d.ts +81 -0
- package/dist/types/form/Radios.d.ts +13 -0
- package/dist/types/form/groupFieldset.d.ts +32 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types-cjs/components/Command.d.ts +318 -0
- package/dist/types-cjs/form/CheckboxCard.d.ts +94 -0
- package/dist/types-cjs/form/Checkboxes.d.ts +13 -0
- package/dist/types-cjs/form/RadioCard.d.ts +81 -0
- package/dist/types-cjs/form/Radios.d.ts +13 -0
- package/dist/types-cjs/form/groupFieldset.d.ts +32 -0
- package/dist/types-cjs/index.d.ts +3 -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/components/_command.scss +259 -0
- package/src/scss/components/_index.scss +1 -0
- package/src/scss/form/_checkbox.scss +44 -0
- package/src/scss/form/_checkboxcard.scss +355 -0
- package/src/scss/form/_index.scss +2 -0
- package/src/scss/form/_radio.scss +44 -0
- package/src/scss/form/_radiocard.scss +291 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Command.js","sources":["../../../src/components/Command.tsx"],"sourcesContent":["import React, {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\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 { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport { useLatestRef } from '../helpers/useLatestRef';\nimport { flattenChildren } from '../helpers/flattenChildren';\nimport { warnOnce } from '../helpers/devWarnings';\nimport { isModalOverlayOpen } from '../helpers/overlayStack';\nimport { StatusRegion, spokenText } from '../helpers/statusRegion';\nimport {\n ComboboxEngine,\n useComboboxEngine,\n} from '../helpers/useComboboxEngine';\nimport { Input, InputProps } from '../form/Input';\nimport { Modal } from './Modal';\n\n/** What names a Command that's given no `label`. */\nconst defaultLabel = 'Commands';\n\n/** What a Command given `actions` shows when nothing matches, unless it's given `empty`. */\nconst defaultEmpty = 'No results';\n\n// What the status region announces: the `Command.Empty` content, as the one\n// item it's handed while that content is on screen because of the user's\n// typing.\nconst typedNoMatches = [{ id: 'empty' }];\nconst nothingToAnnounce: Array<{ id: string }> = [];\n\n/** Whether a slot was given something to show. */\nconst isShown = (node: React.ReactNode): boolean =>\n node !== undefined && node !== null && node !== false && node !== '';\n\n/** One action in a Command's `actions`. */\nexport interface CommandAction {\n /** Unique within the Command. It's the item's `value`, so `onSelect` hands it back. */\n id: string;\n /** What the item shows, and what typing matches first. */\n label: string;\n /**\n * A line under the label, such as what the action does or where it goes.\n * Typing matches it too, after the labels. A screen reader hears it after\n * the label, as the item's description.\n */\n description?: string;\n /**\n * More words typing matches, after the labels, such as `['theme']` for\n * \"Dark mode\". They aren't shown.\n */\n keywords?: string[];\n /**\n * The heading the action goes under. Groups show in the order the matches\n * first name them, so the best match is always on top, and the actions with\n * no group show together where the first of them is.\n */\n group?: string;\n /** Shown before the label, and hidden from assistive tech. */\n icon?: React.ReactNode;\n /**\n * Shown at the end of the row, such as the action's own keyboard shortcut in\n * a `Kbd.Group`, or a `Tag`. It only shows: nothing listens for a shortcut\n * written here. A screen reader hears it after the label, with the\n * description.\n */\n hint?: React.ReactNode;\n /** Shown, and reached with the arrows so a screen reader user finds it, but never run. */\n disabled?: boolean;\n /** Runs the action, when it's picked with Enter or a click, before the Command's `onSelect`. */\n onSelect?: () => void;\n}\n\n/** What a Command takes whether it's given `actions` or built from parts. */\ninterface CommandBaseProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'onSelect'>,\n Omit<BulmaClassesProps, 'color'> {\n /**\n * What the Command is for, such as \"Commands\" or \"Settings\". It's never\n * shown: it names the search field and the list for assistive tech, and in\n * `Command.Dialog` the dialog too. An empty string counts as none.\n * @defaultValue 'Commands'\n */\n label?: string;\n /**\n * The search, controlled: the text in the field. Pair it with\n * `onQueryChange`.\n */\n query?: string;\n /**\n * The search to start with when uncontrolled.\n * @defaultValue ''\n */\n defaultQuery?: string;\n /**\n * Called with the search as the user types it. Built from parts, this is\n * where the app filters its items.\n */\n onQueryChange?: (query: string) => void;\n /**\n * Called with the picked item's `value`, an action's `id`, when it's run\n * with Enter or a click, after the item's own `onSelect`. A disabled item\n * is never run.\n */\n onSelect?: (value: string) => void;\n}\n\n/** Props for a Command given `actions`. */\nexport interface CommandActionsProps extends CommandBaseProps {\n /**\n * The actions, for a Command that renders the field, the list, the groups\n * and the empty message itself. Typing filters them by label, keywords and\n * description, ignoring case, with label matches first. Leave it out to\n * build the Command from parts.\n */\n actions: CommandAction[];\n /**\n * Takes over the filtering, with `actions`: it's handed the search as typed\n * and every action, and returns the ones to show, in the order to show\n * them, which is how to plug in fuzzy matching or cut the list short. It's\n * called with an empty search too.\n */\n filter?: (query: string, actions: CommandAction[]) => CommandAction[];\n /** The field's placeholder, with `actions`. */\n placeholder?: string;\n /**\n * What shows in place of the list, with `actions`, when nothing matches.\n * It's announced the way `Command.Empty` is. `null` shows nothing.\n * @defaultValue 'No results'\n */\n empty?: React.ReactNode;\n /** @internal With `actions`, the Command renders its own parts. */\n children?: never;\n}\n\n/** Props for a Command built from parts. */\nexport interface CommandPartsProps extends CommandBaseProps {\n /**\n * The parts, in order: `Command.Input`, then `Command.List` while there are\n * items and `Command.Empty` while there aren't. Nothing filters them, so\n * render the items that match the search `onQueryChange` reports. With\n * `actions` there are none to give: children given with it are ignored,\n * with a warning in development.\n */\n children?: React.ReactNode;\n /** @internal Built from parts, the app renders the items. */\n actions?: never;\n /** @internal Built from parts, the app filters. */\n filter?: never;\n /** @internal Built from parts, `Command.Input` takes the placeholder. */\n placeholder?: never;\n /** @internal Built from parts, `Command.Empty` is the empty message. */\n empty?: never;\n}\n\n/**\n * Props for the Command component: given `actions`, it renders, filters and\n * groups them itself, and without them it's built from parts. The helper\n * props, the other attributes and the `ref` land on the `div.command` around\n * the field and the list.\n *\n * @extraProp {React.Ref<HTMLDivElement>} [ref] - Ref forwarded to the `div.command` around the field and the list.\n */\nexport type CommandProps = CommandActionsProps | CommandPartsProps;\n\n/** What Command.Dialog takes on top of a Command's props. */\ninterface CommandDialogOwnProps {\n /** Controlled open state. When set, opening and closing only report through `onOpenChange`. */\n open?: boolean;\n /**\n * Initial open state when uncontrolled.\n * @defaultValue false\n */\n defaultOpen?: boolean;\n /**\n * Called with the open state asked for: `true` from the `shortcut`, and\n * `false` from Escape, a click on the background, or a pick while\n * `closeOnSelect` is on. Fires in controlled and uncontrolled use.\n */\n onOpenChange?: (open: boolean) => void;\n /**\n * A key combination that opens the dialog from anywhere on the page, such\n * as `\"mod+k\"`: modifiers and a key joined by `+`, where `mod` is Ctrl or\n * ⌘ (either one, on every platform), and the others are `ctrl`, `meta`,\n * `alt` and `shift`. It's ignored while the user is typing in a text field,\n * a select or editable content, while an IME is composing, while a modal\n * overlay is open (a `Modal`, a `Dialog`, a `Sidebar` with its overlay or a\n * full-page `Loading`), and when something else has already used the key.\n * It only opens the dialog. Off unless given.\n */\n shortcut?: string;\n /**\n * Closes the dialog once an item has run. Turn it off for an item that\n * opens another page of the palette, and close it yourself with `open`.\n * @defaultValue true\n */\n closeOnSelect?: boolean;\n /**\n * Clears the search when the dialog closes: an uncontrolled one itself,\n * and a controlled one through `onQueryChange('')`.\n * @defaultValue true\n */\n clearOnClose?: boolean;\n /**\n * Renders the dialog into a portal target instead of inline. Forwarded to\n * the underlying `Modal`; see its `portal` prop for the accepted values.\n * @defaultValue false\n */\n portal?: boolean | string | HTMLElement;\n}\n\n/** Props for a Command.Dialog given `actions`. */\nexport interface CommandDialogActionsProps\n extends CommandActionsProps, CommandDialogOwnProps {}\n\n/** Props for a Command.Dialog built from parts. */\nexport interface CommandDialogPartsProps\n extends CommandPartsProps, CommandDialogOwnProps {}\n\n/**\n * Props for Command.Dialog, the Command in a modal: a Command's props, given\n * `actions` or built from parts, and the dialog's own. The helper props, the\n * other attributes and the `ref` land on the `div.command` that is the\n * dialog.\n *\n * @extraProp {React.Ref<HTMLDivElement>} [ref] - Ref forwarded to the `div.command` that is the dialog.\n */\nexport type CommandDialogProps =\n CommandDialogActionsProps | CommandDialogPartsProps;\n\n/**\n * Props for Command.Input, the search field. It renders `Input`, so its\n * icons, `isLoading` and `color` work as they do there. Its text is the\n * Command's `query`, and it's `autoComplete=\"off\"`, so the browser's own\n * suggestions don't open over the list: neither is yours to set.\n */\nexport type CommandInputProps = Omit<\n InputProps,\n // By name, since the docs read only names out of an Omit. The Field props:\n | 'label'\n | 'labelSize'\n | 'labelProps'\n | 'horizontal'\n | 'message'\n | 'messageColor'\n | 'fieldClassName'\n // And what the Command sets on the field itself:\n | 'role'\n | 'autoComplete'\n | 'value'\n | 'defaultValue'\n>;\n\n/**\n * Props for Command.List, the list. Its `id` is the one the field's\n * `aria-controls` names, so it isn't yours to set.\n */\nexport interface CommandListProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'role' | 'id'\n> {\n /** `Command.Item`s and `Command.Group`s, in the order they're shown. */\n children?: React.ReactNode;\n}\n\n/** Props for Command.Group, items under a heading. */\nexport interface CommandGroupProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'role'\n> {\n /**\n * The heading, which also names the group for assistive tech, unless you\n * give the group an `aria-label` or `aria-labelledby` of its own.\n */\n label: React.ReactNode;\n /** The group's `Command.Item`s. */\n children?: React.ReactNode;\n}\n\n/**\n * Props for Command.Item, one thing to do in the list. Its `id` follows from\n * its `value`, since the field's `aria-activedescendant` names it, so it\n * isn't yours to set.\n */\nexport interface CommandItemProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'role' | 'onSelect' | 'id'\n> {\n /** What the Command's `onSelect` hands back. Unique within the Command. */\n value: string;\n /**\n * Can't be run. The arrows still reach it, so a screen reader user finds\n * it, and it's never `aria-selected`.\n * @defaultValue false\n */\n disabled?: boolean;\n /** Runs the item, when it's picked with Enter or a click, before the Command's `onSelect`. */\n onSelect?: () => void;\n /** Shown before the label, and hidden from assistive tech. */\n icon?: React.ReactNode;\n /**\n * A line under the label. A screen reader hears it after the label, as the\n * item's description.\n */\n description?: React.ReactNode;\n /**\n * Shown at the end of the row, such as a keyboard shortcut in a\n * `Kbd.Group`, or a `Tag`. It only shows. A screen reader hears it after\n * the label, with the description.\n */\n hint?: React.ReactNode;\n /** The label, which names the item. */\n children?: React.ReactNode;\n}\n\n/** Props for Command.Empty, the message shown in place of the list. */\nexport interface CommandEmptyProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * The message, such as \"No commands match\". Its text is announced when\n * typing brings it on screen and isn't read again while it stays, so a\n * message that names the search is heard for the first search only.\n */\n children?: React.ReactNode;\n}\n\n/** A handler an item registers, read when it's run. */\ntype ItemHandler = { readonly current: (() => void) | undefined };\n\n/** What the Command hands its parts. */\ninterface CommandContextValue {\n engine: ComboboxEngine;\n /** What names the field and the list. */\n label: string;\n /** The search. */\n query: string;\n /** A change to the field's value, which is the user typing. */\n onFieldChange: (value: string) => void;\n /** Tells the Command the field's `isLoading`, which holds the empty message's announcement. */\n reportLoading: (loading: boolean) => void;\n /** Records the empty message while it's on screen. Returns the function that forgets it. */\n reportEmpty: (element: HTMLElement) => () => void;\n /** Records an item's `onSelect`. Returns the function that forgets it. */\n registerHandler: (value: string, handler: ItemHandler) => () => void;\n}\n\nconst noop = () => {};\nconst registerNothing = () => noop;\n\n// What a part rendered outside a Command reads: nothing to report to, so it\n// renders its markup and does nothing.\nconst standalone: CommandContextValue = {\n engine: {\n open: false,\n expanded: false,\n highlighted: null,\n typed: false,\n listboxId: '',\n itemId: () => '',\n rootRef: { current: null },\n inputRef: { current: null },\n listboxRef: { current: null },\n registerPopup: registerNothing,\n registerItem: registerNothing,\n onKeyDown: noop,\n onChange: noop,\n onClick: noop,\n onBlur: noop,\n hover: noop,\n pick: noop,\n keepFocus: noop,\n markInside: noop,\n },\n label: defaultLabel,\n query: '',\n onFieldChange: noop,\n reportLoading: noop,\n reportEmpty: registerNothing,\n registerHandler: registerNothing,\n};\n\nconst CommandContext = createContext<CommandContextValue | null>(null);\n\nconst useCommand = () => useContext(CommandContext) ?? standalone;\n\n/** Hands a node to a forwarded ref and to one of the component's own. */\nfunction setRefs<T>(\n node: T | null,\n own: React.MutableRefObject<T | null>,\n forwarded: React.ForwardedRef<T>\n) {\n own.current = node;\n if (typeof forwarded === 'function') forwarded(node);\n else if (forwarded) forwarded.current = node;\n}\n\n/**\n * The default filter: the actions whose label, keywords or description hold\n * the search, ignoring case and the spaces around it, label matches first and\n * the order otherwise kept. An empty search keeps them all.\n */\nconst filterActions = (\n query: string,\n actions: CommandAction[]\n): CommandAction[] => {\n const term = query.trim().toLowerCase();\n if (term === '') return actions;\n const byLabel: CommandAction[] = [];\n const byOther: CommandAction[] = [];\n for (const action of actions) {\n if (action.label.toLowerCase().includes(term)) {\n byLabel.push(action);\n } else if (\n action.description?.toLowerCase().includes(term) ||\n action.keywords?.some(keyword => keyword.toLowerCase().includes(term))\n ) {\n byOther.push(action);\n }\n }\n return [...byLabel, ...byOther];\n};\n\n/** The search icon at the start of the field. */\nconst SearchIcon = () => (\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.75\"\n strokeLinecap=\"round\"\n width=\"1em\"\n height=\"1em\"\n focusable=\"false\"\n >\n <circle cx=\"7\" cy=\"7\" r=\"4.75\" />\n <path d=\"M10.5 10.5L14 14\" />\n </svg>\n);\n\n/**\n * The Command built from parts: the field, the list, the keys and the run,\n * with the items and their filtering left to the app.\n */\nconst CommandParts = forwardRef<HTMLDivElement, CommandPartsProps>(\n (\n {\n children,\n label,\n query: controlledQuery,\n defaultQuery = '',\n onQueryChange,\n onSelect,\n className,\n ...props\n },\n ref\n ) => {\n const [ownQuery, setOwnQuery] = useState(defaultQuery);\n const query = controlledQuery ?? ownQuery;\n\n // Each item's `onSelect`, by value, read when it runs.\n const handlersRef = useRef(new Map<string, ItemHandler>());\n const registerHandler = useCallback(\n (value: string, handler: ItemHandler) => {\n const handlers = handlersRef.current;\n handlers.set(value, handler);\n return () => {\n if (handlers.get(value) === handler) handlers.delete(value);\n };\n },\n []\n );\n const run = (value: string) => {\n handlersRef.current.get(value)?.current?.();\n onSelect?.(value);\n };\n\n // Inline: the list is always on screen, nothing opens or closes it, and\n // Escape goes on to what's around it. `keepFirst` keeps the highlight on\n // the top match, so Enter runs it.\n const engine = useComboboxEngine({\n defaultOpen: true,\n onSelect: run,\n keepFirst: true,\n multiple: false,\n inline: true,\n deferred: false,\n });\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const rootClass = usePrefixedClassNames('command');\n\n // A polite status region, in the page from the start so it's there\n // before anything is written into it, announces `Command.Empty` when the\n // user's typing leaves it on screen: once each time that happens, not\n // again on each keystroke while it stays. An empty search isn't a search,\n // so it stays quiet then, and while the field's `isLoading` says results\n // are on their way, it waits.\n const [inputLoading, setInputLoading] = useState(false);\n const emptyRef = useRef<HTMLElement | null>(null);\n const [emptyShown, setEmptyShown] = useState(false);\n const announced =\n engine.typed && query !== '' && emptyShown && !inputLoading\n ? typedNoMatches\n : nothingToAnnounce;\n // The region reads the text on screen, whatever the message renders.\n const describeEmpty = useCallback(() => {\n const node = emptyRef.current;\n /* istanbul ignore if: it's only announced while it's on screen */\n if (!node) return null;\n return spokenText(node);\n }, []);\n const reportEmpty = useCallback((element: HTMLElement) => {\n emptyRef.current = element;\n setEmptyShown(true);\n return () => {\n emptyRef.current = null;\n setEmptyShown(false);\n };\n }, []);\n\n const onFieldChange = (value: string) => {\n if (controlledQuery === undefined) setOwnQuery(value);\n onQueryChange?.(value);\n engine.onChange();\n };\n\n // A new value each render: the engine's state and handlers are, and the\n // parts read the highlight from it.\n const context: CommandContextValue = {\n engine,\n label: label || defaultLabel,\n query,\n onFieldChange,\n reportLoading: setInputLoading,\n reportEmpty,\n registerHandler,\n };\n\n const { rootRef } = engine;\n const rootRefs = useCallback(\n (node: HTMLDivElement | null) => setRefs(node, rootRef, ref),\n [rootRef, ref]\n );\n\n return (\n // The ref after the spread, so the element stays the Command's.\n <div\n className={classNames(rootClass, bulmaHelperClasses, className)}\n {...rest}\n ref={rootRefs}\n >\n <CommandContext.Provider value={context}>\n {children}\n </CommandContext.Provider>\n <StatusRegion items={announced} describe={describeEmpty} />\n </div>\n );\n }\n);\nCommandParts.displayName = 'CommandParts';\n\n/**\n * The search field, with the combobox role and the keys, rendered as an `Input` with a search icon.\n *\n * @function\n * @param {CommandInputProps} props - Props for the Command.Input component.\n * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the `<input>`.\n * @returns {JSX.Element} The field in its Control.\n */\nexport const CommandInput = forwardRef<HTMLInputElement, CommandInputProps>(\n (\n {\n isLoading,\n iconLeft,\n iconLeftName,\n onKeyDown,\n onChange,\n onClick,\n onBlur,\n 'aria-autocomplete': ariaAutocomplete,\n ...props\n },\n ref\n ) => {\n const context = useCommand();\n const { engine, reportLoading } = context;\n useClientLayoutEffect(() => {\n reportLoading(!!isLoading);\n return () => reportLoading(false);\n }, [reportLoading, isLoading]);\n const { inputRef } = engine;\n const inputRefs = useCallback(\n (node: HTMLInputElement | null) => setRefs(node, inputRef, ref),\n [inputRef, ref]\n );\n const { expanded, highlighted } = engine;\n // A name the caller gave the field wins over the Command's `label`.\n const callerNamed = !!props['aria-label'] || 'aria-labelledby' in props;\n\n return (\n // The attributes the Command owns after the caller's, so a stray\n // `aria-expanded` never wins. A search isn't prose, so the browser's\n // spelling and autocorrect stay out of it unless the caller asks.\n <Input\n autoCorrect=\"off\"\n spellCheck={false}\n {...props}\n ref={inputRefs}\n value={context.query}\n iconLeft={\n iconLeft === undefined && !iconLeftName ? <SearchIcon /> : iconLeft\n }\n iconLeftName={iconLeftName}\n isLoading={isLoading}\n aria-label={callerNamed ? props['aria-label'] : context.label}\n role=\"combobox\"\n aria-autocomplete={ariaAutocomplete ?? 'list'}\n aria-haspopup=\"listbox\"\n aria-expanded={expanded}\n aria-controls={expanded ? engine.listboxId : undefined}\n aria-activedescendant={\n expanded && highlighted !== null\n ? engine.itemId(highlighted)\n : undefined\n }\n autoComplete=\"off\"\n onKeyDown={event => {\n onKeyDown?.(event);\n engine.onKeyDown(event);\n }}\n onChange={event => {\n onChange?.(event);\n context.onFieldChange(event.target.value);\n }}\n onClick={event => {\n onClick?.(event);\n if (!event.defaultPrevented) engine.onClick();\n }}\n onBlur={event => {\n onBlur?.(event);\n engine.onBlur(event);\n }}\n />\n );\n }\n);\nCommandInput.displayName = 'CommandInput';\n\n/**\n * The list of items, a `listbox` named by the Command's `label`.\n *\n * @function\n * @param {CommandListProps} props - Props for the Command.List component.\n * @returns {JSX.Element} The listbox.\n */\nexport const CommandList: React.FC<CommandListProps> = ({\n children,\n className,\n onMouseDown,\n ...props\n}) => {\n const { engine, label } = useCommand();\n const { listboxRef, listboxId, keepFocus } = engine;\n const listClass = usePrefixedClassNames('command-list');\n // A name the caller gave the list wins over the Command's.\n const callerNamed = !!props['aria-label'] || 'aria-labelledby' in props;\n return (\n <div\n className={classNames(listClass, className)}\n {...props}\n ref={listboxRef}\n id={listboxId || undefined}\n role=\"listbox\"\n aria-label={callerNamed ? props['aria-label'] : label}\n onMouseDown={event => {\n onMouseDown?.(event);\n keepFocus(event);\n }}\n >\n {children}\n </div>\n );\n};\nCommandList.displayName = 'CommandList';\n\n/**\n * Items under a heading, a `group` named by it.\n *\n * @function\n * @param {CommandGroupProps} props - Props for the Command.Group component.\n * @returns {JSX.Element} The group and its heading.\n */\nexport const CommandGroup: React.FC<CommandGroupProps> = ({\n label,\n children,\n className,\n ...props\n}) => {\n const labelId = useId();\n const groupClass = usePrefixedClassNames('command-group');\n const labelClass = usePrefixedClassNames('command-group-label');\n // A name the caller gave the group wins over its heading's, as on the list.\n const callerNamed = !!props['aria-label'] || 'aria-labelledby' in props;\n return (\n <div\n className={classNames(groupClass, className)}\n {...props}\n role=\"group\"\n aria-labelledby={callerNamed ? props['aria-labelledby'] : labelId}\n >\n <div className={labelClass} id={labelId}>\n {label}\n </div>\n {children}\n </div>\n );\n};\nCommandGroup.displayName = 'CommandGroup';\n\n/**\n * One thing to do in the list, named by its label and described by its description and hint.\n *\n * @function\n * @param {CommandItemProps} props - Props for the Command.Item component.\n * @returns {JSX.Element} The item.\n */\nexport const CommandItem: React.FC<CommandItemProps> = ({\n value,\n disabled = false,\n onSelect,\n icon,\n description,\n hint,\n children,\n className,\n onClick,\n onPointerMove,\n ...props\n}) => {\n const { engine, registerHandler } = useCommand();\n const itemRef = useRef<HTMLDivElement>(null);\n const { registerItem } = engine;\n useClientLayoutEffect(\n () =>\n registerItem(itemRef.current as HTMLDivElement, {\n value,\n disabled,\n checked: false,\n }),\n [registerItem, value, disabled]\n );\n const onSelectRef = useLatestRef(onSelect);\n useClientLayoutEffect(\n () => registerHandler(value, onSelectRef),\n [registerHandler, value, onSelectRef]\n );\n const highlighted = engine.highlighted === value;\n const itemClass = usePrefixedClassNames('command-item', {\n 'is-active': highlighted,\n 'is-disabled': disabled,\n });\n const iconClass = usePrefixedClassNames('command-item-icon');\n const bodyClass = usePrefixedClassNames('command-item-body');\n const labelClass = usePrefixedClassNames('command-item-label');\n const descriptionClass = usePrefixedClassNames('command-item-description');\n const hintClass = usePrefixedClassNames('command-item-hint');\n\n // Named by its label alone, so a screen reader says what it does before\n // the rest, and described by the description and the hint.\n const baseId = useId();\n const labelId = `${baseId}label`;\n const descriptionId = isShown(description)\n ? `${baseId}description`\n : undefined;\n const hintId = isShown(hint) ? `${baseId}hint` : undefined;\n const describedBy =\n [descriptionId, hintId].filter(Boolean).join(' ') || undefined;\n const callerNamed = !!props['aria-label'] || 'aria-labelledby' in props;\n\n return (\n <div\n className={classNames(itemClass, className)}\n aria-describedby={describedBy}\n {...props}\n ref={itemRef}\n id={engine.itemId(value) || undefined}\n role=\"option\"\n // The highlighted option, as the ARIA Authoring Practices' combobox\n // has it, and no attribute on the rest. Never a disabled option.\n aria-selected={disabled ? undefined : highlighted || undefined}\n aria-disabled={disabled || undefined}\n aria-labelledby={callerNamed ? props['aria-labelledby'] : labelId}\n onClick={event => {\n onClick?.(event);\n if (!disabled && !event.defaultPrevented) engine.pick(value);\n }}\n onPointerMove={event => {\n onPointerMove?.(event);\n if (!disabled && !highlighted) engine.hover(value);\n }}\n >\n {isShown(icon) && (\n <span className={iconClass} aria-hidden=\"true\">\n {icon}\n </span>\n )}\n <span className={bodyClass}>\n <span className={labelClass} id={labelId}>\n {children}\n </span>\n {descriptionId && (\n <span className={descriptionClass} id={descriptionId}>\n {description}\n </span>\n )}\n </span>\n {hintId && (\n <span className={hintClass} id={hintId}>\n {hint}\n </span>\n )}\n </div>\n );\n};\nCommandItem.displayName = 'CommandItem';\n\n/**\n * The message shown in place of the list when nothing matches, announced when typing brings it on screen.\n *\n * @function\n * @param {CommandEmptyProps} props - Props for the Command.Empty component.\n * @returns {JSX.Element} The message.\n */\nexport const CommandEmpty: React.FC<CommandEmptyProps> = ({\n children,\n className,\n onMouseDown,\n ...props\n}) => {\n const { engine, reportEmpty } = useCommand();\n const emptyRef = useRef<HTMLDivElement>(null);\n useClientLayoutEffect(\n () => reportEmpty(emptyRef.current as HTMLDivElement),\n [reportEmpty]\n );\n const emptyClass = usePrefixedClassNames('command-empty');\n return (\n <div\n className={classNames(emptyClass, className)}\n {...props}\n ref={emptyRef}\n onMouseDown={event => {\n onMouseDown?.(event);\n engine.keepFocus(event);\n }}\n >\n {children}\n </div>\n );\n};\nCommandEmpty.displayName = 'CommandEmpty';\n\n/** What a Command given `actions` renders inside its parts root. */\ninterface CommandActionsContentProps {\n actions: CommandAction[];\n filter: CommandActionsProps['filter'];\n placeholder: string | undefined;\n empty: React.ReactNode;\n}\n\n/**\n * The field, and the actions that match the search, grouped, or the empty\n * message. The search is the parts root's, read from its context.\n */\nconst CommandActionsContent = ({\n actions,\n filter = filterActions,\n placeholder,\n empty,\n}: CommandActionsContentProps) => {\n const { query } = useCommand();\n const shown = filter(query, actions);\n\n // Each group where the matches first name it, and the actions with none\n // together where the first of them is, so the best match stays on top.\n const sections = new Map<string, CommandAction[]>();\n for (const action of shown) {\n const group = action.group ?? '';\n sections.set(group, [...(sections.get(group) ?? []), action]);\n }\n const renderItem = (action: CommandAction) => (\n <CommandItem\n key={action.id}\n value={action.id}\n disabled={action.disabled}\n icon={action.icon}\n description={action.description}\n hint={action.hint}\n onSelect={action.onSelect}\n >\n {action.label}\n </CommandItem>\n );\n\n return (\n <>\n <CommandInput placeholder={placeholder} />\n {shown.length > 0 ? (\n <CommandList>\n {Array.from(sections, ([group, members]) =>\n group ? (\n <CommandGroup key={group} label={group}>\n {members.map(renderItem)}\n </CommandGroup>\n ) : (\n members.map(renderItem)\n )\n )}\n </CommandList>\n ) : isShown(empty) ? (\n <CommandEmpty>{empty}</CommandEmpty>\n ) : null}\n </>\n );\n};\n\n/**\n * The Command given `actions`. It renders the parts itself and filters the\n * actions as the user types, so a run goes through the same parts, keys and\n * ARIA as one built by hand.\n */\nconst CommandFromActions = forwardRef<HTMLDivElement, CommandActionsProps>(\n (\n { actions, filter, placeholder, empty = defaultEmpty, children, ...rest },\n ref\n ) => {\n if (flattenChildren(children).length > 0) {\n warnOnce(\n 'Command:actions-children',\n '[bestax-bulma] <Command actions> renders its own field and items, ' +\n 'so its children are ignored. Give it actions or build it from ' +\n 'parts, not both.'\n );\n }\n return (\n <CommandParts {...rest} ref={ref}>\n <CommandActionsContent\n actions={actions}\n filter={filter}\n placeholder={placeholder}\n empty={empty}\n />\n </CommandParts>\n );\n }\n);\nCommandFromActions.displayName = 'CommandFromActions';\n\n/**\n * The `Command` component is a search field over a list of things to do, which narrows as you type and runs the top match on Enter: inline by default, and a command palette in a modal as `Command.Dialog`.\n *\n * Given `actions`, it's one element. It renders the field, the list, the\n * groups and the empty message, and filters the actions by label, keywords\n * and description as the user types, with label matches first. `filter`\n * takes over the matching, for fuzzy search.\n *\n * Built from parts, the app owns the items: what's in the list and how it's\n * filtered, from the search `onQueryChange` reports. Nothing filters them,\n * so a server's answer shows as it came.\n *\n * Either way, focus stays in the field, and the highlighted item is its\n * `aria-activedescendant`. The first enabled item is highlighted whenever\n * the items change, so Enter runs the top match. Running an item calls its\n * own `onSelect`, then the Command's.\n *\n * When typing leaves the empty message on screen, its text is announced\n * through a polite status region, once, after any loading ends. Result\n * counts aren't announced: a screen reader reads the list's size from the\n * markup, and a count on every keystroke talks over the typing.\n *\n * @function\n * @param {CommandProps} props - Props for the Command component.\n * @param {React.Ref<HTMLDivElement>} ref - Forwarded ref to the `div.command`.\n * @returns {JSX.Element} The field and its list.\n *\n * @example\n * <Command\n * label=\"Settings\"\n * placeholder=\"Search settings\"\n * actions={[\n * { id: 'profile', label: 'Edit profile', onSelect: openProfile },\n * { id: 'theme', label: 'Dark mode', keywords: ['theme'], onSelect: toggleTheme },\n * ]}\n * />\n *\n * @example\n * <Command label=\"People\" onQueryChange={setQuery} onSelect={openProfile}>\n * <Command.Input placeholder=\"Find a person\" />\n * {matches.length > 0 ? (\n * <Command.List>\n * {matches.map(person => (\n * <Command.Item key={person.id} value={person.id}>\n * {person.name}\n * </Command.Item>\n * ))}\n * </Command.List>\n * ) : (\n * <Command.Empty>No one matches</Command.Empty>\n * )}\n * </Command>\n */\nconst CommandRoot = forwardRef<HTMLDivElement, CommandProps>((props, ref) =>\n props.actions === undefined ? (\n <CommandParts {...props} ref={ref} />\n ) : (\n <CommandFromActions {...props} ref={ref} />\n )\n);\n\n/** A key combination, read from a `shortcut` string. */\ninterface ParsedShortcut {\n /** The key, lowercased, as `KeyboardEvent.key` names it. */\n key: string;\n mod: boolean;\n ctrl: boolean;\n meta: boolean;\n alt: boolean;\n shift: boolean;\n}\n\n/** Other names a key goes by in a `shortcut`, for the ones `key` spells otherwise. */\nconst keyAliases: Record<string, string> = {\n space: ' ',\n esc: 'escape',\n};\n\n/**\n * Reads a `shortcut` such as `\"mod+k\"` or `\"ctrl + shift + p\"`.\n *\n * @param shortcut - Modifiers and a key, joined by `+`.\n * @returns The combination, or `null` when it doesn't read as one.\n */\nconst parseShortcut = (shortcut: string): ParsedShortcut | null => {\n const parts = shortcut\n .toLowerCase()\n .split('+')\n .map(part => part.trim());\n const key = parts.pop() as string;\n if (key === '') return null;\n const parsed: ParsedShortcut = {\n key: keyAliases[key] ?? key,\n mod: false,\n ctrl: false,\n meta: false,\n alt: false,\n shift: false,\n };\n for (const part of parts) {\n if (part === 'mod') parsed.mod = true;\n else if (part === 'ctrl' || part === 'control') parsed.ctrl = true;\n else if (part === 'meta' || part === 'cmd' || part === 'command')\n parsed.meta = true;\n else if (part === 'alt' || part === 'option') parsed.alt = true;\n else if (part === 'shift') parsed.shift = true;\n else return null;\n }\n return parsed;\n};\n\n/**\n * Whether a keydown is the combination. `mod` takes Ctrl or ⌘, and any other\n * modifier has to be as the combination says, so `mod+k` isn't\n * `mod+shift+k`. A letter or digit is matched by its key, and by where it\n * sits on the keyboard only when the key isn't a Latin letter or digit at\n * all, as on a Cyrillic layout or with Option held on a Mac, so another\n * Latin layout's own letters keep their own shortcuts.\n */\nconst matchesShortcut = (\n event: KeyboardEvent,\n shortcut: ParsedShortcut\n): boolean => {\n if (event.altKey !== shortcut.alt) return false;\n // A symbol such as `?` already says whether Shift was down, and which key\n // takes Shift to type it depends on the layout, so Shift is only checked\n // for a letter, a digit or a named key, unless the combination names it.\n const shiftMatters =\n shortcut.shift ||\n shortcut.key.length > 1 ||\n /^[a-z0-9]$/.test(shortcut.key);\n if (shiftMatters && event.shiftKey !== shortcut.shift) return false;\n if (shortcut.mod) {\n if (!event.ctrlKey && !event.metaKey) return false;\n } else if (\n event.ctrlKey !== shortcut.ctrl ||\n event.metaKey !== shortcut.meta\n ) {\n return false;\n }\n const key = (event.key ?? '').toLowerCase();\n if (key === shortcut.key) return true;\n if (/^[a-z0-9]$/.test(key)) return false;\n if (/^[a-z]$/.test(shortcut.key)) {\n return event.code === `Key${shortcut.key.toUpperCase()}`;\n }\n if (/^[0-9]$/.test(shortcut.key)) {\n return event.code === `Digit${shortcut.key}`;\n }\n return false;\n};\n\n/** Input types that take no typing, so a shortcut pressed in one still counts. */\nconst untypedInputs = new Set([\n 'button',\n 'checkbox',\n 'color',\n 'file',\n 'hidden',\n 'image',\n 'radio',\n 'range',\n 'reset',\n 'submit',\n]);\n\n/**\n * Whether a keydown happened while the user was typing: in a text field, a\n * text area, a select, or editable content. The composed path's first entry\n * is the element itself, even inside a shadow root.\n */\nconst isTyping = (event: KeyboardEvent): boolean => {\n const target = event.composedPath()[0] as Partial<Element> | undefined;\n if (typeof target?.closest !== 'function') return false;\n const element = target as Element;\n const editable = element.closest('[contenteditable]');\n if (editable && editable.getAttribute('contenteditable') !== 'false') {\n return true;\n }\n const tag = element.tagName;\n if (tag === 'TEXTAREA' || tag === 'SELECT') return true;\n return (\n tag === 'INPUT' &&\n !untypedInputs.has((element as HTMLInputElement).type.toLowerCase())\n );\n};\n\n/**\n * The Command in a modal, a command palette, opened by its `shortcut` or by `open`, that closes once an item has run.\n *\n * It renders nothing while it's closed. Open, it's a `Modal` with a\n * background and the Command's box as the `dialog`, named by `label`:\n * focus goes to the search field, Tab stays inside, Escape and a click on\n * the background close it, the page behind it doesn't scroll, and focus goes\n * back to where it was when it closes.\n *\n * @function\n * @param {CommandDialogProps} props - Props for the Command.Dialog component.\n * @param {React.Ref<HTMLDivElement>} ref - Forwarded ref to the `div.command` that is the dialog.\n * @returns {JSX.Element | null} The dialog, or nothing while it's closed.\n */\nexport const CommandDialog = forwardRef<HTMLDivElement, CommandDialogProps>(\n (\n {\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n shortcut,\n closeOnSelect = true,\n clearOnClose = true,\n portal,\n label,\n query: controlledQuery,\n defaultQuery = '',\n onQueryChange,\n onSelect,\n className,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n ...props\n },\n ref\n ) => {\n const [ownOpen, setOwnOpen] = useState(defaultOpen);\n const open = controlledOpen ?? ownOpen;\n // Only ever asked for the other state: the shortcut listens while it's\n // closed, and everything that closes it is there while it's open.\n const setOpen = (next: boolean) => {\n if (controlledOpen === undefined) setOwnOpen(next);\n onOpenChange?.(next);\n };\n\n // The search is held here rather than in the Command, which is only\n // mounted while the dialog is open, so it can outlive a close when\n // `clearOnClose` is off.\n const [ownQuery, setOwnQuery] = useState(defaultQuery);\n const query = controlledQuery ?? ownQuery;\n const setQuery = (next: string) => {\n if (controlledQuery === undefined) setOwnQuery(next);\n onQueryChange?.(next);\n };\n // Closing clears the search, however the dialog closed. Our own is\n // cleared during render, React's pattern for adjusting state when other\n // state changes, and a controlled one is asked for after the commit.\n const [shownOpen, setShownOpen] = useState(open);\n if (shownOpen !== open) {\n setShownOpen(open);\n if (!open && clearOnClose && controlledQuery === undefined) {\n setOwnQuery('');\n }\n }\n const wasOpenRef = useRef(open);\n const clearRef = useLatestRef(() => {\n if (clearOnClose && controlledQuery !== undefined && query !== '') {\n onQueryChange?.('');\n }\n });\n useEffect(() => {\n const wasOpen = wasOpenRef.current;\n wasOpenRef.current = open;\n if (wasOpen && !open) clearRef.current();\n }, [open, clearRef]);\n\n if (controlledOpen === undefined && !defaultOpen && !shortcut) {\n warnOnce(\n 'Command.Dialog:no-opener',\n '[bestax-bulma] <Command.Dialog> has no way to open. Give it a ' +\n 'shortcut, or open and onOpenChange.'\n );\n }\n if (shortcut && !parseShortcut(shortcut)) {\n warnOnce(\n `Command.Dialog:shortcut:${shortcut}`,\n `[bestax-bulma] <Command.Dialog> can't read the shortcut ` +\n `\"${shortcut}\". Write modifiers and a key joined by +, such as ` +\n `\"mod+k\", where the modifiers are mod, ctrl, meta, alt and shift.`\n );\n }\n\n const openFromShortcut = useLatestRef(() => setOpen(true));\n useEffect(() => {\n const combination = shortcut ? parseShortcut(shortcut) : null;\n if (!combination || open) return undefined;\n const onKeyDown = (event: KeyboardEvent) => {\n if (\n event.defaultPrevented ||\n event.isComposing ||\n event.keyCode === 229 ||\n !matchesShortcut(event, combination) ||\n isTyping(event) ||\n // A Modal, a Dialog, a Sidebar with its overlay or a full-page\n // Loading has the page shut off, so the key isn't the page's. A\n // Sidebar without one leaves the page in use, so it still opens.\n isModalOverlayOpen()\n ) {\n return;\n }\n // The browser's own use of the combination, such as Ctrl+K's search\n // in the address bar, doesn't happen as well.\n event.preventDefault();\n openFromShortcut.current();\n };\n // On `window`, where a keydown arrives last, so anything on the page\n // that used the key first has said so with `preventDefault()`.\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [shortcut, open, openFromShortcut]);\n\n const dialogClass = usePrefixedClassNames('command-dialog');\n\n if (!open) return null;\n\n const close = () => setOpen(false);\n const run = (value: string) => {\n onSelect?.(value);\n if (closeOnSelect) close();\n };\n\n return (\n <Modal isActive onClose={close} role=\"presentation\" portal={portal}>\n <Modal.Background onClick={close} />\n <CommandRoot\n {...(props as CommandProps)}\n ref={ref}\n className={classNames(dialogClass, className)}\n label={label}\n query={query}\n onQueryChange={setQuery}\n onSelect={run}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={\n ariaLabelledBy === undefined\n ? ariaLabel || label || defaultLabel\n : ariaLabel\n }\n aria-labelledby={ariaLabelledBy}\n />\n </Modal>\n );\n }\n);\nCommandDialog.displayName = 'CommandDialog';\n\n/** Command with Input, List, Group, Item, Empty and Dialog sub-components. */\nexport const Command = withSubComponents(\n CommandRoot,\n {\n Input: CommandInput,\n List: CommandList,\n Group: CommandGroup,\n Item: CommandItem,\n Empty: CommandEmpty,\n Dialog: CommandDialog,\n },\n 'Command'\n);\n\nexport default Command;\n"],"names":["typedNoMatches","nothingToAnnounce","noop","registerNothing","standalone","setRefs","_jsxs","_jsx"],"mappings":"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"}
|
|
@@ -23,7 +23,7 @@ const keepFocus = (e) => e.preventDefault();
|
|
|
23
23
|
// An IME that's composing owns every key: Enter confirms what it composed,
|
|
24
24
|
// and the arrows move through its candidates. Safari can say so with
|
|
25
25
|
// `keyCode` 229 rather than `isComposing`.
|
|
26
|
-
const isComposing$
|
|
26
|
+
const isComposing$1 = (e) => e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229;
|
|
27
27
|
// Whether an option can be picked. The arrows still reach a disabled one, so
|
|
28
28
|
// a screen reader user finds it.
|
|
29
29
|
const isEnabled = (item) => typeof item === 'string' || !item.disabled;
|
|
@@ -195,7 +195,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
195
195
|
}, [keepFirst, isActive, filteredData.length, inputValue]);
|
|
196
196
|
// Handle keyboard navigation
|
|
197
197
|
const handleKeyDown = useCallback((e) => {
|
|
198
|
-
if (disabled || isComposing$
|
|
198
|
+
if (disabled || isComposing$1(e))
|
|
199
199
|
return;
|
|
200
200
|
switch (e.key) {
|
|
201
201
|
case 'ArrowDown':
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { forwardRef, useRef, useCallback, useId } from 'react';
|
|
4
|
+
import { usePrefixedClassNames, classNames } from '../helpers/classNames.js';
|
|
5
|
+
import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
|
|
6
|
+
import { useClientLayoutEffect } from '../helpers/useClientLayoutEffect.js';
|
|
7
|
+
import { useCheckboxesGroup } from './FormContext.js';
|
|
8
|
+
|
|
9
|
+
// The colors `Checkbox` takes, as `checkboxColors` lists them. Declared here as
|
|
10
|
+
// well, so the API page can read them off this module, and a type test holds
|
|
11
|
+
// the two lists to each other.
|
|
12
|
+
const checkboxCardColors = [
|
|
13
|
+
'primary',
|
|
14
|
+
'link',
|
|
15
|
+
'info',
|
|
16
|
+
'success',
|
|
17
|
+
'warning',
|
|
18
|
+
'danger',
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* The `CheckboxCard` component is a checkbox drawn as a card, with a title and a description, that toggles wherever you click it.
|
|
22
|
+
*
|
|
23
|
+
* It's a `<label>` around a real checkbox, so it sends its `value` with a
|
|
24
|
+
* form and Space toggles it. The title names the checkbox and the
|
|
25
|
+
* description describes it. Alone it's one choice; inside `Checkboxes` it
|
|
26
|
+
* takes the group's name and selection, as `Checkbox` does.
|
|
27
|
+
*
|
|
28
|
+
* @function
|
|
29
|
+
* @param {CheckboxCardProps} props - Props for the CheckboxCard component.
|
|
30
|
+
* @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the `<input>`.
|
|
31
|
+
* @returns {JSX.Element} The rendered card.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* <Checkboxes label="Add-ons" name="extras" defaultValue={['backups']}>
|
|
35
|
+
* <CheckboxCard value="backups" title="Daily backups" description="Kept for 30 days." />
|
|
36
|
+
* <CheckboxCard value="domain" title="Custom domain" description="Bring your own." />
|
|
37
|
+
* </Checkboxes>
|
|
38
|
+
*/
|
|
39
|
+
const CheckboxCard = forwardRef(({ title, description, children, hasIndicator = true, color, className, textColor, disabled, name, value, checked, defaultChecked, indeterminate, onChange, ...props }, ref) => {
|
|
40
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
41
|
+
color: textColor,
|
|
42
|
+
...props,
|
|
43
|
+
});
|
|
44
|
+
// The input's own ref, merged with the forwarded one, as Checkbox does,
|
|
45
|
+
// so the mixed state can be set on it.
|
|
46
|
+
const inputRef = useRef(null);
|
|
47
|
+
const setRefs = useCallback((node) => {
|
|
48
|
+
inputRef.current = node;
|
|
49
|
+
if (typeof ref === 'function')
|
|
50
|
+
return ref(node);
|
|
51
|
+
if (ref)
|
|
52
|
+
ref.current = node;
|
|
53
|
+
}, [ref]);
|
|
54
|
+
// `indeterminate` is a DOM property with no attribute, and a click clears
|
|
55
|
+
// it, so it's set after every render while the prop is set, and cleared
|
|
56
|
+
// once when the prop goes back to unset. Checkbox does the same.
|
|
57
|
+
const ownsIndeterminateRef = useRef(false);
|
|
58
|
+
useClientLayoutEffect(() => {
|
|
59
|
+
if (indeterminate !== undefined) {
|
|
60
|
+
ownsIndeterminateRef.current = true;
|
|
61
|
+
inputRef.current.indeterminate = indeterminate;
|
|
62
|
+
}
|
|
63
|
+
else if (ownsIndeterminateRef.current) {
|
|
64
|
+
ownsIndeterminateRef.current = false;
|
|
65
|
+
inputRef.current.indeterminate = false;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
// A surrounding <Checkboxes> hands down its name and, when it manages
|
|
69
|
+
// the selection, whether this card's value is in it. The card's own
|
|
70
|
+
// props win, as they do on Checkbox.
|
|
71
|
+
const group = useCheckboxesGroup();
|
|
72
|
+
const effectiveName = name ?? group?.name;
|
|
73
|
+
const groupManaged = group?.value !== undefined && value !== undefined;
|
|
74
|
+
const effectiveChecked = checked !== undefined
|
|
75
|
+
? checked
|
|
76
|
+
: groupManaged
|
|
77
|
+
? group.value.includes(String(value))
|
|
78
|
+
: undefined;
|
|
79
|
+
const effectiveDefaultChecked = groupManaged ? undefined : defaultChecked;
|
|
80
|
+
const handleChange = useCallback((e) => {
|
|
81
|
+
if (indeterminate !== undefined)
|
|
82
|
+
e.target.indeterminate = indeterminate;
|
|
83
|
+
onChange?.(e);
|
|
84
|
+
if (group?.onChange && value !== undefined) {
|
|
85
|
+
const valStr = String(value);
|
|
86
|
+
const current = group.value ?? [];
|
|
87
|
+
group.onChange(e.target.checked
|
|
88
|
+
? current.includes(valStr)
|
|
89
|
+
? current
|
|
90
|
+
: [...current, valStr]
|
|
91
|
+
: current.filter(v => v !== valStr));
|
|
92
|
+
}
|
|
93
|
+
}, [onChange, group, value, indeterminate]);
|
|
94
|
+
// The title names the input and the description describes it. A name
|
|
95
|
+
// passed in wins, and without one of either the label's own text names
|
|
96
|
+
// the input, description included, so it isn't described again.
|
|
97
|
+
const titleId = useId();
|
|
98
|
+
const descriptionId = useId();
|
|
99
|
+
const ariaLabel = rest['aria-label'];
|
|
100
|
+
const ariaLabelledBy = rest['aria-labelledby'] || (!ariaLabel && title ? titleId : undefined);
|
|
101
|
+
const ariaDescribedBy = rest['aria-describedby'] ||
|
|
102
|
+
(description && (ariaLabel || ariaLabelledBy)
|
|
103
|
+
? descriptionId
|
|
104
|
+
: undefined);
|
|
105
|
+
const cardClass = usePrefixedClassNames('checkbox-card', 'card', {
|
|
106
|
+
[`is-${color}`]: color && checkboxCardColors.includes(color),
|
|
107
|
+
});
|
|
108
|
+
const contentClass = usePrefixedClassNames('card-content', 'checkbox-card-content');
|
|
109
|
+
const checkClass = usePrefixedClassNames('checkbox-card-check');
|
|
110
|
+
const bodyClass = usePrefixedClassNames('checkbox-card-body');
|
|
111
|
+
const titleClass = usePrefixedClassNames('checkbox-card-title');
|
|
112
|
+
const descriptionClass = usePrefixedClassNames('checkbox-card-description');
|
|
113
|
+
return (jsxs("label", { className: classNames(cardClass, bulmaHelperClasses, className), children: [jsx("input", { ref: setRefs, type: "checkbox", disabled: disabled, name: effectiveName, value: value, checked: effectiveChecked, defaultChecked: effectiveDefaultChecked, onChange: handleChange, ...rest, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy }), jsxs("span", { className: contentClass, children: [hasIndicator && jsx("span", { className: checkClass }), jsxs("span", { className: bodyClass, children: [title ? (jsx("span", { id: titleId, className: titleClass, children: title })) : null, description ? (jsx("span", { id: descriptionId, className: descriptionClass, children: description })) : null, children] })] })] }));
|
|
114
|
+
});
|
|
115
|
+
CheckboxCard.displayName = 'CheckboxCard';
|
|
116
|
+
|
|
117
|
+
export { CheckboxCard };
|
|
118
|
+
//# sourceMappingURL=CheckboxCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CheckboxCard.js","sources":["../../../src/form/CheckboxCard.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useId, useRef } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport { useCheckboxesGroup } from './FormContext';\n\n// The colors `Checkbox` takes, as `checkboxColors` lists them. Declared here as\n// well, so the API page can read them off this module, and a type test holds\n// the two lists to each other.\nconst checkboxCardColors = [\n 'primary',\n 'link',\n 'info',\n 'success',\n 'warning',\n 'danger',\n] as const;\n\n/**\n * Props for the CheckboxCard component.\n *\n * @helperProps Helper props go on the outer `<label>`, the `.card`, with\n * `className`. The other attributes go on the `<input>`.\n * @extraProp {string} [name] - The form field name. Inside `Checkboxes`, the group's `name` when this is unset.\n * @extraProp {string} [value] - What a form sends for the card when it's checked. Inside a `Checkboxes` group that takes `value`, `defaultValue` or `onChange`, the card is checked while the group's value holds it.\n */\nexport interface CheckboxCardProps\n extends\n Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'type' | 'color' | 'title'\n >,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor' | 'size'> {\n /**\n * What the option is, such as \"Daily backups\". It names the checkbox, so\n * a screen reader says it with the state. Without it, the card's whole\n * text names the checkbox, as a label's text does.\n */\n title?: React.ReactNode;\n /**\n * A line or two about the option, read after the name and the state. It's\n * the checkbox's description when `title`, `aria-label` or\n * `aria-labelledby` names it. Without one of those it's part of the name\n * already, so it isn't read twice.\n */\n description?: React.ReactNode;\n /**\n * Anything else in the card, after the description, such as a price. A\n * label holds phrasing content only, so spans, images and links: a link\n * works and doesn't toggle the card, but a button or another input can't\n * go inside a label at all. It isn't read when the checkbox takes focus,\n * so put what a screen reader should hear in `title` and `description`.\n */\n children?: React.ReactNode;\n /**\n * Shows the checkbox at the start of the card. Without it, the card's\n * edge alone shows the selection, and it's thicker when checked, so the\n * selection never rests on color.\n */\n hasIndicator?: boolean;\n /** The color of the checkbox and of a checked card's edge. */\n color?: (typeof checkboxCardColors)[number];\n /**\n * Text color helper, on the card. The title and the children take it, and\n * the description keeps its own color.\n */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Whether the card is disabled. A disabled card dims, takes no clicks, and leaves the Tab order. */\n disabled?: boolean;\n /**\n * Shows the mixed state, as in a \"Select all\" card when some of what it\n * covers is checked. It's a look and an announcement only: `checked` is\n * still the value, and a click still toggles `checked`. Set to `true` or\n * `false`, it's controlled: a browser clears the mixed state on a click,\n * so the component sets it again from this prop after every click and\n * every render. Unset isn't `false`. The component leaves the input's own\n * `indeterminate` property alone, so a ref can set it, and going from set\n * to unset clears it once and hands it back. It has no HTML attribute, so\n * server-rendered markup can't carry it, and a mixed card renders unmixed\n * until hydration.\n */\n indeterminate?: boolean;\n /**\n * Additional CSS classes, on the outer `<label>`, the card. That's the\n * element that declares the `--bulma-checkbox-card-*` variables, and\n * Bulma's `--bulma-card-*` ones, so a class is how to set one: `style` and\n * the other input attributes go to the `<input>`. Name `.checkbox-card`\n * beside your class in the selector, so it beats the card's own\n * declaration whatever order the stylesheets load in. A `color` prop\n * declares the active color again on `.checkbox-card.is-<color>`, which\n * ties that selector, so leave `color` unset when a class sets it.\n */\n className?: string;\n}\n\n/**\n * The `CheckboxCard` component is a checkbox drawn as a card, with a title and a description, that toggles wherever you click it.\n *\n * It's a `<label>` around a real checkbox, so it sends its `value` with a\n * form and Space toggles it. The title names the checkbox and the\n * description describes it. Alone it's one choice; inside `Checkboxes` it\n * takes the group's name and selection, as `Checkbox` does.\n *\n * @function\n * @param {CheckboxCardProps} props - Props for the CheckboxCard component.\n * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the `<input>`.\n * @returns {JSX.Element} The rendered card.\n *\n * @example\n * <Checkboxes label=\"Add-ons\" name=\"extras\" defaultValue={['backups']}>\n * <CheckboxCard value=\"backups\" title=\"Daily backups\" description=\"Kept for 30 days.\" />\n * <CheckboxCard value=\"domain\" title=\"Custom domain\" description=\"Bring your own.\" />\n * </Checkboxes>\n */\nexport const CheckboxCard = forwardRef<HTMLInputElement, CheckboxCardProps>(\n (\n {\n title,\n description,\n children,\n hasIndicator = true,\n color,\n className,\n textColor,\n disabled,\n name,\n value,\n checked,\n defaultChecked,\n indeterminate,\n onChange,\n ...props\n },\n ref\n ) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n ...props,\n });\n\n // The input's own ref, merged with the forwarded one, as Checkbox does,\n // so the mixed state can be set on it.\n const inputRef = useRef<HTMLInputElement | null>(null);\n const setRefs = useCallback(\n (node: HTMLInputElement | null) => {\n inputRef.current = node;\n if (typeof ref === 'function') return ref(node);\n if (ref) ref.current = node;\n },\n [ref]\n );\n\n // `indeterminate` is a DOM property with no attribute, and a click clears\n // it, so it's set after every render while the prop is set, and cleared\n // once when the prop goes back to unset. Checkbox does the same.\n const ownsIndeterminateRef = useRef(false);\n useClientLayoutEffect(() => {\n if (indeterminate !== undefined) {\n ownsIndeterminateRef.current = true;\n inputRef.current!.indeterminate = indeterminate;\n } else if (ownsIndeterminateRef.current) {\n ownsIndeterminateRef.current = false;\n inputRef.current!.indeterminate = false;\n }\n });\n\n // A surrounding <Checkboxes> hands down its name and, when it manages\n // the selection, whether this card's value is in it. The card's own\n // props win, as they do on Checkbox.\n const group = useCheckboxesGroup();\n const effectiveName = name ?? group?.name;\n const groupManaged = group?.value !== undefined && value !== undefined;\n const effectiveChecked =\n checked !== undefined\n ? checked\n : groupManaged\n ? group!.value!.includes(String(value))\n : undefined;\n const effectiveDefaultChecked = groupManaged ? undefined : defaultChecked;\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n if (indeterminate !== undefined) e.target.indeterminate = indeterminate;\n onChange?.(e);\n if (group?.onChange && value !== undefined) {\n const valStr = String(value);\n const current = group.value ?? [];\n group.onChange(\n e.target.checked\n ? current.includes(valStr)\n ? current\n : [...current, valStr]\n : current.filter(v => v !== valStr)\n );\n }\n },\n [onChange, group, value, indeterminate]\n );\n\n // The title names the input and the description describes it. A name\n // passed in wins, and without one of either the label's own text names\n // the input, description included, so it isn't described again.\n const titleId = useId();\n const descriptionId = useId();\n const ariaLabel = rest['aria-label'];\n const ariaLabelledBy =\n rest['aria-labelledby'] || (!ariaLabel && title ? titleId : undefined);\n const ariaDescribedBy =\n rest['aria-describedby'] ||\n (description && (ariaLabel || ariaLabelledBy)\n ? descriptionId\n : undefined);\n\n const cardClass = usePrefixedClassNames('checkbox-card', 'card', {\n [`is-${color}`]: color && checkboxCardColors.includes(color),\n });\n const contentClass = usePrefixedClassNames(\n 'card-content',\n 'checkbox-card-content'\n );\n const checkClass = usePrefixedClassNames('checkbox-card-check');\n const bodyClass = usePrefixedClassNames('checkbox-card-body');\n const titleClass = usePrefixedClassNames('checkbox-card-title');\n const descriptionClass = usePrefixedClassNames('checkbox-card-description');\n\n return (\n <label className={classNames(cardClass, bulmaHelperClasses, className)}>\n <input\n ref={setRefs}\n type=\"checkbox\"\n disabled={disabled}\n name={effectiveName}\n value={value}\n checked={effectiveChecked}\n defaultChecked={effectiveDefaultChecked}\n onChange={handleChange}\n {...rest}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n />\n <span className={contentClass}>\n {hasIndicator && <span className={checkClass} />}\n <span className={bodyClass}>\n {title ? (\n <span id={titleId} className={titleClass}>\n {title}\n </span>\n ) : null}\n {description ? (\n <span id={descriptionId} className={descriptionClass}>\n {description}\n </span>\n ) : null}\n {children}\n </span>\n </span>\n </label>\n );\n }\n);\n\nCheckboxCard.displayName = 'CheckboxCard';\n\nexport default CheckboxCard;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@ import { Field } from './Field.js';
|
|
|
9
9
|
import { Control } from './Control.js';
|
|
10
10
|
import { useAutoLabelledBy } from './useAutoLabelId.js';
|
|
11
11
|
import { Checkbox } from './Checkbox.js';
|
|
12
|
+
import { GroupFieldset } from './groupFieldset.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* The `Checkboxes` component wraps multiple `Checkbox` components in a Bulma-styled group.
|
|
@@ -35,7 +36,7 @@ import { Checkbox } from './Checkbox.js';
|
|
|
35
36
|
* <Checkbox value="angular">Angular</Checkbox>
|
|
36
37
|
* </Checkboxes>
|
|
37
38
|
*/
|
|
38
|
-
const CheckboxesComponent = ({ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName, name, value, defaultValue, onChange, children, className, ...props }) => {
|
|
39
|
+
const CheckboxesComponent = ({ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName, name, value, defaultValue, onChange, children, className, as, ...props }) => {
|
|
39
40
|
const insideField = useInsideField();
|
|
40
41
|
const insideControl = useInsideControl();
|
|
41
42
|
const ownField = rendersOwnField('Checkboxes', {
|
|
@@ -46,10 +47,14 @@ const CheckboxesComponent = ({ label, labelSize, labelProps, horizontal, message
|
|
|
46
47
|
horizontal,
|
|
47
48
|
fieldClassName,
|
|
48
49
|
});
|
|
50
|
+
// As a fieldset with a Field of its own, the group's label is its legend,
|
|
51
|
+
// which names it with no id, so nothing points `aria-labelledby` at it.
|
|
52
|
+
const asFieldset = as === 'fieldset';
|
|
53
|
+
const fieldsetField = asFieldset && ownField;
|
|
49
54
|
const { ariaLabelledBy, fieldLabelProps } = useAutoLabelledBy({
|
|
50
55
|
label,
|
|
51
56
|
labelProps,
|
|
52
|
-
rendersLabel: ownField,
|
|
57
|
+
rendersLabel: ownField && !fieldsetField,
|
|
53
58
|
callerProps: props,
|
|
54
59
|
});
|
|
55
60
|
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
@@ -74,11 +79,17 @@ const CheckboxesComponent = ({ label, labelSize, labelProps, horizontal, message
|
|
|
74
79
|
name,
|
|
75
80
|
...(groupActive ? { value: currentValue, onChange: handleChange } : {}),
|
|
76
81
|
}), [name, groupActive, currentValue, handleChange]);
|
|
77
|
-
const
|
|
82
|
+
const choices = (jsx(CheckboxesProvider, { value: ctx, children: children }));
|
|
83
|
+
// A fieldset is a group already, so it takes no role of its own.
|
|
84
|
+
const Group = asFieldset ? 'fieldset' : 'div';
|
|
85
|
+
const checkboxesElement = fieldsetField ? (jsx("div", { className: wrapperClass, children: choices })) : (jsx(Group, { className: wrapperClass, role: asFieldset ? undefined : 'group', "aria-labelledby": ariaLabelledBy, ...rest, children: choices }));
|
|
78
86
|
let content = checkboxesElement;
|
|
79
87
|
if (rendersOwnControl('Checkboxes', { insideControl })) {
|
|
80
88
|
content = jsx(Control, { children: content });
|
|
81
89
|
}
|
|
90
|
+
if (fieldsetField) {
|
|
91
|
+
return (jsx(GroupFieldset, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, fieldClassName: fieldClassName, attributes: rest, message: messageEl, children: content }));
|
|
92
|
+
}
|
|
82
93
|
if (ownField) {
|
|
83
94
|
return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
|
|
84
95
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkboxes.js","sources":["../../../src/form/Checkboxes.tsx"],"sourcesContent":["import React, { useCallback, useMemo, useState } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport {\n useInsideField,\n useInsideControl,\n rendersOwnField,\n rendersOwnControl,\n CheckboxesProvider,\n CheckboxesGroupContextValue,\n} from './FormContext';\nimport { Field } from './Field';\nimport { Control } from './Control';\nimport { FormFieldProps } from './fieldProps';\nimport { useAutoLabelledBy } from './useAutoLabelId';\nimport { Checkbox } from './Checkbox';\n\n/**\n * Props for the Checkboxes component.\n * Inside an existing `Control` it renders no `Control` of its own. Inside an\n * outer `Field`, or a `Control` with no `Field` around it, it renders no\n * `Field` of its own either. The exception is `label`, `message`, `horizontal`\n * or `fieldClassName` in that bare `Control`: it keeps a `Field` for them,\n * nested in the `.control`, and warns in development. Wrap the `Control` in a\n * `Field` instead, and set the `label`, `horizontal` and class name on that\n * `Field`.\n */\nexport interface CheckboxesProps\n extends Omit<BulmaClassesProps, 'color'>, FormFieldProps {\n /** Field label naming the whole group. Automatically associated via `aria-labelledby` on the `role=\"group\"` wrapper — uses your `labelProps.id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label names the group instead through `aria-labelledby` when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). An `aria-label` or `aria-labelledby` you set on the group wins over either label, which still renders but no longer names it. An `aria-labelledby` key counts even when undefined, since it is spread over the group's own. */\n label?: React.ReactNode;\n /** Props for the label element. An explicit `id` here is used as the `aria-labelledby` target instead of a generated one; any `htmlFor` is ignored (a group label names the group, never a single control). */\n labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {\n [key: string]: unknown;\n };\n /** Additional CSS classes to apply. */\n className?: string;\n /** Form field name shared by every Checkbox in the group (via context). */\n name?: string;\n /** Currently-selected values (controlled mode). */\n value?: string[];\n /** Initial selected values (uncontrolled mode). */\n defaultValue?: string[];\n /** Fires when the selection changes; receives the new array. */\n onChange?: (values: string[]) => void;\n /** Checkbox elements to render in the group. */\n children?: React.ReactNode;\n}\n\n/**\n * The `Checkboxes` component wraps multiple `Checkbox` components in a Bulma-styled group.\n *\n * @function\n * @param {CheckboxesProps} props - Props for the Checkboxes component.\n * @returns {JSX.Element} The rendered checkboxes group.\n * @see {@link https://bulma.io/documentation/form/checkbox/#grouped-checkboxes | Bulma Checkboxes documentation}\n *\n * @example\n * // Controlled\n * const [tags, setTags] = useState(['react']);\n * <Checkboxes name=\"tags\" value={tags} onChange={setTags}>\n * <Checkbox value=\"react\">React</Checkbox>\n * <Checkbox value=\"vue\">Vue</Checkbox>\n * <Checkbox value=\"angular\">Angular</Checkbox>\n * </Checkboxes>\n *\n * @example\n * // Uncontrolled\n * <Checkboxes name=\"tags\" defaultValue={['react', 'vue']}>\n * <Checkbox value=\"react\">React</Checkbox>\n * <Checkbox value=\"vue\">Vue</Checkbox>\n * <Checkbox value=\"angular\">Angular</Checkbox>\n * </Checkboxes>\n */\nconst CheckboxesComponent: React.FC<CheckboxesProps> = ({\n label,\n labelSize,\n labelProps,\n horizontal,\n message,\n messageColor,\n fieldClassName,\n name,\n value,\n defaultValue,\n onChange,\n children,\n className,\n ...props\n}) => {\n const insideField = useInsideField();\n const insideControl = useInsideControl();\n const ownField = rendersOwnField('Checkboxes', {\n insideField,\n insideControl,\n label,\n message,\n horizontal,\n fieldClassName,\n });\n const { ariaLabelledBy, fieldLabelProps } = useAutoLabelledBy({\n label,\n labelProps,\n rendersLabel: ownField,\n callerProps: props,\n });\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n ...props,\n });\n\n const mainClass = usePrefixedClassNames('checkboxes');\n const wrapperClass = classNames(mainClass, bulmaHelperClasses, className);\n\n const helpClass = usePrefixedClassNames('help', {\n [`is-${messageColor}`]: !!messageColor,\n });\n const messageEl = message ? <p className={helpClass}>{message}</p> : null;\n\n const groupActive =\n value !== undefined || defaultValue !== undefined || onChange !== undefined;\n\n const [internalValue, setInternalValue] = useState<string[] | undefined>(\n defaultValue\n );\n const isControlled = value !== undefined;\n const currentValue = isControlled ? value : internalValue;\n\n const handleChange = useCallback(\n (newValues: string[]) => {\n if (!isControlled) setInternalValue(newValues);\n onChange?.(newValues);\n },\n [isControlled, onChange]\n );\n\n const ctx = useMemo<CheckboxesGroupContextValue>(\n () => ({\n name,\n ...(groupActive ? { value: currentValue, onChange: handleChange } : {}),\n }),\n [name, groupActive, currentValue, handleChange]\n );\n\n const checkboxesElement = (\n <div\n className={wrapperClass}\n role=\"group\"\n aria-labelledby={ariaLabelledBy}\n {...rest}\n >\n <CheckboxesProvider value={ctx}>{children}</CheckboxesProvider>\n </div>\n );\n\n let content = checkboxesElement;\n\n if (rendersOwnControl('Checkboxes', { insideControl })) {\n content = <Control>{content}</Control>;\n }\n\n if (ownField) {\n return (\n <Field\n label={label}\n labelSize={labelSize}\n labelProps={fieldLabelProps}\n horizontal={horizontal}\n className={fieldClassName}\n >\n {content}\n {messageEl}\n </Field>\n );\n }\n\n return (\n <>\n {content}\n {messageEl}\n </>\n );\n};\n\nexport const Checkboxes = withSubComponents(\n CheckboxesComponent,\n { Checkbox },\n 'Checkboxes'\n);\n\nexport default Checkboxes;\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Checkboxes.js","sources":["../../../src/form/Checkboxes.tsx"],"sourcesContent":["import React, { useCallback, useMemo, useState } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport {\n useInsideField,\n useInsideControl,\n rendersOwnField,\n rendersOwnControl,\n CheckboxesProvider,\n CheckboxesGroupContextValue,\n} from './FormContext';\nimport { Field } from './Field';\nimport { Control } from './Control';\nimport { FormFieldProps } from './fieldProps';\nimport { useAutoLabelledBy } from './useAutoLabelId';\nimport { Checkbox } from './Checkbox';\nimport { GroupFieldset } from './groupFieldset';\n\n/**\n * Props for the Checkboxes component.\n * Inside an existing `Control` it renders no `Control` of its own. Inside an\n * outer `Field`, or a `Control` with no `Field` around it, it renders no\n * `Field` of its own either. The exception is `label`, `message`, `horizontal`\n * or `fieldClassName` in that bare `Control`: it keeps a `Field` for them,\n * nested in the `.control`, and warns in development. Wrap the `Control` in a\n * `Field` instead, and set the `label`, `horizontal` and class name on that\n * `Field`.\n */\nexport interface CheckboxesProps\n extends Omit<BulmaClassesProps, 'color'>, FormFieldProps {\n /** Field label naming the whole group. Automatically associated via `aria-labelledby` on the `role=\"group\"` wrapper — uses your `labelProps.id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label names the group instead through `aria-labelledby` when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). An `aria-label` or `aria-labelledby` you set on the group wins over either label, which still renders but no longer names it. An `aria-labelledby` key counts even when undefined, since it is spread over the group's own. */\n label?: React.ReactNode;\n /** Props for the label element. An explicit `id` here is used as the `aria-labelledby` target instead of a generated one; any `htmlFor` is ignored (a group label names the group, never a single control). */\n labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {\n [key: string]: unknown;\n };\n /** Additional CSS classes to apply. */\n className?: string;\n /** Form field name shared by every Checkbox in the group (via context). */\n name?: string;\n /** Currently-selected values (controlled mode). */\n value?: string[];\n /** Initial selected values (uncontrolled mode). */\n defaultValue?: string[];\n /** Fires when the selection changes; receives the new array. */\n onChange?: (values: string[]) => void;\n /** Checkbox elements to render in the group. */\n children?: React.ReactNode;\n /**\n * The element the group renders as. With `fieldset` it's a native\n * `<fieldset>`. Where the group renders a `Field` of its own, that `Field`\n * is the `<fieldset>` and the `label` is its `<legend>`, in the label\n * column when `horizontal`, so the legend names the group with no ids to\n * wire. Your other attributes then go on the `<fieldset>`, while\n * `className` and the helper props stay on the box that lays out the\n * checkboxes. Inside an outer `Field` there's no legend: the group element\n * itself is the `<fieldset>`, named by that `Field`'s label as before.\n * `div`, the default, renders the group as it always has.\n * @defaultValue 'div'\n */\n as?: 'div' | 'fieldset';\n}\n\n/**\n * The `Checkboxes` component wraps multiple `Checkbox` components in a Bulma-styled group.\n *\n * @function\n * @param {CheckboxesProps} props - Props for the Checkboxes component.\n * @returns {JSX.Element} The rendered checkboxes group.\n * @see {@link https://bulma.io/documentation/form/checkbox/#grouped-checkboxes | Bulma Checkboxes documentation}\n *\n * @example\n * // Controlled\n * const [tags, setTags] = useState(['react']);\n * <Checkboxes name=\"tags\" value={tags} onChange={setTags}>\n * <Checkbox value=\"react\">React</Checkbox>\n * <Checkbox value=\"vue\">Vue</Checkbox>\n * <Checkbox value=\"angular\">Angular</Checkbox>\n * </Checkboxes>\n *\n * @example\n * // Uncontrolled\n * <Checkboxes name=\"tags\" defaultValue={['react', 'vue']}>\n * <Checkbox value=\"react\">React</Checkbox>\n * <Checkbox value=\"vue\">Vue</Checkbox>\n * <Checkbox value=\"angular\">Angular</Checkbox>\n * </Checkboxes>\n */\nconst CheckboxesComponent: React.FC<CheckboxesProps> = ({\n label,\n labelSize,\n labelProps,\n horizontal,\n message,\n messageColor,\n fieldClassName,\n name,\n value,\n defaultValue,\n onChange,\n children,\n className,\n as,\n ...props\n}) => {\n const insideField = useInsideField();\n const insideControl = useInsideControl();\n const ownField = rendersOwnField('Checkboxes', {\n insideField,\n insideControl,\n label,\n message,\n horizontal,\n fieldClassName,\n });\n // As a fieldset with a Field of its own, the group's label is its legend,\n // which names it with no id, so nothing points `aria-labelledby` at it.\n const asFieldset = as === 'fieldset';\n const fieldsetField = asFieldset && ownField;\n const { ariaLabelledBy, fieldLabelProps } = useAutoLabelledBy({\n label,\n labelProps,\n rendersLabel: ownField && !fieldsetField,\n callerProps: props,\n });\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n ...props,\n });\n\n const mainClass = usePrefixedClassNames('checkboxes');\n const wrapperClass = classNames(mainClass, bulmaHelperClasses, className);\n\n const helpClass = usePrefixedClassNames('help', {\n [`is-${messageColor}`]: !!messageColor,\n });\n const messageEl = message ? <p className={helpClass}>{message}</p> : null;\n\n const groupActive =\n value !== undefined || defaultValue !== undefined || onChange !== undefined;\n\n const [internalValue, setInternalValue] = useState<string[] | undefined>(\n defaultValue\n );\n const isControlled = value !== undefined;\n const currentValue = isControlled ? value : internalValue;\n\n const handleChange = useCallback(\n (newValues: string[]) => {\n if (!isControlled) setInternalValue(newValues);\n onChange?.(newValues);\n },\n [isControlled, onChange]\n );\n\n const ctx = useMemo<CheckboxesGroupContextValue>(\n () => ({\n name,\n ...(groupActive ? { value: currentValue, onChange: handleChange } : {}),\n }),\n [name, groupActive, currentValue, handleChange]\n );\n\n const choices = (\n <CheckboxesProvider value={ctx}>{children}</CheckboxesProvider>\n );\n // A fieldset is a group already, so it takes no role of its own.\n const Group = asFieldset ? 'fieldset' : 'div';\n const checkboxesElement = fieldsetField ? (\n <div className={wrapperClass}>{choices}</div>\n ) : (\n <Group\n className={wrapperClass}\n role={asFieldset ? undefined : 'group'}\n aria-labelledby={ariaLabelledBy}\n {...rest}\n >\n {choices}\n </Group>\n );\n\n let content = checkboxesElement;\n\n if (rendersOwnControl('Checkboxes', { insideControl })) {\n content = <Control>{content}</Control>;\n }\n\n if (fieldsetField) {\n return (\n <GroupFieldset\n label={label}\n labelSize={labelSize}\n labelProps={labelProps}\n horizontal={horizontal}\n fieldClassName={fieldClassName}\n attributes={rest}\n message={messageEl}\n >\n {content}\n </GroupFieldset>\n );\n }\n\n if (ownField) {\n return (\n <Field\n label={label}\n labelSize={labelSize}\n labelProps={fieldLabelProps}\n horizontal={horizontal}\n className={fieldClassName}\n >\n {content}\n {messageEl}\n </Field>\n );\n }\n\n return (\n <>\n {content}\n {messageEl}\n </>\n );\n};\n\nexport const Checkboxes = withSubComponents(\n CheckboxesComponent,\n { Checkbox },\n 'Checkboxes'\n);\n\nexport default Checkboxes;\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":";;;;;;;;;;;;;AAgEA;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AACH,MAAM,mBAAmB,GAA8B,CAAC,EACtD,KAAK,EACL,SAAS,EACT,UAAU,EACV,UAAU,EACV,OAAO,EACP,YAAY,EACZ,cAAc,EACd,IAAI,EACJ,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,EAAE,EACF,GAAG,KAAK,EACT,KAAI;AACH,IAAA,MAAM,WAAW,GAAG,cAAc,EAAE;AACpC,IAAA,MAAM,aAAa,GAAG,gBAAgB,EAAE;AACxC,IAAA,MAAM,QAAQ,GAAG,eAAe,CAAC,YAAY,EAAE;QAC7C,WAAW;QACX,aAAa;QACb,KAAK;QACL,OAAO;QACP,UAAU;QACV,cAAc;AACf,KAAA,CAAC;;;AAGF,IAAA,MAAM,UAAU,GAAG,EAAE,KAAK,UAAU;AACpC,IAAA,MAAM,aAAa,GAAG,UAAU,IAAI,QAAQ;AAC5C,IAAA,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,GAAG,iBAAiB,CAAC;QAC5D,KAAK;QACL,UAAU;AACV,QAAA,YAAY,EAAE,QAAQ,IAAI,CAAC,aAAa;AACxC,QAAA,WAAW,EAAE,KAAK;AACnB,KAAA,CAAC;AACF,IAAA,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC;AACnD,QAAA,GAAG,KAAK;AACT,KAAA,CAAC;AAEF,IAAA,MAAM,SAAS,GAAG,qBAAqB,CAAC,YAAY,CAAC;IACrD,MAAM,YAAY,GAAG,UAAU,CAAC,SAAS,EAAE,kBAAkB,EAAE,SAAS,CAAC;AAEzE,IAAA,MAAM,SAAS,GAAG,qBAAqB,CAAC,MAAM,EAAE;AAC9C,QAAA,CAAC,MAAM,YAAY,CAAA,CAAE,GAAG,CAAC,CAAC,YAAY;AACvC,KAAA,CAAC;AACF,IAAA,MAAM,SAAS,GAAG,OAAO,GAAGA,GAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAE,SAAS,YAAG,OAAO,EAAA,CAAK,GAAG,IAAI;AAEzE,IAAA,MAAM,WAAW,GACf,KAAK,KAAK,SAAS,IAAI,YAAY,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS;IAE7E,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAChD,YAAY,CACb;AACD,IAAA,MAAM,YAAY,GAAG,KAAK,KAAK,SAAS;IACxC,MAAM,YAAY,GAAG,YAAY,GAAG,KAAK,GAAG,aAAa;AAEzD,IAAA,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,SAAmB,KAAI;AACtB,QAAA,IAAI,CAAC,YAAY;YAAE,gBAAgB,CAAC,SAAS,CAAC;AAC9C,QAAA,QAAQ,GAAG,SAAS,CAAC;AACvB,IAAA,CAAC,EACD,CAAC,YAAY,EAAE,QAAQ,CAAC,CACzB;AAED,IAAA,MAAM,GAAG,GAAG,OAAO,CACjB,OAAO;QACL,IAAI;AACJ,QAAA,IAAI,WAAW,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;KACxE,CAAC,EACF,CAAC,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,CAAC,CAChD;AAED,IAAA,MAAM,OAAO,IACXA,GAAA,CAAC,kBAAkB,EAAA,EAAC,KAAK,EAAE,GAAG,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAsB,CAChE;;IAED,MAAM,KAAK,GAAG,UAAU,GAAG,UAAU,GAAG,KAAK;IAC7C,MAAM,iBAAiB,GAAG,aAAa,IACrCA,aAAK,SAAS,EAAE,YAAY,EAAA,QAAA,EAAG,OAAO,GAAO,KAE7CA,IAAC,KAAK,EAAA,EACJ,SAAS,EAAE,YAAY,EACvB,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,qBACrB,cAAc,EAAA,GAC3B,IAAI,EAAA,QAAA,EAEP,OAAO,EAAA,CACF,CACT;IAED,IAAI,OAAO,GAAG,iBAAiB;IAE/B,IAAI,iBAAiB,CAAC,YAAY,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE;AACtD,QAAA,OAAO,GAAGA,GAAA,CAAC,OAAO,EAAA,EAAA,QAAA,EAAE,OAAO,GAAW;IACxC;IAEA,IAAI,aAAa,EAAE;AACjB,QAAA,QACEA,GAAA,CAAC,aAAa,EAAA,EACZ,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,IAAI,EAChB,OAAO,EAAE,SAAS,EAAA,QAAA,EAEjB,OAAO,EAAA,CACM;IAEpB;IAEA,IAAI,QAAQ,EAAE;AACZ,QAAA,QACEC,IAAA,CAAC,KAAK,EAAA,EACJ,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,eAAe,EAC3B,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,cAAc,EAAA,QAAA,EAAA,CAExB,OAAO,EACP,SAAS,CAAA,EAAA,CACJ;IAEZ;AAEA,IAAA,QACEA,IAAA,CAAAC,QAAA,EAAA,EAAA,QAAA,EAAA,CACG,OAAO,EACP,SAAS,CAAA,EAAA,CACT;AAEP,CAAC;AAEM,MAAM,UAAU,GAAG,iBAAiB,CACzC,mBAAmB,EACnB,EAAE,QAAQ,EAAE,EACZ,YAAY;;"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { forwardRef, useCallback, useId } from 'react';
|
|
4
|
+
import { usePrefixedClassNames, classNames } from '../helpers/classNames.js';
|
|
5
|
+
import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
|
|
6
|
+
import { useRadiosGroup } from './FormContext.js';
|
|
7
|
+
|
|
8
|
+
// The colors `Radio` takes, as `radioColors` lists them. Declared here as
|
|
9
|
+
// well, so the API page can read them off this module, and a type test holds
|
|
10
|
+
// the two lists to each other.
|
|
11
|
+
const radioCardColors = [
|
|
12
|
+
'primary',
|
|
13
|
+
'link',
|
|
14
|
+
'info',
|
|
15
|
+
'success',
|
|
16
|
+
'warning',
|
|
17
|
+
'danger',
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* The `RadioCard` component is a radio button drawn as a card, with a title and a description, picked wherever you click it.
|
|
21
|
+
*
|
|
22
|
+
* It's a `<label>` around a real radio, so it sends its `value` with a form,
|
|
23
|
+
* and the cards that share a `name` are one choice the arrow keys move
|
|
24
|
+
* through. The title names the radio and the description describes it.
|
|
25
|
+
* Inside `Radios` it takes the group's name and selection, as `Radio` does.
|
|
26
|
+
*
|
|
27
|
+
* @function
|
|
28
|
+
* @param {RadioCardProps} props - Props for the RadioCard component.
|
|
29
|
+
* @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the `<input>`.
|
|
30
|
+
* @returns {JSX.Element} The rendered card.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* <Radios label="Shipping" name="shipping" defaultValue="standard">
|
|
34
|
+
* <RadioCard value="standard" title="Standard" description="Arrives in 4 to 6 days." />
|
|
35
|
+
* <RadioCard value="express" title="Express" description="Arrives tomorrow." />
|
|
36
|
+
* </Radios>
|
|
37
|
+
*/
|
|
38
|
+
const RadioCard = forwardRef(({ title, description, children, hasIndicator = true, color, className, textColor, disabled, name, value, checked, defaultChecked, onChange, ...props }, ref) => {
|
|
39
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
40
|
+
color: textColor,
|
|
41
|
+
...props,
|
|
42
|
+
});
|
|
43
|
+
// A surrounding <Radios> hands down its name and, when it manages the
|
|
44
|
+
// selection, whether this card is the one picked. The card's own props
|
|
45
|
+
// win, as they do on Radio.
|
|
46
|
+
const group = useRadiosGroup();
|
|
47
|
+
const effectiveName = name ?? group?.name;
|
|
48
|
+
const groupManaged = group?.value !== undefined && value !== undefined;
|
|
49
|
+
const effectiveChecked = checked !== undefined
|
|
50
|
+
? checked
|
|
51
|
+
: groupManaged
|
|
52
|
+
? group.value === value
|
|
53
|
+
: undefined;
|
|
54
|
+
const effectiveDefaultChecked = groupManaged ? undefined : defaultChecked;
|
|
55
|
+
const handleChange = useCallback((e) => {
|
|
56
|
+
onChange?.(e);
|
|
57
|
+
if (group?.onChange && value !== undefined) {
|
|
58
|
+
group.onChange(String(value));
|
|
59
|
+
}
|
|
60
|
+
}, [onChange, group, value]);
|
|
61
|
+
// The title names the input and the description describes it. A name
|
|
62
|
+
// passed in wins, and without one of either the label's own text names
|
|
63
|
+
// the input, description included, so it isn't described again.
|
|
64
|
+
const titleId = useId();
|
|
65
|
+
const descriptionId = useId();
|
|
66
|
+
const ariaLabel = rest['aria-label'];
|
|
67
|
+
const ariaLabelledBy = rest['aria-labelledby'] || (!ariaLabel && title ? titleId : undefined);
|
|
68
|
+
const ariaDescribedBy = rest['aria-describedby'] ||
|
|
69
|
+
(description && (ariaLabel || ariaLabelledBy)
|
|
70
|
+
? descriptionId
|
|
71
|
+
: undefined);
|
|
72
|
+
const cardClass = usePrefixedClassNames('radio-card', 'card', {
|
|
73
|
+
[`is-${color}`]: color && radioCardColors.includes(color),
|
|
74
|
+
});
|
|
75
|
+
const contentClass = usePrefixedClassNames('card-content', 'radio-card-content');
|
|
76
|
+
const checkClass = usePrefixedClassNames('radio-card-check');
|
|
77
|
+
const bodyClass = usePrefixedClassNames('radio-card-body');
|
|
78
|
+
const titleClass = usePrefixedClassNames('radio-card-title');
|
|
79
|
+
const descriptionClass = usePrefixedClassNames('radio-card-description');
|
|
80
|
+
return (jsxs("label", { className: classNames(cardClass, bulmaHelperClasses, className), children: [jsx("input", { ref: ref, type: "radio", disabled: disabled, name: effectiveName, value: value, checked: effectiveChecked, defaultChecked: effectiveDefaultChecked, onChange: handleChange, ...rest, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy }), jsxs("span", { className: contentClass, children: [hasIndicator && jsx("span", { className: checkClass }), jsxs("span", { className: bodyClass, children: [title ? (jsx("span", { id: titleId, className: titleClass, children: title })) : null, description ? (jsx("span", { id: descriptionId, className: descriptionClass, children: description })) : null, children] })] })] }));
|
|
81
|
+
});
|
|
82
|
+
RadioCard.displayName = 'RadioCard';
|
|
83
|
+
|
|
84
|
+
export { RadioCard };
|
|
85
|
+
//# sourceMappingURL=RadioCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RadioCard.js","sources":["../../../src/form/RadioCard.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useId } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport { useRadiosGroup } from './FormContext';\n\n// The colors `Radio` takes, as `radioColors` lists them. Declared here as\n// well, so the API page can read them off this module, and a type test holds\n// the two lists to each other.\nconst radioCardColors = [\n 'primary',\n 'link',\n 'info',\n 'success',\n 'warning',\n 'danger',\n] as const;\n\n/**\n * Props for the RadioCard component.\n *\n * @helperProps Helper props go on the outer `<label>`, the `.card`, with\n * `className`. The other attributes go on the `<input>`.\n * @extraProp {string} [name] - The form field name, which the cards of one choice share, so the arrow keys move between them. Inside `Radios`, the group's `name` when this is unset.\n * @extraProp {string} [value] - What a form sends when this card is the one picked. Inside a `Radios` group that takes `value`, `defaultValue` or `onChange`, the card is checked while the group's value is this.\n */\nexport interface RadioCardProps\n extends\n Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'type' | 'color' | 'title'\n >,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor' | 'size'> {\n /**\n * What the option is, such as \"Express\". It names the radio, so a screen\n * reader says it with the state and its place in the group. Without it,\n * the card's whole text names the radio, as a label's text does.\n */\n title?: React.ReactNode;\n /**\n * A line or two about the option, read after the name and the state. It's\n * the radio's description when `title`, `aria-label` or `aria-labelledby`\n * names it. Without one of those it's part of the name already, so it\n * isn't read twice.\n */\n description?: React.ReactNode;\n /**\n * Anything else in the card, after the description, such as a price. A\n * label holds phrasing content only, so spans, images and links: a link\n * works and doesn't pick the card, but a button or another input can't go\n * inside a label at all. It isn't read when the radio takes focus, so put\n * what a screen reader should hear in `title` and `description`.\n */\n children?: React.ReactNode;\n /**\n * Shows the radio at the start of the card. Without it, the card's edge\n * alone shows the selection, and it's thicker when picked, so the\n * selection never rests on color.\n */\n hasIndicator?: boolean;\n /** The color of the radio and of a picked card's edge. */\n color?: (typeof radioCardColors)[number];\n /**\n * Text color helper, on the card. The title and the children take it, and\n * the description keeps its own color.\n */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Whether the card is disabled. A disabled card dims, takes no clicks, and the arrow keys skip it. */\n disabled?: boolean;\n /**\n * Additional CSS classes, on the outer `<label>`, the card. That's the\n * element that declares the `--bulma-radio-card-*` variables, and Bulma's\n * `--bulma-card-*` ones, so a class is how to set one: `style` and the\n * other input attributes go to the `<input>`. Name `.radio-card` beside\n * your class in the selector, so it beats the card's own declaration\n * whatever order the stylesheets load in. A `color` prop declares the\n * active color again on `.radio-card.is-<color>`, which ties that\n * selector, so leave `color` unset when a class sets it.\n */\n className?: string;\n}\n\n/**\n * The `RadioCard` component is a radio button drawn as a card, with a title and a description, picked wherever you click it.\n *\n * It's a `<label>` around a real radio, so it sends its `value` with a form,\n * and the cards that share a `name` are one choice the arrow keys move\n * through. The title names the radio and the description describes it.\n * Inside `Radios` it takes the group's name and selection, as `Radio` does.\n *\n * @function\n * @param {RadioCardProps} props - Props for the RadioCard component.\n * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the `<input>`.\n * @returns {JSX.Element} The rendered card.\n *\n * @example\n * <Radios label=\"Shipping\" name=\"shipping\" defaultValue=\"standard\">\n * <RadioCard value=\"standard\" title=\"Standard\" description=\"Arrives in 4 to 6 days.\" />\n * <RadioCard value=\"express\" title=\"Express\" description=\"Arrives tomorrow.\" />\n * </Radios>\n */\nexport const RadioCard = forwardRef<HTMLInputElement, RadioCardProps>(\n (\n {\n title,\n description,\n children,\n hasIndicator = true,\n color,\n className,\n textColor,\n disabled,\n name,\n value,\n checked,\n defaultChecked,\n onChange,\n ...props\n },\n ref\n ) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n ...props,\n });\n\n // A surrounding <Radios> hands down its name and, when it manages the\n // selection, whether this card is the one picked. The card's own props\n // win, as they do on Radio.\n const group = useRadiosGroup();\n const effectiveName = name ?? group?.name;\n const groupManaged = group?.value !== undefined && value !== undefined;\n const effectiveChecked =\n checked !== undefined\n ? checked\n : groupManaged\n ? group!.value === value\n : undefined;\n const effectiveDefaultChecked = groupManaged ? undefined : defaultChecked;\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange?.(e);\n if (group?.onChange && value !== undefined) {\n group.onChange(String(value));\n }\n },\n [onChange, group, value]\n );\n\n // The title names the input and the description describes it. A name\n // passed in wins, and without one of either the label's own text names\n // the input, description included, so it isn't described again.\n const titleId = useId();\n const descriptionId = useId();\n const ariaLabel = rest['aria-label'];\n const ariaLabelledBy =\n rest['aria-labelledby'] || (!ariaLabel && title ? titleId : undefined);\n const ariaDescribedBy =\n rest['aria-describedby'] ||\n (description && (ariaLabel || ariaLabelledBy)\n ? descriptionId\n : undefined);\n\n const cardClass = usePrefixedClassNames('radio-card', 'card', {\n [`is-${color}`]: color && radioCardColors.includes(color),\n });\n const contentClass = usePrefixedClassNames(\n 'card-content',\n 'radio-card-content'\n );\n const checkClass = usePrefixedClassNames('radio-card-check');\n const bodyClass = usePrefixedClassNames('radio-card-body');\n const titleClass = usePrefixedClassNames('radio-card-title');\n const descriptionClass = usePrefixedClassNames('radio-card-description');\n\n return (\n <label className={classNames(cardClass, bulmaHelperClasses, className)}>\n <input\n ref={ref}\n type=\"radio\"\n disabled={disabled}\n name={effectiveName}\n value={value}\n checked={effectiveChecked}\n defaultChecked={effectiveDefaultChecked}\n onChange={handleChange}\n {...rest}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n />\n <span className={contentClass}>\n {hasIndicator && <span className={checkClass} />}\n <span className={bodyClass}>\n {title ? (\n <span id={titleId} className={titleClass}>\n {title}\n </span>\n ) : null}\n {description ? (\n <span id={descriptionId} className={descriptionClass}>\n {description}\n </span>\n ) : null}\n {children}\n </span>\n </span>\n </label>\n );\n }\n);\n\nRadioCard.displayName = 'RadioCard';\n\nexport default RadioCard;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
package/dist/esm/form/Radios.js
CHANGED
|
@@ -9,6 +9,7 @@ import { Field } from './Field.js';
|
|
|
9
9
|
import { Control } from './Control.js';
|
|
10
10
|
import { useAutoLabelledBy } from './useAutoLabelId.js';
|
|
11
11
|
import { Radio } from './Radio.js';
|
|
12
|
+
import { GroupFieldset } from './groupFieldset.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* The `Radios` component wraps multiple `Radio` components in a Bulma-styled group.
|
|
@@ -34,7 +35,7 @@ import { Radio } from './Radio.js';
|
|
|
34
35
|
* <Radio value="green">Green</Radio>
|
|
35
36
|
* </Radios>
|
|
36
37
|
*/
|
|
37
|
-
const RadiosComponent = ({ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName, name, value, defaultValue, onChange, children, className, ...props }) => {
|
|
38
|
+
const RadiosComponent = ({ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName, name, value, defaultValue, onChange, children, className, as, ...props }) => {
|
|
38
39
|
const insideField = useInsideField();
|
|
39
40
|
const insideControl = useInsideControl();
|
|
40
41
|
const ownField = rendersOwnField('Radios', {
|
|
@@ -45,10 +46,14 @@ const RadiosComponent = ({ label, labelSize, labelProps, horizontal, message, me
|
|
|
45
46
|
horizontal,
|
|
46
47
|
fieldClassName,
|
|
47
48
|
});
|
|
49
|
+
// As a fieldset with a Field of its own, the group's label is its legend,
|
|
50
|
+
// which names it with no id, so nothing points `aria-labelledby` at it.
|
|
51
|
+
const asFieldset = as === 'fieldset';
|
|
52
|
+
const fieldsetField = asFieldset && ownField;
|
|
48
53
|
const { ariaLabelledBy, fieldLabelProps } = useAutoLabelledBy({
|
|
49
54
|
label,
|
|
50
55
|
labelProps,
|
|
51
|
-
rendersLabel: ownField,
|
|
56
|
+
rendersLabel: ownField && !fieldsetField,
|
|
52
57
|
callerProps: props,
|
|
53
58
|
});
|
|
54
59
|
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
@@ -76,11 +81,17 @@ const RadiosComponent = ({ label, labelSize, labelProps, horizontal, message, me
|
|
|
76
81
|
name,
|
|
77
82
|
...(groupActive ? { value: currentValue, onChange: handleChange } : {}),
|
|
78
83
|
}), [name, groupActive, currentValue, handleChange]);
|
|
79
|
-
const
|
|
84
|
+
const choices = jsx(RadiosProvider, { value: ctx, children: children });
|
|
85
|
+
// ARIA in HTML allows `radiogroup` on a fieldset, so it keeps the role.
|
|
86
|
+
const Group = asFieldset ? 'fieldset' : 'div';
|
|
87
|
+
const radiosElement = fieldsetField ? (jsx("div", { className: wrapperClass, children: choices })) : (jsx(Group, { className: wrapperClass, role: "radiogroup", "aria-labelledby": ariaLabelledBy, ...rest, children: choices }));
|
|
80
88
|
let content = radiosElement;
|
|
81
89
|
if (rendersOwnControl('Radios', { insideControl })) {
|
|
82
90
|
content = jsx(Control, { children: content });
|
|
83
91
|
}
|
|
92
|
+
if (fieldsetField) {
|
|
93
|
+
return (jsx(GroupFieldset, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, fieldClassName: fieldClassName, role: "radiogroup", attributes: rest, message: messageEl, children: content }));
|
|
94
|
+
}
|
|
84
95
|
if (ownField) {
|
|
85
96
|
return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
|
|
86
97
|
}
|