@allxsmith/bestax-bulma 5.34.0 → 5.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/form/Field.js +3 -3
- package/dist/esm/form/Field.js.map +1 -1
- package/dist/esm/form/FormContext.js +2 -1
- package/dist/esm/form/FormContext.js.map +1 -1
- package/dist/esm/form/Taginput.js +36 -6
- package/dist/esm/form/Taginput.js.map +1 -1
- package/dist/esm/form/useAutoLabelId.js.map +1 -1
- package/dist/index.cjs +40 -9
- package/dist/index.cjs.map +1 -1
- package/dist/types/form/Field.d.ts +5 -5
- package/dist/types/form/FormContext.d.ts +2 -1
- package/dist/types/form/Taginput.d.ts +8 -3
- package/dist/types/form/useAutoLabelId.d.ts +2 -2
- package/dist/types-cjs/form/Field.d.ts +5 -5
- package/dist/types-cjs/form/FormContext.d.ts +2 -1
- package/dist/types-cjs/form/Taginput.d.ts +8 -3
- package/dist/types-cjs/form/useAutoLabelId.d.ts +2 -2
- package/package.json +1 -1
package/dist/esm/form/Field.js
CHANGED
|
@@ -16,9 +16,9 @@ import { Control } from './Control.js';
|
|
|
16
16
|
* `id`, or give the horizontal `Field` a `label` prop, which renders this
|
|
17
17
|
* column and its `<label>` for you. A `<label>` you put here names the
|
|
18
18
|
* control through its `htmlFor` alone: a range `Slider`'s thumbs and an
|
|
19
|
-
* `Autocomplete`'s suggestion list point `aria-labelledby` at
|
|
20
|
-
* label only when its `label` prop renders it and it names the
|
|
21
|
-
* Where it would not name the control on its own, as in an inner `Field`,
|
|
19
|
+
* `Autocomplete`'s or `Taginput`'s suggestion list point `aria-labelledby` at
|
|
20
|
+
* a `Field`'s label only when its `label` prop renders it and it names the
|
|
21
|
+
* control. Where it would not name the control on its own, as in an inner `Field`,
|
|
22
22
|
* pass `labelProps={{ htmlFor, id }}` with a matching `id` on the control.
|
|
23
23
|
*
|
|
24
24
|
* @function
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Field.js","sources":["../../../src/form/Field.tsx"],"sourcesContent":["import React, { useCallback, useId, useMemo, useRef, useState } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport {\n FieldProvider,\n FieldLabelIdProvider,\n FieldLabelElementIdProvider,\n FieldLabelForProvider,\n FieldLabelForReportProvider,\n useFieldLabelFor,\n} from './FormContext';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport { Control } from './Control';\n\n/**\n * Props for the Field component.\n */\nexport interface FieldProps\n extends\n React.HTMLAttributes<HTMLDivElement>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Renders the field as horizontal (label and control side by side). */\n horizontal?: boolean;\n /** Group controls in a row (optionally centered, right, or multiline). */\n grouped?: boolean | 'centered' | 'right' | 'multiline';\n /** Group controls as addons (optionally centered or right-aligned). */\n hasAddons?: boolean | 'centered' | 'right';\n /** Constrains the field to its content's width (used inside horizontal field bodies). */\n narrow?: boolean;\n /** Field label, rendered above the widget. Automatically names the one control the Field holds: a composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase` or `DateTimeInputBase` (an `inline` picker has no input, so it takes nothing), or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id that the label's `htmlFor` points at, and a group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`, or a composed `DateRangeInputBase`, `inline` or not) points `aria-labelledby` at the label's own id unless you gave the group an `aria-label` or `aria-labelledby`. A range `Slider` takes the id on its low thumb and also starts each thumb's name with the label through `aria-labelledby`, unless its `ariaLabel` names that thumb or its own `aria-label` or `aria-labelledby` takes the label's place. An `Autocomplete` also names its open suggestion list after the label through `aria-labelledby`. Nothing else takes the label: `Checkbox`, `Radio` and `Switch` are named by their own children, and the label names one only when you wire it as you would any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's `id`. Only the single inputs take the `htmlFor`, so once the Field's content has mounted the label keeps it only while one of them holds the id, and drops it over anything else: a group, a `Checkbox`, `Radio` or `Switch`, an `inline` picker, an inner `Field`, an input with an `id` of its own, markup of your own, or nothing at all. A server render, and the first render while hydrating, still write the `htmlFor`, which keeps hydration matching, and an input that mounts later puts it back. The label names an input with an `id` of your own only through `labelProps={{ htmlFor }}` set to that `id`, a `for` it always keeps; `labelProps={{ htmlFor: undefined }}` opts out. Skipped for `grouped`/`hasAddons` fields (multiple controls), and a nested `Field` starts its own scope, so a horizontal Field whose body holds an inner `Field` names the control there only when you wire it. Two controls in one plain labeled Field would both adopt the id, so give each an `id` of its own. */\n label?: React.ReactNode;\n /** Size for the label. */\n labelSize?: 'small' | 'normal' | 'medium' | 'large';\n /** Props for the label element. An explicit `htmlFor` key — even set to `undefined` — takes over the association. While the association is on, the label renders with the `id` given here, or a generated one, and a group control, a range `Slider`'s thumbs and an `Autocomplete`'s suggestion list point `aria-labelledby` at it. A label you take over gets no generated id, and no group points at it on its own. With an `id` here, though, a range `Slider` or an `Autocomplete` whose `id` your `htmlFor` names still points its thumbs or its suggestion list at it, in a `grouped` or `hasAddons` Field too. To point a group in an inner `Field` at this label by hand, pass that `id`. Nothing in the inner `Field` takes the generated `htmlFor`, so the label drops it after mounting, and adding `htmlFor: undefined` keeps it out of server-rendered markup too. */\n labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {\n [key: string]: unknown;\n };\n /** Text color for the field. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Bulma color for the field. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color for the field. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Additional CSS classes. */\n className?: string;\n /** Field content. */\n children?: React.ReactNode;\n}\n\n/**\n * Props for the FieldLabel component.\n */\nexport interface FieldLabelProps\n extends\n React.HTMLAttributes<HTMLDivElement>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Size for the field label. */\n size?: 'small' | 'normal' | 'medium' | 'large';\n /** Text color for the label. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Bulma color for the label. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color for the label. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Additional CSS classes. */\n className?: string;\n /** Field label content. */\n children?: React.ReactNode;\n}\n\n/**\n * Props for the FieldBody component.\n */\nexport interface FieldBodyProps\n extends\n React.HTMLAttributes<HTMLDivElement>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Text color for the field body. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Bulma color for the field body. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color for the field body. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Additional CSS classes. */\n className?: string;\n /** Field body content. */\n children?: React.ReactNode;\n}\n\n/**\n * FieldLabel component for rendering a Bulma field label. It renders the\n * label column of a horizontal `Field` (a `div` with the `field-label` class),\n * not a `<label>`, so text placed straight in it names nothing. Put a `<label>`\n * with the `label` class inside it and point its `htmlFor` at the control's\n * `id`, or give the horizontal `Field` a `label` prop, which renders this\n * column and its `<label>` for you. A `<label>` you put here names the\n * control through its `htmlFor` alone: a range `Slider`'s thumbs and an\n * `Autocomplete`'s suggestion list point `aria-labelledby` at a `Field`'s\n * label only when its `label` prop renders it and it names the control.\n * Where it would not name the control on its own, as in an inner `Field`,\n * pass `labelProps={{ htmlFor, id }}` with a matching `id` on the control.\n *\n * @function\n * @param {FieldLabelProps} props - Props for the FieldLabel component.\n * @returns {JSX.Element} The rendered field label.\n *\n * @example\n * <FieldLabel size=\"normal\">\n * <label className=\"label\" htmlFor=\"name\">Name</label>\n * </FieldLabel>\n */\nexport const FieldLabel: React.FC<FieldLabelProps> = ({\n size,\n textColor,\n bgColor,\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n const mainClass = usePrefixedClassNames('field-label', {\n [`is-${size}`]: !!size,\n });\n const fieldLabelClass = classNames(mainClass, bulmaHelperClasses, className);\n // Spread ...props and ...rest so custom props like data-testid are included\n return (\n <div className={fieldLabelClass} {...props} {...rest}>\n {children}\n </div>\n );\n};\n\n/**\n * FieldBody component for rendering Bulma field body.\n *\n * @function\n * @param {FieldBodyProps} props - Props for the FieldBody component.\n * @returns {JSX.Element} The rendered field body.\n *\n * @example\n * <FieldBody><input className=\"input\" /></FieldBody>\n */\nexport const FieldBody: React.FC<FieldBodyProps> = ({\n textColor,\n bgColor,\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n const mainClass = usePrefixedClassNames('field-body');\n const fieldBodyClass = classNames(mainClass, bulmaHelperClasses, className);\n // Spread ...props and ...rest so custom props like data-testid are included\n return (\n <div className={fieldBodyClass} {...props} {...rest}>\n {children}\n </div>\n );\n};\n\n/**\n * The `Field` component is a Bulma-styled form field container.\n *\n * @function\n * @param {FieldProps} props - Props for the Field component.\n * @returns {JSX.Element} The rendered field container.\n * @see {@link https://bulma.io/documentation/form/general/#field | Bulma Field documentation}\n *\n * @example\n * // Labelled field — the label auto-associates with the composed base\n * <Field label=\"Email\">\n * <Control>\n * <InputBase type=\"email\" />\n * </Control>\n * </Field>\n *\n * @example\n * // Horizontal field\n * <Field horizontal label=\"Name\">\n * <Control>\n * <InputBase />\n * </Control>\n * </Field>\n */\nconst FieldComponent: React.FC<FieldProps> = ({\n horizontal,\n grouped,\n hasAddons,\n narrow,\n label,\n labelSize,\n labelProps,\n textColor,\n color: _fieldColor,\n bgColor,\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n const mainClass = usePrefixedClassNames('field', {\n 'is-horizontal': horizontal,\n 'has-addons': !!hasAddons,\n 'has-addons-centered': hasAddons === 'centered',\n 'has-addons-right': hasAddons === 'right',\n 'is-narrow': narrow,\n 'is-grouped':\n grouped === true ||\n grouped === 'centered' ||\n grouped === 'right' ||\n grouped === 'multiline',\n 'is-grouped-centered': grouped === 'centered',\n 'is-grouped-right': grouped === 'right',\n 'is-grouped-multiline': grouped === 'multiline',\n });\n const fieldClass = classNames(mainClass, bulmaHelperClasses, className);\n\n // Default labelSize to 'normal' when horizontal for proper baseline alignment\n const effectiveLabelSize = labelSize ?? (horizontal ? 'normal' : undefined);\n\n const labelClass = usePrefixedClassNames('label');\n\n // Auto-associate the label with a single composed base control (#495): the\n // label points at a generated id shared via context, which a composed base\n // adopts when the user supplied no id of their own.\n // Presence semantics on htmlFor — even an explicit `htmlFor: undefined`\n // means the caller owns the association. Grouped/addons fields hold several\n // controls, so no single association is generated for them.\n const generatedId = useId();\n const userWiredLabel = !!labelProps && 'htmlFor' in labelProps;\n const targetId =\n label && !userWiredLabel && !grouped && !hasAddons\n ? generatedId\n : undefined;\n // A group control (Radios, Checkboxes, Rate, DateRangeInput and its base)\n // cannot take that `for`, so it points `aria-labelledby` at the label\n // itself (#939).\n // The label gets an id whenever the association is on, unless the caller\n // gave it one.\n const labelId =\n labelProps?.id ?? (targetId ? `${targetId}-label` : undefined);\n // What the rendered label's `for` points at, generated or the caller's, and\n // the id it renders with, so a control can tell when a label wired by hand\n // names it and point at that label. An unlabeled Field passes on its\n // parent's. Unlike `targetId`, a label wired by hand passes on its own in\n // `grouped`/`hasAddons` Fields too, on purpose: those only stop the Field\n // picking one control out of several, and the caller's `for` has picked\n // one, so a range Slider or Autocomplete it names points at that label in\n // a row as well. A group reads the label element id below instead, which\n // stays off for a label wired by hand, since no group takes its `for`.\n const inheritedLabelFor = useFieldLabelFor();\n const labelForTarget = userWiredLabel ? labelProps.htmlFor : targetId;\n const ownLabelFor = useMemo(\n () => ({ htmlFor: labelForTarget, id: labelId }),\n [labelForTarget, labelId]\n );\n const labelFor = label ? ownLabelFor : inheritedLabelFor;\n\n // Whether the label keeps its generated `for` (#1004). Content that takes\n // the Field's id says so from a layout effect, and this Field's own layout\n // effect runs after its content's in the same commit, so by then every\n // report has landed. Until it runs, on the server and in the first render\n // while hydrating, the label writes the `for` as it always has. From then\n // on it keeps the `for` only while some content holds the id, and content\n // that mounts or changes later reports when it does. Counted in a ref, and\n // state is set only once settled, so content that takes the id renders\n // the Field just once.\n const takersRef = useRef(0);\n const settledRef = useRef(false);\n const [forTaken, setForTaken] = useState(true);\n const settle = useCallback(() => {\n if (settledRef.current) setForTaken(takersRef.current > 0);\n }, []);\n const reportLabelFor = useCallback(() => {\n takersRef.current += 1;\n settle();\n return () => {\n takersRef.current -= 1;\n settle();\n };\n }, [settle]);\n useClientLayoutEffect(() => {\n settledRef.current = true;\n if (targetId) settle();\n }, [targetId, settle]);\n const renderedTargetId = forTaken ? targetId : undefined;\n\n let renderedLabel = null;\n if (label) {\n if (horizontal) {\n renderedLabel = (\n <FieldLabel size={effectiveLabelSize}>\n <label\n htmlFor={renderedTargetId}\n {...labelProps}\n id={labelId}\n className={classNames(labelClass, labelProps?.className)}\n style={labelProps?.style}\n >\n {label}\n </label>\n </FieldLabel>\n );\n } else {\n renderedLabel = (\n <label\n htmlFor={renderedTargetId}\n {...labelProps}\n id={labelId}\n className={classNames(labelClass, labelProps?.className)}\n style={{ display: 'block', ...(labelProps?.style || {}) }}\n >\n {label}\n </label>\n );\n }\n }\n\n // If horizontal, wrap children in FieldBody (unless the user already provided\n // a FieldBody — either as the single child, or as one element among siblings\n // like <Field.Label/> + <Field.Body/>).\n let content = children;\n if (horizontal) {\n const isFieldBody = (c: React.ReactNode): boolean =>\n React.isValidElement(c) &&\n // @ts-expect-error displayName isn't on the public type\n (c.type === FieldBody || c.type?.displayName === 'FieldBody');\n const isFieldLabel = (c: React.ReactNode): boolean =>\n React.isValidElement(c) &&\n // @ts-expect-error displayName isn't on the public type\n (c.type === FieldLabel || c.type?.displayName === 'FieldLabel');\n const childArray = React.Children.toArray(children);\n const userProvidedStructure = childArray.some(\n c => isFieldBody(c) || isFieldLabel(c)\n );\n if (userProvidedStructure) {\n content = children;\n } else {\n content = <FieldBody>{children}</FieldBody>;\n }\n }\n\n return (\n <FieldProvider value={true}>\n <FieldLabelIdProvider value={targetId}>\n <FieldLabelElementIdProvider value={targetId ? labelId : undefined}>\n <FieldLabelForProvider value={labelFor}>\n <FieldLabelForReportProvider\n value={targetId ? reportLabelFor : undefined}\n >\n <div className={fieldClass} {...rest}>\n {renderedLabel}\n {content}\n </div>\n </FieldLabelForReportProvider>\n </FieldLabelForProvider>\n </FieldLabelElementIdProvider>\n </FieldLabelIdProvider>\n </FieldProvider>\n );\n};\n\nFieldLabel.displayName = 'FieldLabel';\nFieldBody.displayName = 'FieldBody';\n\nexport const Field = withSubComponents(\n FieldComponent,\n {\n Label: FieldLabel,\n Body: FieldBody,\n Control,\n },\n 'Field'\n);\n\nexport default Field;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Field.js","sources":["../../../src/form/Field.tsx"],"sourcesContent":["import React, { useCallback, useId, useMemo, useRef, useState } from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport {\n FieldProvider,\n FieldLabelIdProvider,\n FieldLabelElementIdProvider,\n FieldLabelForProvider,\n FieldLabelForReportProvider,\n useFieldLabelFor,\n} from './FormContext';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport { Control } from './Control';\n\n/**\n * Props for the Field component.\n */\nexport interface FieldProps\n extends\n React.HTMLAttributes<HTMLDivElement>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Renders the field as horizontal (label and control side by side). */\n horizontal?: boolean;\n /** Group controls in a row (optionally centered, right, or multiline). */\n grouped?: boolean | 'centered' | 'right' | 'multiline';\n /** Group controls as addons (optionally centered or right-aligned). */\n hasAddons?: boolean | 'centered' | 'right';\n /** Constrains the field to its content's width (used inside horizontal field bodies). */\n narrow?: boolean;\n /** Field label, rendered above the widget. Automatically names the one control the Field holds: a composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase` or `DateTimeInputBase` (an `inline` picker has no input, so it takes nothing), or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id that the label's `htmlFor` points at, and a group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`, or a composed `DateRangeInputBase`, `inline` or not) points `aria-labelledby` at the label's own id unless you gave the group an `aria-label` or `aria-labelledby`. A range `Slider` takes the id on its low thumb and also starts each thumb's name with the label through `aria-labelledby`, unless its `ariaLabel` names that thumb or its own `aria-label` or `aria-labelledby` takes the label's place. An `Autocomplete` or a `Taginput` also names its open suggestion list after the label through `aria-labelledby`. Nothing else takes the label: `Checkbox`, `Radio` and `Switch` are named by their own children, and the label names one only when you wire it as you would any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's `id`. Only the single inputs take the `htmlFor`, so once the Field's content has mounted the label keeps it only while one of them holds the id, and drops it over anything else: a group, a `Checkbox`, `Radio` or `Switch`, an `inline` picker, an inner `Field`, an input with an `id` of its own, markup of your own, or nothing at all. A server render, and the first render while hydrating, still write the `htmlFor`, which keeps hydration matching, and an input that mounts later puts it back. The label names an input with an `id` of your own only through `labelProps={{ htmlFor }}` set to that `id`, a `for` it always keeps; `labelProps={{ htmlFor: undefined }}` opts out. Skipped for `grouped`/`hasAddons` fields (multiple controls), and a nested `Field` starts its own scope, so a horizontal Field whose body holds an inner `Field` names the control there only when you wire it. Two controls in one plain labeled Field would both adopt the id, so give each an `id` of its own. */\n label?: React.ReactNode;\n /** Size for the label. */\n labelSize?: 'small' | 'normal' | 'medium' | 'large';\n /** Props for the label element. An explicit `htmlFor` key — even set to `undefined` — takes over the association. While the association is on, the label renders with the `id` given here, or a generated one, and a group control, a range `Slider`'s thumbs and an `Autocomplete`'s or `Taginput`'s suggestion list point `aria-labelledby` at it. A label you take over gets no generated id, and no group points at it on its own. With an `id` here, though, a range `Slider`, an `Autocomplete` or a `Taginput` whose `id` your `htmlFor` names still points its thumbs or its suggestion list at it, in a `grouped` or `hasAddons` Field too. To point a group in an inner `Field` at this label by hand, pass that `id`. Nothing in the inner `Field` takes the generated `htmlFor`, so the label drops it after mounting, and adding `htmlFor: undefined` keeps it out of server-rendered markup too. */\n labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {\n [key: string]: unknown;\n };\n /** Text color for the field. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Bulma color for the field. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color for the field. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Additional CSS classes. */\n className?: string;\n /** Field content. */\n children?: React.ReactNode;\n}\n\n/**\n * Props for the FieldLabel component.\n */\nexport interface FieldLabelProps\n extends\n React.HTMLAttributes<HTMLDivElement>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Size for the field label. */\n size?: 'small' | 'normal' | 'medium' | 'large';\n /** Text color for the label. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Bulma color for the label. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color for the label. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Additional CSS classes. */\n className?: string;\n /** Field label content. */\n children?: React.ReactNode;\n}\n\n/**\n * Props for the FieldBody component.\n */\nexport interface FieldBodyProps\n extends\n React.HTMLAttributes<HTMLDivElement>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Text color for the field body. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Bulma color for the field body. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color for the field body. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Additional CSS classes. */\n className?: string;\n /** Field body content. */\n children?: React.ReactNode;\n}\n\n/**\n * FieldLabel component for rendering a Bulma field label. It renders the\n * label column of a horizontal `Field` (a `div` with the `field-label` class),\n * not a `<label>`, so text placed straight in it names nothing. Put a `<label>`\n * with the `label` class inside it and point its `htmlFor` at the control's\n * `id`, or give the horizontal `Field` a `label` prop, which renders this\n * column and its `<label>` for you. A `<label>` you put here names the\n * control through its `htmlFor` alone: a range `Slider`'s thumbs and an\n * `Autocomplete`'s or `Taginput`'s suggestion list point `aria-labelledby` at\n * a `Field`'s label only when its `label` prop renders it and it names the\n * control. Where it would not name the control on its own, as in an inner `Field`,\n * pass `labelProps={{ htmlFor, id }}` with a matching `id` on the control.\n *\n * @function\n * @param {FieldLabelProps} props - Props for the FieldLabel component.\n * @returns {JSX.Element} The rendered field label.\n *\n * @example\n * <FieldLabel size=\"normal\">\n * <label className=\"label\" htmlFor=\"name\">Name</label>\n * </FieldLabel>\n */\nexport const FieldLabel: React.FC<FieldLabelProps> = ({\n size,\n textColor,\n bgColor,\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n const mainClass = usePrefixedClassNames('field-label', {\n [`is-${size}`]: !!size,\n });\n const fieldLabelClass = classNames(mainClass, bulmaHelperClasses, className);\n // Spread ...props and ...rest so custom props like data-testid are included\n return (\n <div className={fieldLabelClass} {...props} {...rest}>\n {children}\n </div>\n );\n};\n\n/**\n * FieldBody component for rendering Bulma field body.\n *\n * @function\n * @param {FieldBodyProps} props - Props for the FieldBody component.\n * @returns {JSX.Element} The rendered field body.\n *\n * @example\n * <FieldBody><input className=\"input\" /></FieldBody>\n */\nexport const FieldBody: React.FC<FieldBodyProps> = ({\n textColor,\n bgColor,\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n const mainClass = usePrefixedClassNames('field-body');\n const fieldBodyClass = classNames(mainClass, bulmaHelperClasses, className);\n // Spread ...props and ...rest so custom props like data-testid are included\n return (\n <div className={fieldBodyClass} {...props} {...rest}>\n {children}\n </div>\n );\n};\n\n/**\n * The `Field` component is a Bulma-styled form field container.\n *\n * @function\n * @param {FieldProps} props - Props for the Field component.\n * @returns {JSX.Element} The rendered field container.\n * @see {@link https://bulma.io/documentation/form/general/#field | Bulma Field documentation}\n *\n * @example\n * // Labelled field — the label auto-associates with the composed base\n * <Field label=\"Email\">\n * <Control>\n * <InputBase type=\"email\" />\n * </Control>\n * </Field>\n *\n * @example\n * // Horizontal field\n * <Field horizontal label=\"Name\">\n * <Control>\n * <InputBase />\n * </Control>\n * </Field>\n */\nconst FieldComponent: React.FC<FieldProps> = ({\n horizontal,\n grouped,\n hasAddons,\n narrow,\n label,\n labelSize,\n labelProps,\n textColor,\n color: _fieldColor,\n bgColor,\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n const mainClass = usePrefixedClassNames('field', {\n 'is-horizontal': horizontal,\n 'has-addons': !!hasAddons,\n 'has-addons-centered': hasAddons === 'centered',\n 'has-addons-right': hasAddons === 'right',\n 'is-narrow': narrow,\n 'is-grouped':\n grouped === true ||\n grouped === 'centered' ||\n grouped === 'right' ||\n grouped === 'multiline',\n 'is-grouped-centered': grouped === 'centered',\n 'is-grouped-right': grouped === 'right',\n 'is-grouped-multiline': grouped === 'multiline',\n });\n const fieldClass = classNames(mainClass, bulmaHelperClasses, className);\n\n // Default labelSize to 'normal' when horizontal for proper baseline alignment\n const effectiveLabelSize = labelSize ?? (horizontal ? 'normal' : undefined);\n\n const labelClass = usePrefixedClassNames('label');\n\n // Auto-associate the label with a single composed base control (#495): the\n // label points at a generated id shared via context, which a composed base\n // adopts when the user supplied no id of their own.\n // Presence semantics on htmlFor — even an explicit `htmlFor: undefined`\n // means the caller owns the association. Grouped/addons fields hold several\n // controls, so no single association is generated for them.\n const generatedId = useId();\n const userWiredLabel = !!labelProps && 'htmlFor' in labelProps;\n const targetId =\n label && !userWiredLabel && !grouped && !hasAddons\n ? generatedId\n : undefined;\n // A group control (Radios, Checkboxes, Rate, DateRangeInput and its base)\n // cannot take that `for`, so it points `aria-labelledby` at the label\n // itself (#939).\n // The label gets an id whenever the association is on, unless the caller\n // gave it one.\n const labelId =\n labelProps?.id ?? (targetId ? `${targetId}-label` : undefined);\n // What the rendered label's `for` points at, generated or the caller's, and\n // the id it renders with, so a control can tell when a label wired by hand\n // names it and point at that label. An unlabeled Field passes on its\n // parent's. Unlike `targetId`, a label wired by hand passes on its own in\n // `grouped`/`hasAddons` Fields too, on purpose: those only stop the Field\n // picking one control out of several, and the caller's `for` has picked\n // one, so a range Slider or Autocomplete it names points at that label in\n // a row as well. A group reads the label element id below instead, which\n // stays off for a label wired by hand, since no group takes its `for`.\n const inheritedLabelFor = useFieldLabelFor();\n const labelForTarget = userWiredLabel ? labelProps.htmlFor : targetId;\n const ownLabelFor = useMemo(\n () => ({ htmlFor: labelForTarget, id: labelId }),\n [labelForTarget, labelId]\n );\n const labelFor = label ? ownLabelFor : inheritedLabelFor;\n\n // Whether the label keeps its generated `for` (#1004). Content that takes\n // the Field's id says so from a layout effect, and this Field's own layout\n // effect runs after its content's in the same commit, so by then every\n // report has landed. Until it runs, on the server and in the first render\n // while hydrating, the label writes the `for` as it always has. From then\n // on it keeps the `for` only while some content holds the id, and content\n // that mounts or changes later reports when it does. Counted in a ref, and\n // state is set only once settled, so content that takes the id renders\n // the Field just once.\n const takersRef = useRef(0);\n const settledRef = useRef(false);\n const [forTaken, setForTaken] = useState(true);\n const settle = useCallback(() => {\n if (settledRef.current) setForTaken(takersRef.current > 0);\n }, []);\n const reportLabelFor = useCallback(() => {\n takersRef.current += 1;\n settle();\n return () => {\n takersRef.current -= 1;\n settle();\n };\n }, [settle]);\n useClientLayoutEffect(() => {\n settledRef.current = true;\n if (targetId) settle();\n }, [targetId, settle]);\n const renderedTargetId = forTaken ? targetId : undefined;\n\n let renderedLabel = null;\n if (label) {\n if (horizontal) {\n renderedLabel = (\n <FieldLabel size={effectiveLabelSize}>\n <label\n htmlFor={renderedTargetId}\n {...labelProps}\n id={labelId}\n className={classNames(labelClass, labelProps?.className)}\n style={labelProps?.style}\n >\n {label}\n </label>\n </FieldLabel>\n );\n } else {\n renderedLabel = (\n <label\n htmlFor={renderedTargetId}\n {...labelProps}\n id={labelId}\n className={classNames(labelClass, labelProps?.className)}\n style={{ display: 'block', ...(labelProps?.style || {}) }}\n >\n {label}\n </label>\n );\n }\n }\n\n // If horizontal, wrap children in FieldBody (unless the user already provided\n // a FieldBody — either as the single child, or as one element among siblings\n // like <Field.Label/> + <Field.Body/>).\n let content = children;\n if (horizontal) {\n const isFieldBody = (c: React.ReactNode): boolean =>\n React.isValidElement(c) &&\n // @ts-expect-error displayName isn't on the public type\n (c.type === FieldBody || c.type?.displayName === 'FieldBody');\n const isFieldLabel = (c: React.ReactNode): boolean =>\n React.isValidElement(c) &&\n // @ts-expect-error displayName isn't on the public type\n (c.type === FieldLabel || c.type?.displayName === 'FieldLabel');\n const childArray = React.Children.toArray(children);\n const userProvidedStructure = childArray.some(\n c => isFieldBody(c) || isFieldLabel(c)\n );\n if (userProvidedStructure) {\n content = children;\n } else {\n content = <FieldBody>{children}</FieldBody>;\n }\n }\n\n return (\n <FieldProvider value={true}>\n <FieldLabelIdProvider value={targetId}>\n <FieldLabelElementIdProvider value={targetId ? labelId : undefined}>\n <FieldLabelForProvider value={labelFor}>\n <FieldLabelForReportProvider\n value={targetId ? reportLabelFor : undefined}\n >\n <div className={fieldClass} {...rest}>\n {renderedLabel}\n {content}\n </div>\n </FieldLabelForReportProvider>\n </FieldLabelForProvider>\n </FieldLabelElementIdProvider>\n </FieldLabelIdProvider>\n </FieldProvider>\n );\n};\n\nFieldLabel.displayName = 'FieldLabel';\nFieldBody.displayName = 'FieldBody';\n\nexport const Field = withSubComponents(\n FieldComponent,\n {\n Label: FieldLabel,\n Body: FieldBody,\n Control,\n },\n 'Field'\n);\n\nexport default Field;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
@@ -175,7 +175,8 @@ const FieldLabelForContext = createContext({});
|
|
|
175
175
|
* renders with, if it has one. An unlabeled Field passes both through
|
|
176
176
|
* together, so a control in the inner Field of a horizontal layout can tell
|
|
177
177
|
* the outer label names it, and point at that label by its id, as a range
|
|
178
|
-
* Slider's thumbs (#981) and Autocomplete's
|
|
178
|
+
* Slider's thumbs (#981) and Autocomplete's and Taginput's suggestion lists
|
|
179
|
+
* (#998, #1082) do. The
|
|
179
180
|
* `htmlFor` is only ever compared with a control's own id, never adopted, so
|
|
180
181
|
* it hands out no id for a control. It keeps the generated id after the
|
|
181
182
|
* label drops a `for` nothing took (#1004), which no control's id matches
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormContext.js","sources":["../../../src/form/FormContext.tsx"],"sourcesContent":["import React, { createContext, useContext } from 'react';\nimport { warnOnce } from '../helpers/devWarnings';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport type { ControlBaseProps } from './Control';\n\nconst FieldContext = createContext(false);\nconst ControlContext = createContext(false);\n\n/**\n * Hook to detect if the component is inside a Field wrapper.\n * Form components use this to skip rendering their own Field.\n */\nexport const useInsideField = () => useContext(FieldContext);\n\n/**\n * Hook to detect if the component is inside a Control wrapper.\n * Form components use this to skip rendering their own Control.\n */\nexport const useInsideControl = () => useContext(ControlContext);\n\n/** Provider for Field context — used internally by Field component. */\nexport const FieldProvider = FieldContext.Provider;\n\n/** Provider for Control context — used internally by Control component. */\nexport const ControlProvider = ControlContext.Provider;\n\n/** The wrapper props that change what its own `Field` renders. */\ninterface FieldShapingProps {\n /** Rendered as the `Field`'s label. */\n label?: React.ReactNode;\n /** Rendered as help text after the widget. */\n message?: React.ReactNode;\n /** Lays the `Field` out horizontally. */\n horizontal?: boolean;\n /** Set on the `Field` as its class. */\n fieldClassName?: string;\n}\n\ninterface OwnFieldOptions extends FieldShapingProps {\n /** `useInsideField()` as the wrapper read it. */\n insideField: boolean;\n /** `useInsideControl()` as the wrapper read it. */\n insideControl: boolean;\n}\n\n// Each Field-shaping prop, with what takes its place on a `Field` the caller\n// wraps around the `Control`. `message` needs nothing there, because the\n// wrapper still renders it inside `Field > Control`. The other Field-level\n// props (`labelSize`, `labelProps`, `messageColor`) change nothing unless a\n// `label` or `message` renders, so on their own they keep no `Field`.\n// `bare-control.test.tsx` holds this list to what each wrapper hands its\n// `Field` and to which props change its markup, so a new Field-level prop\n// fails there until it is sorted into one group or the other.\nconst FIELD_SHAPING: ReadonlyArray<\n [keyof FieldShapingProps, string | undefined]\n> = [\n ['label', 'label'],\n ['message', undefined],\n ['horizontal', 'horizontal'],\n ['fieldClassName', 'className (for fieldClassName)'],\n];\n\n/** `a`, `a and b`, `a, b and c`. */\nconst listOf = (items: string[]): string =>\n items.length > 1\n ? `${items.slice(0, -1).join(', ')} and ${items[items.length - 1]}`\n : items[0];\n\n/**\n * Whether a convenience form wrapper renders a `Field` of its own (#905).\n * Never inside an outer `Field`. Inside a `Control` with no `Field` around\n * it, a `Field` of its own would put a `.field` inside the `.control`, where\n * Bulma's control styles break (its icon rules are sibling selectors on the\n * input). So it renders one there only when a prop that shapes the `Field`'s\n * markup is set (`label`, `message`, `horizontal`, `fieldClassName`), keeping\n * the markup it always had, and warns in development that the fix is a\n * `Field` around that `Control`. A prop counts when it is truthy, the same\n * test that decides whether it changes the `Field`'s output.\n * Internal; not part of the public API.\n */\nexport const rendersOwnField = (\n component: string,\n options: OwnFieldOptions\n): boolean => {\n if (options.insideField) return false;\n if (!options.insideControl) return true;\n const held = FIELD_SHAPING.filter(([prop]) => options[prop]);\n if (held.length === 0) return false;\n const names = held.map(([prop]) => prop);\n const moved = held\n .map(([, onField]) => onField)\n .filter((onField): onField is string => onField !== undefined);\n warnOnce(\n `${component}:Field-in-bare-Control:${names.join('+')}`,\n `[bestax-bulma] <${component} ${names.join(' ')}> inside a <Control> ` +\n `with no <Field> around it renders its own <Field> for ` +\n `${names.length > 1 ? 'those props' : 'that prop'}, which puts a ` +\n `.field inside the .control, a nesting Bulma's styles are not ` +\n `written for. Wrap the <Control> in a <Field> instead` +\n (moved.length > 0 ? `, and set ${listOf(moved)} on that <Field>.` : '.')\n );\n return true;\n};\n\n/** The props a convenience form wrapper hands its own `Control`. Internal. */\nexport interface ControlLevelProps {\n /** Shows the `Control`'s loading spinner. */\n isLoading?: boolean;\n /** The `Control`'s left icon. */\n iconLeft?: ControlBaseProps['iconLeft'];\n /** Shortcut for the left icon's name. */\n iconLeftName?: string;\n /** Shortcut for the left icon's size. */\n iconLeftSize?: ControlBaseProps['iconLeftSize'];\n /** The `Control`'s right icon. */\n iconRight?: ControlBaseProps['iconRight'];\n /** Shortcut for the right icon's name. */\n iconRightName?: string;\n /** Shortcut for the right icon's size. */\n iconRightSize?: ControlBaseProps['iconRightSize'];\n /** Reserves the `Control`'s left icon space. */\n hasIconsLeft?: boolean;\n /** Reserves the `Control`'s right icon space. */\n hasIconsRight?: boolean;\n /** Expands the `Control`. */\n isExpanded?: boolean;\n /** Set on the `Control` as its `size`. */\n controlSize?: ControlBaseProps['size'];\n /** Set on the `Control` as its class. */\n controlClassName?: string;\n}\n\ninterface OwnControlOptions extends ControlLevelProps {\n /** `useInsideControl()` as the wrapper read it. */\n insideControl: boolean;\n /** A picker's `inline`, which renders no `Control` inside one or out. */\n inline?: boolean;\n /**\n * The left glyph the wrapper's own `Control` shows when the caller sets no\n * `iconLeftName`; read only then. `bare-control.test.tsx` reads that glyph\n * from what each wrapper hands its own `Control`, so a wrapper that gains\n * one fails there until it passes it here.\n */\n defaultIconLeftName?: string;\n}\n\n// Each Control-level prop, with what takes its place on the `Control` the\n// caller wrapped around the wrapper. `bare-control.test.tsx` holds this to\n// what each wrapper hands its own `Control`, so a new Control-level prop\n// fails there until it is added here and passed to `rendersOwnControl`.\nconst ON_CONTROL: Record<keyof ControlLevelProps, string> = {\n isLoading: 'isLoading',\n iconLeft: 'iconLeft',\n iconLeftName: 'iconLeftName',\n iconLeftSize: 'iconLeftSize',\n iconRight: 'iconRight',\n iconRightName: 'iconRightName',\n iconRightSize: 'iconRightSize',\n hasIconsLeft: 'hasIconsLeft',\n hasIconsRight: 'hasIconsRight',\n isExpanded: 'isExpanded',\n controlSize: 'size (for controlSize)',\n controlClassName: 'className (for controlClassName)',\n};\n\n/**\n * Whether a convenience form wrapper renders a `Control` of its own (#921):\n * only outside one. Inside a `Control` it renders none, so the props it\n * would have handed its own do nothing there, and it warns in development,\n * naming them and saying to set them on that `Control`. An `inline` picker\n * renders none in either place, so it drops them inside a `Control` or not,\n * and its warning says so without pointing at a `Control`. A wrapper passes\n * only the props it hands its own `Control`, as the caller gave them, so a\n * default the wrapper fills in itself never warns. A prop counts when it is\n * truthy, since a falsy one would change nothing on a `Control` either.\n * `iconLeftSize` and `hasIconsLeft` show nothing on a `Control` without a\n * glyph, so when they move and the caller chose no left icon, the advice\n * names the wrapper's default glyph too, and following it draws what the\n * wrapper's own `Control` did.\n * Internal; not part of the public API.\n */\nexport const rendersOwnControl = (\n component: string,\n options: OwnControlOptions\n): boolean => {\n if (!options.inline && !options.insideControl) return true;\n const held = (\n Object.keys(ON_CONTROL) as Array<keyof ControlLevelProps>\n ).filter(prop => options[prop]);\n if (held.length === 0) return false;\n const names = held.join(' ');\n const doNothing = held.length > 1 ? 'those props do' : 'that prop does';\n let message: string;\n if (options.inline) {\n message =\n `[bestax-bulma] <${component} inline ${names}> renders no <Control> ` +\n `in inline mode, inside a <Control> or not, so ${doNothing} ` +\n `nothing. Leave ${held.length > 1 ? 'them' : 'it'} out of an ` +\n `inline picker.`;\n } else {\n const toSet = held.map(prop => ON_CONTROL[prop]);\n const needsGlyph =\n (options.iconLeftSize || options.hasIconsLeft) &&\n !options.iconLeft &&\n options.iconLeftName === undefined &&\n options.defaultIconLeftName;\n if (needsGlyph) {\n toSet.push(\n `iconLeftName=\"${options.defaultIconLeftName}\" (its default icon)`\n );\n }\n message =\n `[bestax-bulma] <${component} ${names}> inside a <Control> renders ` +\n `no <Control> of its own, so ${doNothing} nothing there. Set ` +\n `${listOf(toSet)} on that <Control> instead.`;\n }\n // Keyed by the message itself: the props named do not settle the advice\n // (an empty `iconLeftName` and an unset one name the same props), so two\n // calls that would advise differently must not share a key.\n warnOnce(message, message);\n return false;\n};\n\nconst FieldLabelIdContext = createContext<string | undefined>(undefined);\n\n/**\n * The id a labeled Field wants its single composed control to adopt (#495).\n * `undefined` outside a Field, in unlabeled/grouped/addons Fields, or when the\n * user took over the association with an explicit `labelProps.htmlFor`.\n * Consumed through `useFieldLabelTarget` by the single-control bases\n * (InputBase, SelectBase, TextAreaBase, and the date and time picker bases\n * unless inline, #968) and, through `useAutoLabelId`, by the convenience\n * inputs that render an input of their own (#939). Read it only through\n * those, which report what they take: a control that read it directly would\n * report nothing and lose its label (#1004), and\n * `__tests__/field-label-readers.test.ts` fails on one. Internal; not part of\n * the public API.\n */\nexport const useFieldLabelId = () => useContext(FieldLabelIdContext);\n\n/** Provider for the Field label-target id — used internally by Field. */\nexport const FieldLabelIdProvider = FieldLabelIdContext.Provider;\n\nconst FieldLabelElementIdContext = createContext<string | undefined>(undefined);\n\n/**\n * The id of a labeled Field's own `<label>`, for a group control (Radios,\n * Checkboxes, Rate, DateRangeInput and DateRangeInputBase) to point\n * `aria-labelledby` at, since a group cannot take the label's `htmlFor`\n * (#939, #1005). Set under the same conditions as\n * {@link useFieldLabelId}. Consumed through `useAutoLabelledBy`.\n * Internal; not part of the public API.\n */\nexport const useFieldLabelElementId = () =>\n useContext(FieldLabelElementIdContext);\n\n/** Provider for the Field label's own id, used internally by Field. */\nexport const FieldLabelElementIdProvider = FieldLabelElementIdContext.Provider;\n\n/** The nearest labeled Field's `<label>`, as {@link useFieldLabelFor} reads it. */\nexport interface FieldLabelFor {\n /** What the label's `htmlFor` points at, generated or the caller's. */\n htmlFor?: string;\n /** The id the label renders with, the caller's or a generated one, if any. */\n id?: string;\n}\n\nconst FieldLabelForContext = createContext<FieldLabelFor>({});\n\n/**\n * The nearest labeled Field's `<label>`: what it points `htmlFor` at, the id\n * it generated or the caller's own `labelProps.htmlFor`, and the id the label\n * renders with, if it has one. An unlabeled Field passes both through\n * together, so a control in the inner Field of a horizontal layout can tell\n * the outer label names it, and point at that label by its id, as a range\n * Slider's thumbs (#981) and Autocomplete's suggestion list (#998) do. The\n * `htmlFor` is only ever compared with a control's own id, never adopted, so\n * it hands out no id for a control. It keeps the generated id after the\n * label drops a `for` nothing took (#1004), which no control's id matches\n * then, so the value does not change under the content that reported it.\n * The `id` is set only while that label renders with it. Unlike\n * {@link useFieldLabelId}, it is set in a `grouped` or `hasAddons` Field\n * too, so a label wired by hand names the control its `for` picks in those\n * rows as well. Consumed through `useAutoLabelId`.\n * Internal; not part of the public API.\n */\nexport const useFieldLabelFor = () => useContext(FieldLabelForContext);\n\n/** Provider for the Field label's `htmlFor` target and id, used internally by Field. */\nexport const FieldLabelForProvider = FieldLabelForContext.Provider;\n\n/**\n * Records that one piece of a labeled Field's content took the label's\n * generated id, and returns the function that forgets it.\n */\ntype FieldLabelForReport = () => () => void;\n\nconst FieldLabelForReportContext = createContext<\n FieldLabelForReport | undefined\n>(undefined);\n\n/**\n * Tells the nearest labeled Field that this content took its generated id\n * while `takesFor` is true (#1004). Once the Field's content has mounted, its\n * label keeps the generated `for` only while something has said so, so the\n * label renders none over a group, a `Checkbox`, `Radio` or `Switch`, an\n * inner `Field`, an input with an `id` of its own, markup of your own, or\n * nothing at all. Anything that puts the id from {@link useFieldLabelId} on\n * an element has to say so, or the label drops the `for` that names it, and\n * content that takes no id has nothing to do. Set under the same conditions\n * as {@link useFieldLabelId}, so a label wired by hand and a `grouped` or\n * `hasAddons` Field hear nothing. It reports from a layout effect, which a\n * server never runs and a hydrating client runs only after its first render,\n * so that render writes the `for` the way the server did.\n * Internal; not part of the public API.\n */\nexport const useReportFieldLabelFor = (takesFor: boolean): void => {\n const report = useContext(FieldLabelForReportContext);\n useClientLayoutEffect(\n () => (takesFor ? report?.() : undefined),\n [report, takesFor]\n );\n};\n\n/** Provider for the labeled Field's report function, used internally by Field. */\nexport const FieldLabelForReportProvider = FieldLabelForReportContext.Provider;\n\n/**\n * The id a control with one input of its own renders with: the caller's\n * `id` when one arrived, otherwise the one a labeled Field offers (#495),\n * unless it has no input to put it on (`hasInput: false`, as in an `inline`\n * picker). It also tells that Field when it took the Field's id, through\n * {@link useReportFieldLabelFor}, so the label keeps its `for` (#1004). Used\n * by the single-control bases. Internal; not part of the public API.\n */\nexport const useFieldLabelTarget = (\n id: string | undefined,\n hasInput = true\n): string | undefined => {\n const fieldLabelId = useFieldLabelId();\n const target = id ?? (hasInput ? fieldLabelId : undefined);\n useReportFieldLabelFor(fieldLabelId !== undefined && target === fieldLabelId);\n return target;\n};\n\n/**\n * Shape of the Radios group context. The group provides:\n * - `name`: shared form field name (Stage 1)\n * - `value`: currently-selected radio value (Stage 2 — group-managed selection)\n * - `onChange`: dispatched by child Radios when clicked (Stage 2)\n *\n * Group sets `value`/`onChange` only when actively managing selection\n * (i.e., the user passed `value`, `defaultValue`, or `onChange` to `<Radios>`).\n * When only `name` is provided, the group is in \"name-only\" mode and child\n * Radios manage their own checked state independently.\n */\nexport interface RadiosGroupContextValue {\n name?: string;\n value?: string;\n onChange?: (value: string) => void;\n}\n\n/**\n * Shape of the Checkboxes group context. Like Radios but with array semantics\n * for multi-select.\n */\nexport interface CheckboxesGroupContextValue {\n name?: string;\n value?: string[];\n onChange?: (values: string[]) => void;\n}\n\nconst RadiosContext = createContext<RadiosGroupContextValue | undefined>(\n undefined\n);\nconst CheckboxesContext = createContext<\n CheckboxesGroupContextValue | undefined\n>(undefined);\n\n/**\n * Hook to read the full surrounding `<Radios>` group context (name + selection).\n * Returns `undefined` when not inside a `<Radios>` group.\n */\nexport const useRadiosGroup = () => useContext(RadiosContext);\n\n/**\n * Hook to read the full surrounding `<Checkboxes>` group context.\n * Returns `undefined` when not inside a `<Checkboxes>` group.\n */\nexport const useCheckboxesGroup = () => useContext(CheckboxesContext);\n\n/**\n * Hook to read just the shared `name` from a surrounding `<Radios>` group.\n * Child `<Radio>` components fall back to this when no local `name` prop is set.\n * Returns `undefined` outside of a `<Radios>` group.\n */\nexport const useRadiosName = () => useRadiosGroup()?.name;\n\n/**\n * Hook to read just the shared `name` from a surrounding `<Checkboxes>` group.\n * Returns `undefined` outside of a `<Checkboxes>` group.\n */\nexport const useCheckboxesName = () => useCheckboxesGroup()?.name;\n\n/** Provider for the Radios group context — used internally by Radios. */\nexport const RadiosProvider = RadiosContext.Provider;\n\n/** Provider for the Checkboxes group context — used internally by Checkboxes. */\nexport const CheckboxesProvider = CheckboxesContext.Provider;\n\n// --- Backward-compat aliases (Stage 1 names) -----------------------------\n// Internal callers may still import these. Both still work because they refer\n// to the same providers/hooks under the new shape.\n\n/** @deprecated Use `RadiosProvider` (provides {name, value, onChange}). */\nexport const RadiosNameProvider = RadiosProvider;\n\n/** @deprecated Use `CheckboxesProvider` (provides {name, value, onChange}). */\nexport const CheckboxesNameProvider = CheckboxesProvider;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FormContext.js","sources":["../../../src/form/FormContext.tsx"],"sourcesContent":["import React, { createContext, useContext } from 'react';\nimport { warnOnce } from '../helpers/devWarnings';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport type { ControlBaseProps } from './Control';\n\nconst FieldContext = createContext(false);\nconst ControlContext = createContext(false);\n\n/**\n * Hook to detect if the component is inside a Field wrapper.\n * Form components use this to skip rendering their own Field.\n */\nexport const useInsideField = () => useContext(FieldContext);\n\n/**\n * Hook to detect if the component is inside a Control wrapper.\n * Form components use this to skip rendering their own Control.\n */\nexport const useInsideControl = () => useContext(ControlContext);\n\n/** Provider for Field context — used internally by Field component. */\nexport const FieldProvider = FieldContext.Provider;\n\n/** Provider for Control context — used internally by Control component. */\nexport const ControlProvider = ControlContext.Provider;\n\n/** The wrapper props that change what its own `Field` renders. */\ninterface FieldShapingProps {\n /** Rendered as the `Field`'s label. */\n label?: React.ReactNode;\n /** Rendered as help text after the widget. */\n message?: React.ReactNode;\n /** Lays the `Field` out horizontally. */\n horizontal?: boolean;\n /** Set on the `Field` as its class. */\n fieldClassName?: string;\n}\n\ninterface OwnFieldOptions extends FieldShapingProps {\n /** `useInsideField()` as the wrapper read it. */\n insideField: boolean;\n /** `useInsideControl()` as the wrapper read it. */\n insideControl: boolean;\n}\n\n// Each Field-shaping prop, with what takes its place on a `Field` the caller\n// wraps around the `Control`. `message` needs nothing there, because the\n// wrapper still renders it inside `Field > Control`. The other Field-level\n// props (`labelSize`, `labelProps`, `messageColor`) change nothing unless a\n// `label` or `message` renders, so on their own they keep no `Field`.\n// `bare-control.test.tsx` holds this list to what each wrapper hands its\n// `Field` and to which props change its markup, so a new Field-level prop\n// fails there until it is sorted into one group or the other.\nconst FIELD_SHAPING: ReadonlyArray<\n [keyof FieldShapingProps, string | undefined]\n> = [\n ['label', 'label'],\n ['message', undefined],\n ['horizontal', 'horizontal'],\n ['fieldClassName', 'className (for fieldClassName)'],\n];\n\n/** `a`, `a and b`, `a, b and c`. */\nconst listOf = (items: string[]): string =>\n items.length > 1\n ? `${items.slice(0, -1).join(', ')} and ${items[items.length - 1]}`\n : items[0];\n\n/**\n * Whether a convenience form wrapper renders a `Field` of its own (#905).\n * Never inside an outer `Field`. Inside a `Control` with no `Field` around\n * it, a `Field` of its own would put a `.field` inside the `.control`, where\n * Bulma's control styles break (its icon rules are sibling selectors on the\n * input). So it renders one there only when a prop that shapes the `Field`'s\n * markup is set (`label`, `message`, `horizontal`, `fieldClassName`), keeping\n * the markup it always had, and warns in development that the fix is a\n * `Field` around that `Control`. A prop counts when it is truthy, the same\n * test that decides whether it changes the `Field`'s output.\n * Internal; not part of the public API.\n */\nexport const rendersOwnField = (\n component: string,\n options: OwnFieldOptions\n): boolean => {\n if (options.insideField) return false;\n if (!options.insideControl) return true;\n const held = FIELD_SHAPING.filter(([prop]) => options[prop]);\n if (held.length === 0) return false;\n const names = held.map(([prop]) => prop);\n const moved = held\n .map(([, onField]) => onField)\n .filter((onField): onField is string => onField !== undefined);\n warnOnce(\n `${component}:Field-in-bare-Control:${names.join('+')}`,\n `[bestax-bulma] <${component} ${names.join(' ')}> inside a <Control> ` +\n `with no <Field> around it renders its own <Field> for ` +\n `${names.length > 1 ? 'those props' : 'that prop'}, which puts a ` +\n `.field inside the .control, a nesting Bulma's styles are not ` +\n `written for. Wrap the <Control> in a <Field> instead` +\n (moved.length > 0 ? `, and set ${listOf(moved)} on that <Field>.` : '.')\n );\n return true;\n};\n\n/** The props a convenience form wrapper hands its own `Control`. Internal. */\nexport interface ControlLevelProps {\n /** Shows the `Control`'s loading spinner. */\n isLoading?: boolean;\n /** The `Control`'s left icon. */\n iconLeft?: ControlBaseProps['iconLeft'];\n /** Shortcut for the left icon's name. */\n iconLeftName?: string;\n /** Shortcut for the left icon's size. */\n iconLeftSize?: ControlBaseProps['iconLeftSize'];\n /** The `Control`'s right icon. */\n iconRight?: ControlBaseProps['iconRight'];\n /** Shortcut for the right icon's name. */\n iconRightName?: string;\n /** Shortcut for the right icon's size. */\n iconRightSize?: ControlBaseProps['iconRightSize'];\n /** Reserves the `Control`'s left icon space. */\n hasIconsLeft?: boolean;\n /** Reserves the `Control`'s right icon space. */\n hasIconsRight?: boolean;\n /** Expands the `Control`. */\n isExpanded?: boolean;\n /** Set on the `Control` as its `size`. */\n controlSize?: ControlBaseProps['size'];\n /** Set on the `Control` as its class. */\n controlClassName?: string;\n}\n\ninterface OwnControlOptions extends ControlLevelProps {\n /** `useInsideControl()` as the wrapper read it. */\n insideControl: boolean;\n /** A picker's `inline`, which renders no `Control` inside one or out. */\n inline?: boolean;\n /**\n * The left glyph the wrapper's own `Control` shows when the caller sets no\n * `iconLeftName`; read only then. `bare-control.test.tsx` reads that glyph\n * from what each wrapper hands its own `Control`, so a wrapper that gains\n * one fails there until it passes it here.\n */\n defaultIconLeftName?: string;\n}\n\n// Each Control-level prop, with what takes its place on the `Control` the\n// caller wrapped around the wrapper. `bare-control.test.tsx` holds this to\n// what each wrapper hands its own `Control`, so a new Control-level prop\n// fails there until it is added here and passed to `rendersOwnControl`.\nconst ON_CONTROL: Record<keyof ControlLevelProps, string> = {\n isLoading: 'isLoading',\n iconLeft: 'iconLeft',\n iconLeftName: 'iconLeftName',\n iconLeftSize: 'iconLeftSize',\n iconRight: 'iconRight',\n iconRightName: 'iconRightName',\n iconRightSize: 'iconRightSize',\n hasIconsLeft: 'hasIconsLeft',\n hasIconsRight: 'hasIconsRight',\n isExpanded: 'isExpanded',\n controlSize: 'size (for controlSize)',\n controlClassName: 'className (for controlClassName)',\n};\n\n/**\n * Whether a convenience form wrapper renders a `Control` of its own (#921):\n * only outside one. Inside a `Control` it renders none, so the props it\n * would have handed its own do nothing there, and it warns in development,\n * naming them and saying to set them on that `Control`. An `inline` picker\n * renders none in either place, so it drops them inside a `Control` or not,\n * and its warning says so without pointing at a `Control`. A wrapper passes\n * only the props it hands its own `Control`, as the caller gave them, so a\n * default the wrapper fills in itself never warns. A prop counts when it is\n * truthy, since a falsy one would change nothing on a `Control` either.\n * `iconLeftSize` and `hasIconsLeft` show nothing on a `Control` without a\n * glyph, so when they move and the caller chose no left icon, the advice\n * names the wrapper's default glyph too, and following it draws what the\n * wrapper's own `Control` did.\n * Internal; not part of the public API.\n */\nexport const rendersOwnControl = (\n component: string,\n options: OwnControlOptions\n): boolean => {\n if (!options.inline && !options.insideControl) return true;\n const held = (\n Object.keys(ON_CONTROL) as Array<keyof ControlLevelProps>\n ).filter(prop => options[prop]);\n if (held.length === 0) return false;\n const names = held.join(' ');\n const doNothing = held.length > 1 ? 'those props do' : 'that prop does';\n let message: string;\n if (options.inline) {\n message =\n `[bestax-bulma] <${component} inline ${names}> renders no <Control> ` +\n `in inline mode, inside a <Control> or not, so ${doNothing} ` +\n `nothing. Leave ${held.length > 1 ? 'them' : 'it'} out of an ` +\n `inline picker.`;\n } else {\n const toSet = held.map(prop => ON_CONTROL[prop]);\n const needsGlyph =\n (options.iconLeftSize || options.hasIconsLeft) &&\n !options.iconLeft &&\n options.iconLeftName === undefined &&\n options.defaultIconLeftName;\n if (needsGlyph) {\n toSet.push(\n `iconLeftName=\"${options.defaultIconLeftName}\" (its default icon)`\n );\n }\n message =\n `[bestax-bulma] <${component} ${names}> inside a <Control> renders ` +\n `no <Control> of its own, so ${doNothing} nothing there. Set ` +\n `${listOf(toSet)} on that <Control> instead.`;\n }\n // Keyed by the message itself: the props named do not settle the advice\n // (an empty `iconLeftName` and an unset one name the same props), so two\n // calls that would advise differently must not share a key.\n warnOnce(message, message);\n return false;\n};\n\nconst FieldLabelIdContext = createContext<string | undefined>(undefined);\n\n/**\n * The id a labeled Field wants its single composed control to adopt (#495).\n * `undefined` outside a Field, in unlabeled/grouped/addons Fields, or when the\n * user took over the association with an explicit `labelProps.htmlFor`.\n * Consumed through `useFieldLabelTarget` by the single-control bases\n * (InputBase, SelectBase, TextAreaBase, and the date and time picker bases\n * unless inline, #968) and, through `useAutoLabelId`, by the convenience\n * inputs that render an input of their own (#939). Read it only through\n * those, which report what they take: a control that read it directly would\n * report nothing and lose its label (#1004), and\n * `__tests__/field-label-readers.test.ts` fails on one. Internal; not part of\n * the public API.\n */\nexport const useFieldLabelId = () => useContext(FieldLabelIdContext);\n\n/** Provider for the Field label-target id — used internally by Field. */\nexport const FieldLabelIdProvider = FieldLabelIdContext.Provider;\n\nconst FieldLabelElementIdContext = createContext<string | undefined>(undefined);\n\n/**\n * The id of a labeled Field's own `<label>`, for a group control (Radios,\n * Checkboxes, Rate, DateRangeInput and DateRangeInputBase) to point\n * `aria-labelledby` at, since a group cannot take the label's `htmlFor`\n * (#939, #1005). Set under the same conditions as\n * {@link useFieldLabelId}. Consumed through `useAutoLabelledBy`.\n * Internal; not part of the public API.\n */\nexport const useFieldLabelElementId = () =>\n useContext(FieldLabelElementIdContext);\n\n/** Provider for the Field label's own id, used internally by Field. */\nexport const FieldLabelElementIdProvider = FieldLabelElementIdContext.Provider;\n\n/** The nearest labeled Field's `<label>`, as {@link useFieldLabelFor} reads it. */\nexport interface FieldLabelFor {\n /** What the label's `htmlFor` points at, generated or the caller's. */\n htmlFor?: string;\n /** The id the label renders with, the caller's or a generated one, if any. */\n id?: string;\n}\n\nconst FieldLabelForContext = createContext<FieldLabelFor>({});\n\n/**\n * The nearest labeled Field's `<label>`: what it points `htmlFor` at, the id\n * it generated or the caller's own `labelProps.htmlFor`, and the id the label\n * renders with, if it has one. An unlabeled Field passes both through\n * together, so a control in the inner Field of a horizontal layout can tell\n * the outer label names it, and point at that label by its id, as a range\n * Slider's thumbs (#981) and Autocomplete's and Taginput's suggestion lists\n * (#998, #1082) do. The\n * `htmlFor` is only ever compared with a control's own id, never adopted, so\n * it hands out no id for a control. It keeps the generated id after the\n * label drops a `for` nothing took (#1004), which no control's id matches\n * then, so the value does not change under the content that reported it.\n * The `id` is set only while that label renders with it. Unlike\n * {@link useFieldLabelId}, it is set in a `grouped` or `hasAddons` Field\n * too, so a label wired by hand names the control its `for` picks in those\n * rows as well. Consumed through `useAutoLabelId`.\n * Internal; not part of the public API.\n */\nexport const useFieldLabelFor = () => useContext(FieldLabelForContext);\n\n/** Provider for the Field label's `htmlFor` target and id, used internally by Field. */\nexport const FieldLabelForProvider = FieldLabelForContext.Provider;\n\n/**\n * Records that one piece of a labeled Field's content took the label's\n * generated id, and returns the function that forgets it.\n */\ntype FieldLabelForReport = () => () => void;\n\nconst FieldLabelForReportContext = createContext<\n FieldLabelForReport | undefined\n>(undefined);\n\n/**\n * Tells the nearest labeled Field that this content took its generated id\n * while `takesFor` is true (#1004). Once the Field's content has mounted, its\n * label keeps the generated `for` only while something has said so, so the\n * label renders none over a group, a `Checkbox`, `Radio` or `Switch`, an\n * inner `Field`, an input with an `id` of its own, markup of your own, or\n * nothing at all. Anything that puts the id from {@link useFieldLabelId} on\n * an element has to say so, or the label drops the `for` that names it, and\n * content that takes no id has nothing to do. Set under the same conditions\n * as {@link useFieldLabelId}, so a label wired by hand and a `grouped` or\n * `hasAddons` Field hear nothing. It reports from a layout effect, which a\n * server never runs and a hydrating client runs only after its first render,\n * so that render writes the `for` the way the server did.\n * Internal; not part of the public API.\n */\nexport const useReportFieldLabelFor = (takesFor: boolean): void => {\n const report = useContext(FieldLabelForReportContext);\n useClientLayoutEffect(\n () => (takesFor ? report?.() : undefined),\n [report, takesFor]\n );\n};\n\n/** Provider for the labeled Field's report function, used internally by Field. */\nexport const FieldLabelForReportProvider = FieldLabelForReportContext.Provider;\n\n/**\n * The id a control with one input of its own renders with: the caller's\n * `id` when one arrived, otherwise the one a labeled Field offers (#495),\n * unless it has no input to put it on (`hasInput: false`, as in an `inline`\n * picker). It also tells that Field when it took the Field's id, through\n * {@link useReportFieldLabelFor}, so the label keeps its `for` (#1004). Used\n * by the single-control bases. Internal; not part of the public API.\n */\nexport const useFieldLabelTarget = (\n id: string | undefined,\n hasInput = true\n): string | undefined => {\n const fieldLabelId = useFieldLabelId();\n const target = id ?? (hasInput ? fieldLabelId : undefined);\n useReportFieldLabelFor(fieldLabelId !== undefined && target === fieldLabelId);\n return target;\n};\n\n/**\n * Shape of the Radios group context. The group provides:\n * - `name`: shared form field name (Stage 1)\n * - `value`: currently-selected radio value (Stage 2 — group-managed selection)\n * - `onChange`: dispatched by child Radios when clicked (Stage 2)\n *\n * Group sets `value`/`onChange` only when actively managing selection\n * (i.e., the user passed `value`, `defaultValue`, or `onChange` to `<Radios>`).\n * When only `name` is provided, the group is in \"name-only\" mode and child\n * Radios manage their own checked state independently.\n */\nexport interface RadiosGroupContextValue {\n name?: string;\n value?: string;\n onChange?: (value: string) => void;\n}\n\n/**\n * Shape of the Checkboxes group context. Like Radios but with array semantics\n * for multi-select.\n */\nexport interface CheckboxesGroupContextValue {\n name?: string;\n value?: string[];\n onChange?: (values: string[]) => void;\n}\n\nconst RadiosContext = createContext<RadiosGroupContextValue | undefined>(\n undefined\n);\nconst CheckboxesContext = createContext<\n CheckboxesGroupContextValue | undefined\n>(undefined);\n\n/**\n * Hook to read the full surrounding `<Radios>` group context (name + selection).\n * Returns `undefined` when not inside a `<Radios>` group.\n */\nexport const useRadiosGroup = () => useContext(RadiosContext);\n\n/**\n * Hook to read the full surrounding `<Checkboxes>` group context.\n * Returns `undefined` when not inside a `<Checkboxes>` group.\n */\nexport const useCheckboxesGroup = () => useContext(CheckboxesContext);\n\n/**\n * Hook to read just the shared `name` from a surrounding `<Radios>` group.\n * Child `<Radio>` components fall back to this when no local `name` prop is set.\n * Returns `undefined` outside of a `<Radios>` group.\n */\nexport const useRadiosName = () => useRadiosGroup()?.name;\n\n/**\n * Hook to read just the shared `name` from a surrounding `<Checkboxes>` group.\n * Returns `undefined` outside of a `<Checkboxes>` group.\n */\nexport const useCheckboxesName = () => useCheckboxesGroup()?.name;\n\n/** Provider for the Radios group context — used internally by Radios. */\nexport const RadiosProvider = RadiosContext.Provider;\n\n/** Provider for the Checkboxes group context — used internally by Checkboxes. */\nexport const CheckboxesProvider = CheckboxesContext.Provider;\n\n// --- Backward-compat aliases (Stage 1 names) -----------------------------\n// Internal callers may still import these. Both still work because they refer\n// to the same providers/hooks under the new shape.\n\n/** @deprecated Use `RadiosProvider` (provides {name, value, onChange}). */\nexport const RadiosNameProvider = RadiosProvider;\n\n/** @deprecated Use `CheckboxesProvider` (provides {name, value, onChange}). */\nexport const CheckboxesNameProvider = CheckboxesProvider;\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import { forwardRef, useRef, useState, useEffect, useCallback } from 'react';
|
|
3
|
+
import { forwardRef, useRef, useState, useId, useEffect, useCallback } from 'react';
|
|
4
4
|
import { classNames, usePrefixedClassNames, prefixedClassNames } from '../helpers/classNames.js';
|
|
5
5
|
import { useConfig, useIconLibrary } from '../helpers/Config.js';
|
|
6
6
|
import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
|
|
@@ -35,7 +35,7 @@ import { Icon } from '../elements/Icon.js';
|
|
|
35
35
|
*/
|
|
36
36
|
const Taginput = forwardRef(({
|
|
37
37
|
// Field props
|
|
38
|
-
label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName, value: controlledValue, defaultValue = [], data
|
|
38
|
+
label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName, value: controlledValue, defaultValue = [], data: dataProp, placeholder, field = 'label', allowNew = true, allowDuplicates = false, openOnFocus = false, removeOnKeys = true, confirmKeys = ['Enter', ','], closable = true, attached = false, maxTags, maxlength, disabled = false, readonly = false, rounded = false, ellipsis = false, hasCounter = true, onPasteSeparators = [','], beforeAdding, createTag, keepFirst = false, keepOpen = true, loading = false, ariaCloseLabel, icon, iconLibrary: iconLibraryProp, iconVariant, iconFeatures, color, tagColor, size, onChange, onAdd, onRemove, onTyping, tagTemplate, name, form, id, className, ...props }, ref) => {
|
|
39
39
|
const insideField = useInsideField();
|
|
40
40
|
const insideControl = useInsideControl();
|
|
41
41
|
const ownField = rendersOwnField('Taginput', {
|
|
@@ -58,17 +58,26 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
58
58
|
const [inputValue, setInputValue] = useState('');
|
|
59
59
|
const [isActive, setIsActive] = useState(false);
|
|
60
60
|
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
|
61
|
+
const listboxId = `${useId()}-listbox`;
|
|
62
|
+
// With `data` the input offers suggestions, so it's a combobox, even
|
|
63
|
+
// while none match. Without it there's never a list, so it stays a plain
|
|
64
|
+
// text field.
|
|
65
|
+
const hasSuggestions = dataProp !== undefined;
|
|
66
|
+
const data = dataProp ?? [];
|
|
61
67
|
// Use controlled or internal tags
|
|
62
68
|
const tags = controlledValue !== undefined ? controlledValue : internalTags;
|
|
63
69
|
const isMaxReached = maxTags !== undefined && tags.length >= maxTags;
|
|
64
70
|
// At the tag limit the text input is not rendered, so there is nothing to
|
|
65
|
-
// wire a label to, its own or a surrounding Field's.
|
|
66
|
-
|
|
71
|
+
// wire a label to, its own or a surrounding Field's. The suggestion list
|
|
72
|
+
// points `aria-labelledby` at the label that names the input, so with
|
|
73
|
+
// suggestions it needs that label's id.
|
|
74
|
+
const { controlId, fieldLabelProps, labelled, labelId: listLabelId, } = useAutoLabelId({
|
|
67
75
|
label,
|
|
68
76
|
id,
|
|
69
77
|
labelProps,
|
|
70
78
|
rendersLabel: ownField && !isMaxReached,
|
|
71
79
|
hasInput: !isMaxReached,
|
|
80
|
+
needsLabelId: hasSuggestions,
|
|
72
81
|
});
|
|
73
82
|
// Get display value from tag
|
|
74
83
|
const getDisplayValue = (tag) => {
|
|
@@ -88,6 +97,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
88
97
|
const hasInput = inputValue || (openOnFocus && isActive);
|
|
89
98
|
return matchesInput && notAlreadyAdded && hasInput;
|
|
90
99
|
});
|
|
100
|
+
const listOpen = isActive && filteredData.length > 0;
|
|
91
101
|
// keepFirst: auto-highlight first item when dropdown opens
|
|
92
102
|
useEffect(() => {
|
|
93
103
|
if (keepFirst && isActive && filteredData.length > 0) {
|
|
@@ -328,15 +338,35 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
328
338
|
[`is-${messageColor}`]: !!messageColor,
|
|
329
339
|
});
|
|
330
340
|
const messageEl = message ? jsx("p", { className: helpClass, children: message }) : null;
|
|
341
|
+
// The combobox controls its listbox and points at the highlighted option,
|
|
342
|
+
// the way Autocomplete's does. The listbox takes its name from the label
|
|
343
|
+
// that names the combobox, the one this renders or a surrounding Field's,
|
|
344
|
+
// and keeps a fallback name when no label names it or the one that does
|
|
345
|
+
// has no id to point at. While no suggestion matches there's no listbox,
|
|
346
|
+
// so the combobox is collapsed and points at nothing. It skips a
|
|
347
|
+
// highlighted suggestion that's blank once trimmed, since that one can't
|
|
348
|
+
// become a tag, and the option it points at is the one marked selected.
|
|
349
|
+
const optionId = (index) => `${listboxId}-${index}`;
|
|
350
|
+
const activeOptionId = listOpen && filteredData[highlightedIndex]?.trim()
|
|
351
|
+
? optionId(highlightedIndex)
|
|
352
|
+
: undefined;
|
|
353
|
+
const comboboxProps = {
|
|
354
|
+
role: 'combobox',
|
|
355
|
+
'aria-expanded': listOpen,
|
|
356
|
+
'aria-controls': listOpen ? listboxId : undefined,
|
|
357
|
+
'aria-activedescendant': activeOptionId,
|
|
358
|
+
'aria-haspopup': 'listbox',
|
|
359
|
+
'aria-autocomplete': 'list',
|
|
360
|
+
};
|
|
331
361
|
const taginputElement = (jsxs("div", { ref: containerRef, className: combinedClasses, onClick: handleContainerClick, ...rest, children: [jsxs("div", { className: containerClasses, children: [icon && (jsx(Icon, { name: icon, library: resolvedLibrary, variant: iconVariant, features: iconFeatures, containerClassName: pcn('icon', 'is-left') })), jsxs("div", { className: tagsClasses, children: [tags.map((tag, index) => {
|
|
332
362
|
const displayVal = getDisplayValue(tag);
|
|
333
363
|
return (jsxs("span", { className: tagClasses, children: [tagTemplate ? (tagTemplate(tag)) : ellipsis ? (jsx("span", { title: displayVal, children: displayVal })) : (displayVal), closable && !disabled && !readonly && (jsx("button", { type: "button", className: pcn('delete', 'is-small'), onClick: e => {
|
|
334
364
|
e.stopPropagation();
|
|
335
365
|
removeTag(index);
|
|
336
366
|
}, "aria-label": ariaCloseLabel || `Remove ${displayVal}` }))] }, index));
|
|
337
|
-
}), !isMaxReached && (jsx("input", { ref: combinedRef, type: "text", className: inputClasses, id: controlId, value: inputValue, placeholder: tags.length === 0 ? placeholder : undefined, disabled: disabled, readOnly: readonly, maxLength: maxlength, onChange: handleInputChange, onFocus: handleFocus, onKeyDown: handleKeyDown, onPaste: handlePaste, "aria-label": labelled ? undefined : 'Add tag' }))] }), loading && (jsx("span", { className: iconRightClass, children: jsx("span", { className: loaderClass }) }))] }),
|
|
367
|
+
}), !isMaxReached && (jsx("input", { ref: combinedRef, type: "text", className: inputClasses, id: controlId, value: inputValue, placeholder: tags.length === 0 ? placeholder : undefined, disabled: disabled, readOnly: readonly, maxLength: maxlength, onChange: handleInputChange, onFocus: handleFocus, onKeyDown: handleKeyDown, onPaste: handlePaste, ...(hasSuggestions && comboboxProps), "aria-label": labelled ? undefined : 'Add tag' }))] }), loading && (jsx("span", { className: iconRightClass, children: jsx("span", { className: loaderClass }) }))] }), listOpen && (jsx("div", { className: dropdownMenuClasses, children: jsx("div", { ref: dropdownRef, id: listboxId, className: dropdownContentClasses, role: "listbox", "aria-labelledby": listLabelId, "aria-label": listLabelId ? undefined : 'Suggestions', children: filteredData.map((item, index) => (jsx("a", { id: optionId(index), className: pcn('dropdown-item', {
|
|
338
368
|
'is-active': index === highlightedIndex,
|
|
339
|
-
}), onClick: () => addTag(item), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index ===
|
|
369
|
+
}), onClick: () => addTag(item), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": optionId(index) === activeOptionId, children: item }, index))) }) })), showCounter && jsx("small", { className: counterClasses, children: counterText }), name &&
|
|
340
370
|
tags.map((tag, i) => (jsx("input", { type: "hidden", name: name, value: getDisplayValue(tag), form: form }, `tag-input-${i}`)))] }));
|
|
341
371
|
if (ownField) {
|
|
342
372
|
return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [taginputElement, messageEl] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Taginput.js","sources":["../../../src/form/Taginput.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useState,\n useRef,\n useEffect,\n useCallback,\n} from 'react';\nimport {\n classNames,\n usePrefixedClassNames,\n prefixedClassNames,\n} from '../helpers/classNames';\nimport { useConfig, useIconLibrary } from '../helpers/Config';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { isEventInside } from '../helpers/shadowDom';\nimport {\n useInsideField,\n useInsideControl,\n rendersOwnField,\n} from './FormContext';\nimport { Field } from './Field';\nimport { FormFieldProps } from './fieldProps';\nimport { useAutoLabelId } from './useAutoLabelId';\nimport { Icon } from '../elements/Icon';\n\n/**\n * Represents a tag item object with a value and optional label.\n */\nexport interface TaginputItem {\n /** The tag value. */\n value: string;\n /** Display label (optional). */\n label?: string;\n [key: string]: unknown;\n}\n\n/** A tag can be either a TaginputItem object or a plain string. */\nexport type TaginputTag = TaginputItem | string;\n\ntype IconLibrary = 'fa' | 'mdi' | 'ion' | 'material-icons' | 'material-symbols';\n\n/**\n * Props for the Taginput component.\n * Inside an outer `Field`, or a `Control` with no `Field` around it, it\n * renders no `Field` of its own. The exception is `label`, `message`,\n * `horizontal` or `fieldClassName` in that bare `Control`: it keeps a `Field`\n * for them, nested in the `.control`, and warns in development. Wrap the\n * `Control` in a `Field` instead, and set the `label`, `horizontal` and class\n * name on that `Field`.\n * @extraProp {string} [className] - Additional CSS classes.\n * @extraProp {React.Ref<HTMLInputElement>} [ref] - Ref forwarded to the input element.\n */\nexport interface TaginputProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'>,\n Omit<BulmaClassesProps, 'color'>,\n FormFieldProps {\n /** Field label. Automatically associated with the text input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired when the tag limit is reached (the input is not rendered). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here; it then replaces the `aria-label=\"Add tag\"` fallback too. */\n label?: React.ReactNode;\n /** Props for the label element. An explicit `htmlFor` here overrides the automatic association (no id is generated then). */\n labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {\n [key: string]: unknown;\n };\n /** Applied to the inner text input (the labellable control), not the wrapper div. */\n id?: string;\n /** The current tags (controlled). */\n value?: TaginputTag[];\n /** Default tags (uncontrolled). */\n defaultValue?: TaginputTag[];\n /** Autocomplete suggestions. */\n data?: string[];\n /** Placeholder text when no tags. */\n placeholder?: string;\n /** Object property to use as display field. */\n field?: string;\n /** Allow creating new tags not in suggestions. */\n allowNew?: boolean;\n /** Allow duplicate tags. */\n allowDuplicates?: boolean;\n /** Open autocomplete dropdown on focus. */\n openOnFocus?: boolean;\n /** Remove tag on backspace. Default: true. */\n removeOnKeys?: boolean;\n /** Keys to confirm tag creation. Default: ['Enter', ',']. */\n confirmKeys?: string[];\n /** Show close button on tags. Default: true. */\n closable?: boolean;\n /** Attach tags visually. */\n attached?: boolean;\n /** Maximum number of tags allowed. */\n maxTags?: number;\n /** Maximum length of input. */\n maxlength?: number;\n /** Whether the input is disabled. */\n disabled?: boolean;\n /** Whether the input is read-only. */\n readonly?: boolean;\n /** Applies rounded corners to the tags. */\n rounded?: boolean;\n /** Truncates long tag text with ellipsis. */\n ellipsis?: boolean;\n /** Shows a counter of the number of tags. */\n hasCounter?: boolean;\n /** Characters that split pasted text into tags. */\n onPasteSeparators?: string[];\n /** Validation function called before adding a tag. */\n beforeAdding?: (tag: string) => boolean;\n /** Custom function for creating tag objects from input. */\n createTag?: (input: string) => TaginputTag;\n /** Keeps the first autocomplete suggestion highlighted. */\n keepFirst?: boolean;\n /** Keeps the autocomplete dropdown open after selection. */\n keepOpen?: boolean;\n /**\n * Shows a loading spinner in the input.\n * Under `prefers-reduced-motion: reduce` the spinner stops and stays\n * drawn (with bestax's CSS loaded).\n */\n loading?: boolean;\n /** ARIA label for tag close buttons. */\n ariaCloseLabel?: string;\n /** Icon name for the input field. */\n icon?: string;\n /** Icon library to use. */\n iconLibrary?: IconLibrary;\n /** Icon style variant (e.g., 'solid', 'outlined'). */\n iconVariant?: string;\n /** Additional icon modifiers. */\n iconFeatures?: string | string[];\n /** Input color variant. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Tag color variant. */\n tagColor?:\n | 'primary'\n | 'link'\n | 'info'\n | 'success'\n | 'warning'\n | 'danger'\n | 'dark'\n | 'light';\n /** Size variant. */\n size?: 'small' | 'medium' | 'large';\n /** Form field name. When set, one hidden input per tag is rendered. */\n name?: string;\n /** Optional id of the form the hidden inputs belong to. */\n form?: string;\n /** Callback when tags change. */\n onChange?: (tags: TaginputTag[]) => void;\n /** Callback when tag is added. */\n onAdd?: (tag: TaginputTag) => void;\n /** Callback when tag is removed. */\n onRemove?: (tag: TaginputTag, index: number) => void;\n /** Callback when typing in input. */\n onTyping?: (value: string) => void;\n /** Custom render for tags. */\n tagTemplate?: (tag: TaginputTag) => React.ReactNode;\n}\n\n/**\n * The `Taginput` component provides a tag/chip input field for managing multiple tags.\n *\n * @function\n * @param {TaginputProps} props - Props for the Taginput component.\n * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the input element.\n * @returns {JSX.Element} The rendered taginput component.\n *\n * @example\n * // Basic usage\n * <Taginput\n * placeholder=\"Add a tag...\"\n * onChange={(tags) => console.log(tags)}\n * />\n *\n * @example\n * // With autocomplete\n * <Taginput\n * data={['React', 'Vue', 'Angular', 'Svelte']}\n * allowNew={false}\n * placeholder=\"Select frameworks...\"\n * />\n */\nexport const Taginput = forwardRef<HTMLInputElement, TaginputProps>(\n (\n {\n // Field props\n label,\n labelSize,\n labelProps,\n horizontal,\n message,\n messageColor,\n fieldClassName,\n value: controlledValue,\n defaultValue = [],\n data = [],\n placeholder,\n field = 'label',\n allowNew = true,\n allowDuplicates = false,\n openOnFocus = false,\n removeOnKeys = true,\n confirmKeys = ['Enter', ','],\n closable = true,\n attached = false,\n maxTags,\n maxlength,\n disabled = false,\n readonly = false,\n rounded = false,\n ellipsis = false,\n hasCounter = true,\n onPasteSeparators = [','],\n beforeAdding,\n createTag,\n keepFirst = false,\n keepOpen = true,\n loading = false,\n ariaCloseLabel,\n icon,\n iconLibrary: iconLibraryProp,\n iconVariant,\n iconFeatures,\n color,\n tagColor,\n size,\n onChange,\n onAdd,\n onRemove,\n onTyping,\n tagTemplate,\n name,\n form,\n id,\n className,\n ...props\n },\n ref\n ) => {\n const insideField = useInsideField();\n const insideControl = useInsideControl();\n const ownField = rendersOwnField('Taginput', {\n insideField,\n insideControl,\n label,\n message,\n horizontal,\n fieldClassName,\n });\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const { classPrefix } = useConfig();\n const defaultIconLibrary = useIconLibrary();\n const resolvedLibrary = iconLibraryProp || defaultIconLibrary || 'fa';\n const pcn = (\n ...args: (\n | string\n | number\n | undefined\n | null\n | false\n | Record<string, unknown>\n | unknown[]\n )[]\n ) => prefixedClassNames(classPrefix, ...args);\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n const [internalTags, setInternalTags] =\n useState<TaginputTag[]>(defaultValue);\n const [inputValue, setInputValue] = useState('');\n const [isActive, setIsActive] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n\n // Use controlled or internal tags\n const tags = controlledValue !== undefined ? controlledValue : internalTags;\n\n const isMaxReached = maxTags !== undefined && tags.length >= maxTags;\n // At the tag limit the text input is not rendered, so there is nothing to\n // wire a label to, its own or a surrounding Field's.\n const { controlId, fieldLabelProps, labelled } = useAutoLabelId({\n label,\n id,\n labelProps,\n rendersLabel: ownField && !isMaxReached,\n hasInput: !isMaxReached,\n });\n\n // Get display value from tag\n const getDisplayValue = (tag: TaginputTag): string => {\n if (typeof tag === 'string') return tag;\n const fieldValue = tag[field];\n if (typeof fieldValue === 'string') return fieldValue;\n return tag.value || '';\n };\n\n // Filter autocomplete data\n const filteredData = data.filter(item => {\n const displayValue = item.toLowerCase();\n const matchesInput = displayValue.includes(inputValue.toLowerCase());\n const notAlreadyAdded =\n allowDuplicates ||\n !tags.some(tag => getDisplayValue(tag).toLowerCase() === displayValue);\n const hasInput = inputValue || (openOnFocus && isActive);\n return matchesInput && notAlreadyAdded && hasInput;\n });\n\n // keepFirst: auto-highlight first item when dropdown opens\n useEffect(() => {\n if (keepFirst && isActive && filteredData.length > 0) {\n setHighlightedIndex(0);\n }\n }, [keepFirst, isActive, filteredData.length]);\n\n // Update tags\n const updateTags = useCallback(\n (newTags: TaginputTag[]) => {\n if (controlledValue === undefined) {\n setInternalTags(newTags);\n }\n onChange?.(newTags);\n },\n [controlledValue, onChange]\n );\n\n // Add tag\n const addTag = useCallback(\n (value: string | TaginputTag) => {\n if (disabled || readonly) return;\n\n const tagValue = typeof value === 'string' ? value.trim() : value;\n const displayValue =\n typeof tagValue === 'string' ? tagValue : getDisplayValue(tagValue);\n\n if (!displayValue) return;\n\n // Check max tags\n if (maxTags && tags.length >= maxTags) return;\n\n // Check duplicates\n if (!allowDuplicates) {\n const exists = tags.some(\n tag =>\n getDisplayValue(tag).toLowerCase() === displayValue.toLowerCase()\n );\n if (exists) return;\n }\n\n // Check if allowed (must be in data if allowNew is false). Compare\n // case-insensitively, consistent with the dropdown filter and the\n // duplicate check above.\n if (\n !allowNew &&\n !data.some(d => d.toLowerCase() === displayValue.toLowerCase())\n )\n return;\n\n // beforeAdding validation\n if (beforeAdding && !beforeAdding(displayValue)) return;\n\n // createTag transformation\n const finalTag = createTag ? createTag(displayValue) : tagValue;\n\n const newTags = [...tags, finalTag];\n updateTags(newTags);\n onAdd?.(finalTag);\n setInputValue('');\n if (!keepOpen) {\n setIsActive(false);\n }\n setHighlightedIndex(-1);\n },\n [\n disabled,\n readonly,\n tags,\n maxTags,\n allowDuplicates,\n allowNew,\n data,\n field,\n updateTags,\n onAdd,\n beforeAdding,\n createTag,\n keepOpen,\n ]\n );\n\n // Remove tag\n const removeTag = useCallback(\n (index: number) => {\n /* istanbul ignore next: both triggers (delete button click, Backspace handler) are already gated on disabled/readonly */\n if (disabled || readonly) return;\n\n const removedTag = tags[index];\n const newTags = tags.filter((_, i) => i !== index);\n updateTags(newTags);\n onRemove?.(removedTag, index);\n },\n [disabled, readonly, tags, updateTags, onRemove]\n );\n\n // Handle input change\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n\n // Check if a confirm key was typed\n const lastChar = newValue.slice(-1);\n if (confirmKeys.includes(lastChar) && lastChar !== 'Enter') {\n const valueWithoutKey = newValue.slice(0, -1).trim();\n if (valueWithoutKey) {\n addTag(valueWithoutKey);\n }\n return;\n }\n\n setInputValue(newValue);\n onTyping?.(newValue);\n\n if (newValue && data.length > 0) {\n setIsActive(true);\n }\n },\n [confirmKeys, addTag, onTyping, data.length]\n );\n\n // Handle paste\n const handlePaste = useCallback(\n (e: React.ClipboardEvent<HTMLInputElement>) => {\n if (onPasteSeparators.length === 0) return;\n\n const pastedText = e.clipboardData.getData('text');\n // Check if any separator exists in the pasted text\n const hasSeparator = onPasteSeparators.some(sep =>\n pastedText.includes(sep)\n );\n\n if (!hasSeparator) return;\n\n e.preventDefault();\n\n // Build a regex from all separators\n const escapedSeparators = onPasteSeparators.map(s =>\n s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n );\n const regex = new RegExp(`[${escapedSeparators.join('')}]`);\n\n const parts = pastedText\n .split(regex)\n .map(s => s.trim())\n .filter(Boolean);\n\n for (const part of parts) {\n addTag(part);\n }\n },\n [onPasteSeparators, addTag]\n );\n\n // Handle focus\n const handleFocus = useCallback(() => {\n if (openOnFocus && data.length > 0 && !disabled) {\n setIsActive(true);\n }\n }, [openOnFocus, data.length, disabled]);\n\n // Handle click outside\n useEffect(() => {\n if (!isActive) return undefined;\n\n const handleClickOutside = (e: MouseEvent) => {\n if (containerRef.current && !isEventInside(e, containerRef.current)) {\n setIsActive(false);\n setHighlightedIndex(-1);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () =>\n document.removeEventListener('mousedown', handleClickOutside);\n }, [isActive]);\n\n // Handle keyboard\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (disabled || readonly) return;\n\n // Handle confirm keys\n if (confirmKeys.includes(e.key)) {\n e.preventDefault();\n if (highlightedIndex >= 0 && filteredData[highlightedIndex]) {\n addTag(filteredData[highlightedIndex]);\n } else if (inputValue.trim()) {\n addTag(inputValue);\n }\n return;\n }\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!isActive && data.length > 0) {\n setIsActive(true);\n } else {\n setHighlightedIndex(prev =>\n prev < filteredData.length - 1 ? prev + 1 : prev\n );\n }\n break;\n case 'ArrowUp':\n e.preventDefault();\n setHighlightedIndex(prev => (prev > 0 ? prev - 1 : prev));\n break;\n case 'Backspace':\n if (removeOnKeys && !inputValue && tags.length > 0) {\n e.preventDefault();\n removeTag(tags.length - 1);\n }\n break;\n case 'Escape':\n setIsActive(false);\n setHighlightedIndex(-1);\n break;\n }\n },\n [\n disabled,\n readonly,\n confirmKeys,\n highlightedIndex,\n filteredData,\n addTag,\n inputValue,\n isActive,\n data.length,\n removeOnKeys,\n tags.length,\n removeTag,\n ]\n );\n\n // Combined ref\n const combinedRef = useCallback(\n (node: HTMLInputElement | null) => {\n (inputRef as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n }\n },\n [ref]\n );\n\n // Focus input when container is clicked\n const handleContainerClick = useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n // Generate classes\n const taginputClasses = pcn('taginput', {\n 'is-active': isActive,\n [`is-${size}`]: !!size,\n [`is-${color}`]: !!color,\n 'is-disabled': disabled,\n 'is-rounded': rounded,\n 'is-ellipsis': ellipsis,\n });\n\n const containerClasses = pcn('taginput-container', {\n 'is-attached': attached,\n 'has-icons-left': !!icon,\n });\n\n const inputClasses = pcn('input', {\n [`is-${size}`]: !!size,\n });\n\n const tagClasses = pcn('tag', {\n [`is-${tagColor}`]: !!tagColor,\n [`is-${size}`]: !!size,\n });\n\n const combinedClasses = classNames(\n taginputClasses,\n bulmaHelperClasses,\n className\n );\n\n // Counter text\n const showCounter =\n hasCounter && (maxTags !== undefined || maxlength !== undefined);\n const counterText =\n maxTags !== undefined\n ? `${tags.length} / ${maxTags}`\n : maxlength !== undefined\n ? `${inputValue.length} / ${maxlength}`\n : '';\n\n const counterClasses = pcn('help', 'counter');\n const tagsClasses = pcn('tags');\n const dropdownMenuClasses = pcn('dropdown-menu', 'is-active');\n const dropdownContentClasses = pcn('dropdown-content');\n const iconRightClass = pcn('icon', 'is-right');\n const loaderClass = pcn('loader', 'is-loading');\n\n const helpClass = usePrefixedClassNames('help', {\n [`is-${messageColor}`]: !!messageColor,\n });\n const messageEl = message ? <p className={helpClass}>{message}</p> : null;\n\n const taginputElement = (\n <div\n ref={containerRef}\n className={combinedClasses}\n onClick={handleContainerClick}\n {...rest}\n >\n <div className={containerClasses}>\n {icon && (\n <Icon\n name={icon}\n library={resolvedLibrary}\n variant={iconVariant}\n features={iconFeatures}\n containerClassName={pcn('icon', 'is-left')}\n />\n )}\n <div className={tagsClasses}>\n {tags.map((tag, index) => {\n const displayVal = getDisplayValue(tag);\n return (\n <span key={index} className={tagClasses}>\n {tagTemplate ? (\n tagTemplate(tag)\n ) : ellipsis ? (\n <span title={displayVal}>{displayVal}</span>\n ) : (\n displayVal\n )}\n {closable && !disabled && !readonly && (\n <button\n type=\"button\"\n className={pcn('delete', 'is-small')}\n onClick={e => {\n e.stopPropagation();\n removeTag(index);\n }}\n aria-label={ariaCloseLabel || `Remove ${displayVal}`}\n />\n )}\n </span>\n );\n })}\n {!isMaxReached && (\n <input\n ref={combinedRef}\n type=\"text\"\n className={inputClasses}\n id={controlId}\n value={inputValue}\n placeholder={tags.length === 0 ? placeholder : undefined}\n disabled={disabled}\n readOnly={readonly}\n maxLength={maxlength}\n onChange={handleInputChange}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n // Fallback name, dropped only when a rendered label actually\n // targets this input, its own or a surrounding Field's\n // (aria-label would win otherwise). A label pointing elsewhere\n // keeps the fallback so the input is never nameless.\n aria-label={labelled ? undefined : 'Add tag'}\n />\n )}\n </div>\n {loading && (\n <span className={iconRightClass}>\n <span className={loaderClass} />\n </span>\n )}\n </div>\n\n {isActive && filteredData.length > 0 && (\n <div className={dropdownMenuClasses}>\n <div\n ref={dropdownRef}\n className={dropdownContentClasses}\n role=\"listbox\"\n >\n {filteredData.map((item, index) => (\n <a\n key={index}\n className={pcn('dropdown-item', {\n 'is-active': index === highlightedIndex,\n })}\n onClick={() => addTag(item)}\n onMouseEnter={() => setHighlightedIndex(index)}\n role=\"option\"\n aria-selected={index === highlightedIndex}\n >\n {item}\n </a>\n ))}\n </div>\n </div>\n )}\n\n {showCounter && <small className={counterClasses}>{counterText}</small>}\n\n {name &&\n tags.map((tag, i) => (\n <input\n key={`tag-input-${i}`}\n type=\"hidden\"\n name={name}\n value={getDisplayValue(tag)}\n form={form}\n />\n ))}\n </div>\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 {taginputElement}\n {messageEl}\n </Field>\n );\n }\n\n return (\n <>\n {taginputElement}\n {messageEl}\n </>\n );\n }\n);\n\nTaginput.displayName = 'Taginput';\n\n/** @deprecated Use `Taginput` — same component. */\nexport const TagInput = Taginput;\n\n/** @deprecated Use `TaginputProps`. */\nexport type TagInputProps = TaginputProps;\n\nexport default Taginput;\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Taginput.js","sources":["../../../src/form/Taginput.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useState,\n useRef,\n useEffect,\n useCallback,\n useId,\n} from 'react';\nimport {\n classNames,\n usePrefixedClassNames,\n prefixedClassNames,\n} from '../helpers/classNames';\nimport { useConfig, useIconLibrary } from '../helpers/Config';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { isEventInside } from '../helpers/shadowDom';\nimport {\n useInsideField,\n useInsideControl,\n rendersOwnField,\n} from './FormContext';\nimport { Field } from './Field';\nimport { FormFieldProps } from './fieldProps';\nimport { useAutoLabelId } from './useAutoLabelId';\nimport { Icon } from '../elements/Icon';\n\n/**\n * Represents a tag item object with a value and optional label.\n */\nexport interface TaginputItem {\n /** The tag value. */\n value: string;\n /** Display label (optional). */\n label?: string;\n [key: string]: unknown;\n}\n\n/** A tag can be either a TaginputItem object or a plain string. */\nexport type TaginputTag = TaginputItem | string;\n\ntype IconLibrary = 'fa' | 'mdi' | 'ion' | 'material-icons' | 'material-symbols';\n\n/**\n * Props for the Taginput component.\n * Inside an outer `Field`, or a `Control` with no `Field` around it, it\n * renders no `Field` of its own. The exception is `label`, `message`,\n * `horizontal` or `fieldClassName` in that bare `Control`: it keeps a `Field`\n * for them, nested in the `.control`, and warns in development. Wrap the\n * `Control` in a `Field` instead, and set the `label`, `horizontal` and class\n * name on that `Field`.\n * @extraProp {string} [className] - Additional CSS classes.\n * @extraProp {React.Ref<HTMLInputElement>} [ref] - Ref forwarded to the input element.\n */\nexport interface TaginputProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'>,\n Omit<BulmaClassesProps, 'color'>,\n FormFieldProps {\n /** Field label. Automatically associated with the text input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired when the tag limit is reached (the input is not rendered). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here; it then replaces the `aria-label=\"Add tag\"` fallback too. With `data`, the label naming the input also names the open suggestion list, through `aria-labelledby`, when it has an id: this label always does, and an outer `Field`'s does unless you wired it by hand without an `id` in its `labelProps`. Otherwise the list is named \"Suggestions\". */\n label?: React.ReactNode;\n /** Props for the label element. An explicit `htmlFor` here overrides the automatic association (no id is generated then). With `data`, while the label names the input, the suggestion list's `aria-labelledby` points at it, through an `id` here when you give one and a generated one otherwise. */\n labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {\n [key: string]: unknown;\n };\n /** Applied to the inner text input (the labellable control), not the wrapper div. */\n id?: string;\n /** The current tags (controlled). */\n value?: TaginputTag[];\n /** Default tags (uncontrolled). */\n defaultValue?: TaginputTag[];\n /**\n * Autocomplete suggestions. With `data` set, even to an empty array, the\n * text input is a `role=\"combobox\"` that controls the suggestion list and\n * points `aria-activedescendant` at the highlighted suggestion. Without it\n * there's no list, so the input stays a plain text field.\n */\n data?: string[];\n /** Placeholder text when no tags. */\n placeholder?: string;\n /** Object property to use as display field. */\n field?: string;\n /** Allow creating new tags not in suggestions. */\n allowNew?: boolean;\n /** Allow duplicate tags. */\n allowDuplicates?: boolean;\n /** Open autocomplete dropdown on focus. */\n openOnFocus?: boolean;\n /** Remove tag on backspace. Default: true. */\n removeOnKeys?: boolean;\n /** Keys to confirm tag creation. Default: ['Enter', ',']. */\n confirmKeys?: string[];\n /** Show close button on tags. Default: true. */\n closable?: boolean;\n /** Attach tags visually. */\n attached?: boolean;\n /** Maximum number of tags allowed. */\n maxTags?: number;\n /** Maximum length of input. */\n maxlength?: number;\n /** Whether the input is disabled. */\n disabled?: boolean;\n /** Whether the input is read-only. */\n readonly?: boolean;\n /** Applies rounded corners to the tags. */\n rounded?: boolean;\n /** Truncates long tag text with ellipsis. */\n ellipsis?: boolean;\n /** Shows a counter of the number of tags. */\n hasCounter?: boolean;\n /** Characters that split pasted text into tags. */\n onPasteSeparators?: string[];\n /** Validation function called before adding a tag. */\n beforeAdding?: (tag: string) => boolean;\n /** Custom function for creating tag objects from input. */\n createTag?: (input: string) => TaginputTag;\n /** Keeps the first autocomplete suggestion highlighted. */\n keepFirst?: boolean;\n /** Keeps the autocomplete dropdown open after selection. */\n keepOpen?: boolean;\n /**\n * Shows a loading spinner in the input.\n * Under `prefers-reduced-motion: reduce` the spinner stops and stays\n * drawn (with bestax's CSS loaded).\n */\n loading?: boolean;\n /** ARIA label for tag close buttons. */\n ariaCloseLabel?: string;\n /** Icon name for the input field. */\n icon?: string;\n /** Icon library to use. */\n iconLibrary?: IconLibrary;\n /** Icon style variant (e.g., 'solid', 'outlined'). */\n iconVariant?: string;\n /** Additional icon modifiers. */\n iconFeatures?: string | string[];\n /** Input color variant. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Tag color variant. */\n tagColor?:\n | 'primary'\n | 'link'\n | 'info'\n | 'success'\n | 'warning'\n | 'danger'\n | 'dark'\n | 'light';\n /** Size variant. */\n size?: 'small' | 'medium' | 'large';\n /** Form field name. When set, one hidden input per tag is rendered. */\n name?: string;\n /** Optional id of the form the hidden inputs belong to. */\n form?: string;\n /** Callback when tags change. */\n onChange?: (tags: TaginputTag[]) => void;\n /** Callback when tag is added. */\n onAdd?: (tag: TaginputTag) => void;\n /** Callback when tag is removed. */\n onRemove?: (tag: TaginputTag, index: number) => void;\n /** Callback when typing in input. */\n onTyping?: (value: string) => void;\n /** Custom render for tags. */\n tagTemplate?: (tag: TaginputTag) => React.ReactNode;\n}\n\n/**\n * The `Taginput` component provides a tag/chip input field for managing multiple tags.\n *\n * @function\n * @param {TaginputProps} props - Props for the Taginput component.\n * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the input element.\n * @returns {JSX.Element} The rendered taginput component.\n *\n * @example\n * // Basic usage\n * <Taginput\n * placeholder=\"Add a tag...\"\n * onChange={(tags) => console.log(tags)}\n * />\n *\n * @example\n * // With autocomplete\n * <Taginput\n * data={['React', 'Vue', 'Angular', 'Svelte']}\n * allowNew={false}\n * placeholder=\"Select frameworks...\"\n * />\n */\nexport const Taginput = forwardRef<HTMLInputElement, TaginputProps>(\n (\n {\n // Field props\n label,\n labelSize,\n labelProps,\n horizontal,\n message,\n messageColor,\n fieldClassName,\n value: controlledValue,\n defaultValue = [],\n data: dataProp,\n placeholder,\n field = 'label',\n allowNew = true,\n allowDuplicates = false,\n openOnFocus = false,\n removeOnKeys = true,\n confirmKeys = ['Enter', ','],\n closable = true,\n attached = false,\n maxTags,\n maxlength,\n disabled = false,\n readonly = false,\n rounded = false,\n ellipsis = false,\n hasCounter = true,\n onPasteSeparators = [','],\n beforeAdding,\n createTag,\n keepFirst = false,\n keepOpen = true,\n loading = false,\n ariaCloseLabel,\n icon,\n iconLibrary: iconLibraryProp,\n iconVariant,\n iconFeatures,\n color,\n tagColor,\n size,\n onChange,\n onAdd,\n onRemove,\n onTyping,\n tagTemplate,\n name,\n form,\n id,\n className,\n ...props\n },\n ref\n ) => {\n const insideField = useInsideField();\n const insideControl = useInsideControl();\n const ownField = rendersOwnField('Taginput', {\n insideField,\n insideControl,\n label,\n message,\n horizontal,\n fieldClassName,\n });\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const { classPrefix } = useConfig();\n const defaultIconLibrary = useIconLibrary();\n const resolvedLibrary = iconLibraryProp || defaultIconLibrary || 'fa';\n const pcn = (\n ...args: (\n | string\n | number\n | undefined\n | null\n | false\n | Record<string, unknown>\n | unknown[]\n )[]\n ) => prefixedClassNames(classPrefix, ...args);\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n const [internalTags, setInternalTags] =\n useState<TaginputTag[]>(defaultValue);\n const [inputValue, setInputValue] = useState('');\n const [isActive, setIsActive] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const listboxId = `${useId()}-listbox`;\n\n // With `data` the input offers suggestions, so it's a combobox, even\n // while none match. Without it there's never a list, so it stays a plain\n // text field.\n const hasSuggestions = dataProp !== undefined;\n const data = dataProp ?? [];\n\n // Use controlled or internal tags\n const tags = controlledValue !== undefined ? controlledValue : internalTags;\n\n const isMaxReached = maxTags !== undefined && tags.length >= maxTags;\n // At the tag limit the text input is not rendered, so there is nothing to\n // wire a label to, its own or a surrounding Field's. The suggestion list\n // points `aria-labelledby` at the label that names the input, so with\n // suggestions it needs that label's id.\n const {\n controlId,\n fieldLabelProps,\n labelled,\n labelId: listLabelId,\n } = useAutoLabelId({\n label,\n id,\n labelProps,\n rendersLabel: ownField && !isMaxReached,\n hasInput: !isMaxReached,\n needsLabelId: hasSuggestions,\n });\n\n // Get display value from tag\n const getDisplayValue = (tag: TaginputTag): string => {\n if (typeof tag === 'string') return tag;\n const fieldValue = tag[field];\n if (typeof fieldValue === 'string') return fieldValue;\n return tag.value || '';\n };\n\n // Filter autocomplete data\n const filteredData = data.filter(item => {\n const displayValue = item.toLowerCase();\n const matchesInput = displayValue.includes(inputValue.toLowerCase());\n const notAlreadyAdded =\n allowDuplicates ||\n !tags.some(tag => getDisplayValue(tag).toLowerCase() === displayValue);\n const hasInput = inputValue || (openOnFocus && isActive);\n return matchesInput && notAlreadyAdded && hasInput;\n });\n const listOpen = isActive && filteredData.length > 0;\n\n // keepFirst: auto-highlight first item when dropdown opens\n useEffect(() => {\n if (keepFirst && isActive && filteredData.length > 0) {\n setHighlightedIndex(0);\n }\n }, [keepFirst, isActive, filteredData.length]);\n\n // Update tags\n const updateTags = useCallback(\n (newTags: TaginputTag[]) => {\n if (controlledValue === undefined) {\n setInternalTags(newTags);\n }\n onChange?.(newTags);\n },\n [controlledValue, onChange]\n );\n\n // Add tag\n const addTag = useCallback(\n (value: string | TaginputTag) => {\n if (disabled || readonly) return;\n\n const tagValue = typeof value === 'string' ? value.trim() : value;\n const displayValue =\n typeof tagValue === 'string' ? tagValue : getDisplayValue(tagValue);\n\n if (!displayValue) return;\n\n // Check max tags\n if (maxTags && tags.length >= maxTags) return;\n\n // Check duplicates\n if (!allowDuplicates) {\n const exists = tags.some(\n tag =>\n getDisplayValue(tag).toLowerCase() === displayValue.toLowerCase()\n );\n if (exists) return;\n }\n\n // Check if allowed (must be in data if allowNew is false). Compare\n // case-insensitively, consistent with the dropdown filter and the\n // duplicate check above.\n if (\n !allowNew &&\n !data.some(d => d.toLowerCase() === displayValue.toLowerCase())\n )\n return;\n\n // beforeAdding validation\n if (beforeAdding && !beforeAdding(displayValue)) return;\n\n // createTag transformation\n const finalTag = createTag ? createTag(displayValue) : tagValue;\n\n const newTags = [...tags, finalTag];\n updateTags(newTags);\n onAdd?.(finalTag);\n setInputValue('');\n if (!keepOpen) {\n setIsActive(false);\n }\n setHighlightedIndex(-1);\n },\n [\n disabled,\n readonly,\n tags,\n maxTags,\n allowDuplicates,\n allowNew,\n data,\n field,\n updateTags,\n onAdd,\n beforeAdding,\n createTag,\n keepOpen,\n ]\n );\n\n // Remove tag\n const removeTag = useCallback(\n (index: number) => {\n /* istanbul ignore next: both triggers (delete button click, Backspace handler) are already gated on disabled/readonly */\n if (disabled || readonly) return;\n\n const removedTag = tags[index];\n const newTags = tags.filter((_, i) => i !== index);\n updateTags(newTags);\n onRemove?.(removedTag, index);\n },\n [disabled, readonly, tags, updateTags, onRemove]\n );\n\n // Handle input change\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n\n // Check if a confirm key was typed\n const lastChar = newValue.slice(-1);\n if (confirmKeys.includes(lastChar) && lastChar !== 'Enter') {\n const valueWithoutKey = newValue.slice(0, -1).trim();\n if (valueWithoutKey) {\n addTag(valueWithoutKey);\n }\n return;\n }\n\n setInputValue(newValue);\n onTyping?.(newValue);\n\n if (newValue && data.length > 0) {\n setIsActive(true);\n }\n },\n [confirmKeys, addTag, onTyping, data.length]\n );\n\n // Handle paste\n const handlePaste = useCallback(\n (e: React.ClipboardEvent<HTMLInputElement>) => {\n if (onPasteSeparators.length === 0) return;\n\n const pastedText = e.clipboardData.getData('text');\n // Check if any separator exists in the pasted text\n const hasSeparator = onPasteSeparators.some(sep =>\n pastedText.includes(sep)\n );\n\n if (!hasSeparator) return;\n\n e.preventDefault();\n\n // Build a regex from all separators\n const escapedSeparators = onPasteSeparators.map(s =>\n s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n );\n const regex = new RegExp(`[${escapedSeparators.join('')}]`);\n\n const parts = pastedText\n .split(regex)\n .map(s => s.trim())\n .filter(Boolean);\n\n for (const part of parts) {\n addTag(part);\n }\n },\n [onPasteSeparators, addTag]\n );\n\n // Handle focus\n const handleFocus = useCallback(() => {\n if (openOnFocus && data.length > 0 && !disabled) {\n setIsActive(true);\n }\n }, [openOnFocus, data.length, disabled]);\n\n // Handle click outside\n useEffect(() => {\n if (!isActive) return undefined;\n\n const handleClickOutside = (e: MouseEvent) => {\n if (containerRef.current && !isEventInside(e, containerRef.current)) {\n setIsActive(false);\n setHighlightedIndex(-1);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () =>\n document.removeEventListener('mousedown', handleClickOutside);\n }, [isActive]);\n\n // Handle keyboard\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (disabled || readonly) return;\n\n // Handle confirm keys\n if (confirmKeys.includes(e.key)) {\n e.preventDefault();\n if (highlightedIndex >= 0 && filteredData[highlightedIndex]) {\n addTag(filteredData[highlightedIndex]);\n } else if (inputValue.trim()) {\n addTag(inputValue);\n }\n return;\n }\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!isActive && data.length > 0) {\n setIsActive(true);\n } else {\n setHighlightedIndex(prev =>\n prev < filteredData.length - 1 ? prev + 1 : prev\n );\n }\n break;\n case 'ArrowUp':\n e.preventDefault();\n setHighlightedIndex(prev => (prev > 0 ? prev - 1 : prev));\n break;\n case 'Backspace':\n if (removeOnKeys && !inputValue && tags.length > 0) {\n e.preventDefault();\n removeTag(tags.length - 1);\n }\n break;\n case 'Escape':\n setIsActive(false);\n setHighlightedIndex(-1);\n break;\n }\n },\n [\n disabled,\n readonly,\n confirmKeys,\n highlightedIndex,\n filteredData,\n addTag,\n inputValue,\n isActive,\n data.length,\n removeOnKeys,\n tags.length,\n removeTag,\n ]\n );\n\n // Combined ref\n const combinedRef = useCallback(\n (node: HTMLInputElement | null) => {\n (inputRef as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n }\n },\n [ref]\n );\n\n // Focus input when container is clicked\n const handleContainerClick = useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n // Generate classes\n const taginputClasses = pcn('taginput', {\n 'is-active': isActive,\n [`is-${size}`]: !!size,\n [`is-${color}`]: !!color,\n 'is-disabled': disabled,\n 'is-rounded': rounded,\n 'is-ellipsis': ellipsis,\n });\n\n const containerClasses = pcn('taginput-container', {\n 'is-attached': attached,\n 'has-icons-left': !!icon,\n });\n\n const inputClasses = pcn('input', {\n [`is-${size}`]: !!size,\n });\n\n const tagClasses = pcn('tag', {\n [`is-${tagColor}`]: !!tagColor,\n [`is-${size}`]: !!size,\n });\n\n const combinedClasses = classNames(\n taginputClasses,\n bulmaHelperClasses,\n className\n );\n\n // Counter text\n const showCounter =\n hasCounter && (maxTags !== undefined || maxlength !== undefined);\n const counterText =\n maxTags !== undefined\n ? `${tags.length} / ${maxTags}`\n : maxlength !== undefined\n ? `${inputValue.length} / ${maxlength}`\n : '';\n\n const counterClasses = pcn('help', 'counter');\n const tagsClasses = pcn('tags');\n const dropdownMenuClasses = pcn('dropdown-menu', 'is-active');\n const dropdownContentClasses = pcn('dropdown-content');\n const iconRightClass = pcn('icon', 'is-right');\n const loaderClass = pcn('loader', 'is-loading');\n\n const helpClass = usePrefixedClassNames('help', {\n [`is-${messageColor}`]: !!messageColor,\n });\n const messageEl = message ? <p className={helpClass}>{message}</p> : null;\n\n // The combobox controls its listbox and points at the highlighted option,\n // the way Autocomplete's does. The listbox takes its name from the label\n // that names the combobox, the one this renders or a surrounding Field's,\n // and keeps a fallback name when no label names it or the one that does\n // has no id to point at. While no suggestion matches there's no listbox,\n // so the combobox is collapsed and points at nothing. It skips a\n // highlighted suggestion that's blank once trimmed, since that one can't\n // become a tag, and the option it points at is the one marked selected.\n const optionId = (index: number) => `${listboxId}-${index}`;\n const activeOptionId =\n listOpen && filteredData[highlightedIndex]?.trim()\n ? optionId(highlightedIndex)\n : undefined;\n const comboboxProps: React.InputHTMLAttributes<HTMLInputElement> = {\n role: 'combobox',\n 'aria-expanded': listOpen,\n 'aria-controls': listOpen ? listboxId : undefined,\n 'aria-activedescendant': activeOptionId,\n 'aria-haspopup': 'listbox',\n 'aria-autocomplete': 'list',\n };\n\n const taginputElement = (\n <div\n ref={containerRef}\n className={combinedClasses}\n onClick={handleContainerClick}\n {...rest}\n >\n <div className={containerClasses}>\n {icon && (\n <Icon\n name={icon}\n library={resolvedLibrary}\n variant={iconVariant}\n features={iconFeatures}\n containerClassName={pcn('icon', 'is-left')}\n />\n )}\n <div className={tagsClasses}>\n {tags.map((tag, index) => {\n const displayVal = getDisplayValue(tag);\n return (\n <span key={index} className={tagClasses}>\n {tagTemplate ? (\n tagTemplate(tag)\n ) : ellipsis ? (\n <span title={displayVal}>{displayVal}</span>\n ) : (\n displayVal\n )}\n {closable && !disabled && !readonly && (\n <button\n type=\"button\"\n className={pcn('delete', 'is-small')}\n onClick={e => {\n e.stopPropagation();\n removeTag(index);\n }}\n aria-label={ariaCloseLabel || `Remove ${displayVal}`}\n />\n )}\n </span>\n );\n })}\n {!isMaxReached && (\n <input\n ref={combinedRef}\n type=\"text\"\n className={inputClasses}\n id={controlId}\n value={inputValue}\n placeholder={tags.length === 0 ? placeholder : undefined}\n disabled={disabled}\n readOnly={readonly}\n maxLength={maxlength}\n onChange={handleInputChange}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n {...(hasSuggestions && comboboxProps)}\n // Fallback name, dropped only when a rendered label actually\n // targets this input, its own or a surrounding Field's\n // (aria-label would win otherwise). A label pointing elsewhere\n // keeps the fallback so the input is never nameless.\n aria-label={labelled ? undefined : 'Add tag'}\n />\n )}\n </div>\n {loading && (\n <span className={iconRightClass}>\n <span className={loaderClass} />\n </span>\n )}\n </div>\n\n {listOpen && (\n <div className={dropdownMenuClasses}>\n <div\n ref={dropdownRef}\n id={listboxId}\n className={dropdownContentClasses}\n role=\"listbox\"\n aria-labelledby={listLabelId}\n aria-label={listLabelId ? undefined : 'Suggestions'}\n >\n {filteredData.map((item, index) => (\n <a\n key={index}\n id={optionId(index)}\n className={pcn('dropdown-item', {\n 'is-active': index === highlightedIndex,\n })}\n onClick={() => addTag(item)}\n onMouseEnter={() => setHighlightedIndex(index)}\n role=\"option\"\n aria-selected={optionId(index) === activeOptionId}\n >\n {item}\n </a>\n ))}\n </div>\n </div>\n )}\n\n {showCounter && <small className={counterClasses}>{counterText}</small>}\n\n {name &&\n tags.map((tag, i) => (\n <input\n key={`tag-input-${i}`}\n type=\"hidden\"\n name={name}\n value={getDisplayValue(tag)}\n form={form}\n />\n ))}\n </div>\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 {taginputElement}\n {messageEl}\n </Field>\n );\n }\n\n return (\n <>\n {taginputElement}\n {messageEl}\n </>\n );\n }\n);\n\nTaginput.displayName = 'Taginput';\n\n/** @deprecated Use `Taginput` — same component. */\nexport const TagInput = Taginput;\n\n/** @deprecated Use `TaginputProps`. */\nexport type TagInputProps = TaginputProps;\n\nexport default Taginput;\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":";;;;;;;;;;;;AAqKA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACI,MAAM,QAAQ,GAAG,UAAU,CAChC,CACE;AACE;AACA,KAAK,EACL,SAAS,EACT,UAAU,EACV,UAAU,EACV,OAAO,EACP,YAAY,EACZ,cAAc,EACd,KAAK,EAAE,eAAe,EACtB,YAAY,GAAG,EAAE,EACjB,IAAI,EAAE,QAAQ,EACd,WAAW,EACX,KAAK,GAAG,OAAO,EACf,QAAQ,GAAG,IAAI,EACf,eAAe,GAAG,KAAK,EACvB,WAAW,GAAG,KAAK,EACnB,YAAY,GAAG,IAAI,EACnB,WAAW,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,EAC5B,QAAQ,GAAG,IAAI,EACf,QAAQ,GAAG,KAAK,EAChB,OAAO,EACP,SAAS,EACT,QAAQ,GAAG,KAAK,EAChB,QAAQ,GAAG,KAAK,EAChB,OAAO,GAAG,KAAK,EACf,QAAQ,GAAG,KAAK,EAChB,UAAU,GAAG,IAAI,EACjB,iBAAiB,GAAG,CAAC,GAAG,CAAC,EACzB,YAAY,EACZ,SAAS,EACT,SAAS,GAAG,KAAK,EACjB,QAAQ,GAAG,IAAI,EACf,OAAO,GAAG,KAAK,EACf,cAAc,EACd,IAAI,EACJ,WAAW,EAAE,eAAe,EAC5B,WAAW,EACX,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,IAAI,EACJ,IAAI,EACJ,EAAE,EACF,SAAS,EACT,GAAG,KAAK,EACT,EACD,GAAG,KACD;AACF,IAAA,MAAM,WAAW,GAAG,cAAc,EAAE;AACpC,IAAA,MAAM,aAAa,GAAG,gBAAgB,EAAE;AACxC,IAAA,MAAM,QAAQ,GAAG,eAAe,CAAC,UAAU,EAAE;QAC3C,WAAW;QACX,aAAa;QACb,KAAK;QACL,OAAO;QACP,UAAU;QACV,cAAc;AACf,KAAA,CAAC;IACF,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC,KAAK,CAAC;AAC3D,IAAA,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,EAAE;AACnC,IAAA,MAAM,kBAAkB,GAAG,cAAc,EAAE;AAC3C,IAAA,MAAM,eAAe,GAAG,eAAe,IAAI,kBAAkB,IAAI,IAAI;AACrE,IAAA,MAAM,GAAG,GAAG,CACV,GAAG,IAQA,KACA,kBAAkB,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC;AAC7C,IAAA,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC;AACjD,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAmB,IAAI,CAAC;AAC/C,IAAA,MAAM,WAAW,GAAG,MAAM,CAAiB,IAAI,CAAC;IAEhD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GACnC,QAAQ,CAAgB,YAAY,CAAC;IACvC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;IAChD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;IAC/C,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;AAC5D,IAAA,MAAM,SAAS,GAAG,CAAA,EAAG,KAAK,EAAE,UAAU;;;;AAKtC,IAAA,MAAM,cAAc,GAAG,QAAQ,KAAK,SAAS;AAC7C,IAAA,MAAM,IAAI,GAAG,QAAQ,IAAI,EAAE;;AAG3B,IAAA,MAAM,IAAI,GAAG,eAAe,KAAK,SAAS,GAAG,eAAe,GAAG,YAAY;IAE3E,MAAM,YAAY,GAAG,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO;;;;;AAKpE,IAAA,MAAM,EACJ,SAAS,EACT,eAAe,EACf,QAAQ,EACR,OAAO,EAAE,WAAW,GACrB,GAAG,cAAc,CAAC;QACjB,KAAK;QACL,EAAE;QACF,UAAU;AACV,QAAA,YAAY,EAAE,QAAQ,IAAI,CAAC,YAAY;QACvC,QAAQ,EAAE,CAAC,YAAY;AACvB,QAAA,YAAY,EAAE,cAAc;AAC7B,KAAA,CAAC;;AAGF,IAAA,MAAM,eAAe,GAAG,CAAC,GAAgB,KAAY;QACnD,IAAI,OAAO,GAAG,KAAK,QAAQ;AAAE,YAAA,OAAO,GAAG;AACvC,QAAA,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC;QAC7B,IAAI,OAAO,UAAU,KAAK,QAAQ;AAAE,YAAA,OAAO,UAAU;AACrD,QAAA,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;AACxB,IAAA,CAAC;;IAGD,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,IAAG;AACtC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE;QACvC,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;QACpE,MAAM,eAAe,GACnB,eAAe;AACf,YAAA,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC;QACxE,MAAM,QAAQ,GAAG,UAAU,KAAK,WAAW,IAAI,QAAQ,CAAC;AACxD,QAAA,OAAO,YAAY,IAAI,eAAe,IAAI,QAAQ;AACpD,IAAA,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,QAAQ,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC;;IAGpD,SAAS,CAAC,MAAK;QACb,IAAI,SAAS,IAAI,QAAQ,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE;YACpD,mBAAmB,CAAC,CAAC,CAAC;QACxB;IACF,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;;AAG9C,IAAA,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,OAAsB,KAAI;AACzB,QAAA,IAAI,eAAe,KAAK,SAAS,EAAE;YACjC,eAAe,CAAC,OAAO,CAAC;QAC1B;AACA,QAAA,QAAQ,GAAG,OAAO,CAAC;AACrB,IAAA,CAAC,EACD,CAAC,eAAe,EAAE,QAAQ,CAAC,CAC5B;;AAGD,IAAA,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,KAA2B,KAAI;QAC9B,IAAI,QAAQ,IAAI,QAAQ;YAAE;AAE1B,QAAA,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,QAAQ,GAAG,KAAK,CAAC,IAAI,EAAE,GAAG,KAAK;AACjE,QAAA,MAAM,YAAY,GAChB,OAAO,QAAQ,KAAK,QAAQ,GAAG,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC;AAErE,QAAA,IAAI,CAAC,YAAY;YAAE;;AAGnB,QAAA,IAAI,OAAO,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO;YAAE;;QAGvC,IAAI,CAAC,eAAe,EAAE;YACpB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CACtB,GAAG,IACD,eAAe,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC,WAAW,EAAE,CACpE;AACD,YAAA,IAAI,MAAM;gBAAE;QACd;;;;AAKA,QAAA,IACE,CAAC,QAAQ;AACT,YAAA,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC,WAAW,EAAE,CAAC;YAE/D;;AAGF,QAAA,IAAI,YAAY,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC;YAAE;;AAGjD,QAAA,MAAM,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,QAAQ;QAE/D,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,EAAE,QAAQ,CAAC;QACnC,UAAU,CAAC,OAAO,CAAC;AACnB,QAAA,KAAK,GAAG,QAAQ,CAAC;QACjB,aAAa,CAAC,EAAE,CAAC;QACjB,IAAI,CAAC,QAAQ,EAAE;YACb,WAAW,CAAC,KAAK,CAAC;QACpB;AACA,QAAA,mBAAmB,CAAC,EAAE,CAAC;AACzB,IAAA,CAAC,EACD;QACE,QAAQ;QACR,QAAQ;QACR,IAAI;QACJ,OAAO;QACP,eAAe;QACf,QAAQ;QACR,IAAI;QACJ,KAAK;QACL,UAAU;QACV,KAAK;QACL,YAAY;QACZ,SAAS;QACT,QAAQ;AACT,KAAA,CACF;;AAGD,IAAA,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,KAAa,KAAI;;QAEhB,IAAI,QAAQ,IAAI,QAAQ;YAAE;AAE1B,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC;AAC9B,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC;QAClD,UAAU,CAAC,OAAO,CAAC;AACnB,QAAA,QAAQ,GAAG,UAAU,EAAE,KAAK,CAAC;AAC/B,IAAA,CAAC,EACD,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,CACjD;;AAGD,IAAA,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,CAAsC,KAAI;AACzC,QAAA,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK;;QAG/B,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACnC,IAAI,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,OAAO,EAAE;AAC1D,YAAA,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;YACpD,IAAI,eAAe,EAAE;gBACnB,MAAM,CAAC,eAAe,CAAC;YACzB;YACA;QACF;QAEA,aAAa,CAAC,QAAQ,CAAC;AACvB,QAAA,QAAQ,GAAG,QAAQ,CAAC;QAEpB,IAAI,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;YAC/B,WAAW,CAAC,IAAI,CAAC;QACnB;AACF,IAAA,CAAC,EACD,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAC7C;;AAGD,IAAA,MAAM,WAAW,GAAG,WAAW,CAC7B,CAAC,CAAyC,KAAI;AAC5C,QAAA,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;YAAE;QAEpC,MAAM,UAAU,GAAG,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC;;AAElD,QAAA,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,IAC7C,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CACzB;AAED,QAAA,IAAI,CAAC,YAAY;YAAE;QAEnB,CAAC,CAAC,cAAc,EAAE;;AAGlB,QAAA,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,IAC/C,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CACzC;AACD,QAAA,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,CAAA,CAAA,EAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA,CAAA,CAAG,CAAC;QAE3D,MAAM,KAAK,GAAG;aACX,KAAK,CAAC,KAAK;aACX,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;aACjB,MAAM,CAAC,OAAO,CAAC;AAElB,QAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,MAAM,CAAC,IAAI,CAAC;QACd;AACF,IAAA,CAAC,EACD,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAC5B;;AAGD,IAAA,MAAM,WAAW,GAAG,WAAW,CAAC,MAAK;QACnC,IAAI,WAAW,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE;YAC/C,WAAW,CAAC,IAAI,CAAC;QACnB;IACF,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;;IAGxC,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,SAAS;AAE/B,QAAA,MAAM,kBAAkB,GAAG,CAAC,CAAa,KAAI;AAC3C,YAAA,IAAI,YAAY,CAAC,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE;gBACnE,WAAW,CAAC,KAAK,CAAC;AAClB,gBAAA,mBAAmB,CAAC,EAAE,CAAC;YACzB;AACF,QAAA,CAAC;AAED,QAAA,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,kBAAkB,CAAC;QAC1D,OAAO,MACL,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,kBAAkB,CAAC;AACjE,IAAA,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;;AAGd,IAAA,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,CAAsB,KAAI;QACzB,IAAI,QAAQ,IAAI,QAAQ;YAAE;;QAG1B,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;YAC/B,CAAC,CAAC,cAAc,EAAE;YAClB,IAAI,gBAAgB,IAAI,CAAC,IAAI,YAAY,CAAC,gBAAgB,CAAC,EAAE;AAC3D,gBAAA,MAAM,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;YACxC;AAAO,iBAAA,IAAI,UAAU,CAAC,IAAI,EAAE,EAAE;gBAC5B,MAAM,CAAC,UAAU,CAAC;YACpB;YACA;QACF;AAEA,QAAA,QAAQ,CAAC,CAAC,GAAG;AACX,YAAA,KAAK,WAAW;gBACd,CAAC,CAAC,cAAc,EAAE;gBAClB,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;oBAChC,WAAW,CAAC,IAAI,CAAC;gBACnB;qBAAO;oBACL,mBAAmB,CAAC,IAAI,IACtB,IAAI,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CACjD;gBACH;gBACA;AACF,YAAA,KAAK,SAAS;gBACZ,CAAC,CAAC,cAAc,EAAE;gBAClB,mBAAmB,CAAC,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;gBACzD;AACF,YAAA,KAAK,WAAW;gBACd,IAAI,YAAY,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;oBAClD,CAAC,CAAC,cAAc,EAAE;AAClB,oBAAA,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC5B;gBACA;AACF,YAAA,KAAK,QAAQ;gBACX,WAAW,CAAC,KAAK,CAAC;AAClB,gBAAA,mBAAmB,CAAC,EAAE,CAAC;gBACvB;;AAEN,IAAA,CAAC,EACD;QACE,QAAQ;QACR,QAAQ;QACR,WAAW;QACX,gBAAgB;QAChB,YAAY;QACZ,MAAM;QACN,UAAU;QACV,QAAQ;AACR,QAAA,IAAI,CAAC,MAAM;QACX,YAAY;AACZ,QAAA,IAAI,CAAC,MAAM;QACX,SAAS;AACV,KAAA,CACF;;AAGD,IAAA,MAAM,WAAW,GAAG,WAAW,CAC7B,CAAC,IAA6B,KAAI;AAC/B,QAAA,QAA4D,CAAC,OAAO;AACnE,YAAA,IAAI;AACN,QAAA,IAAI,OAAO,GAAG,KAAK,UAAU,EAAE;YAC7B,GAAG,CAAC,IAAI,CAAC;QACX;aAAO,IAAI,GAAG,EAAE;AACb,YAAA,GAAuD,CAAC,OAAO;AAC9D,gBAAA,IAAI;QACR;AACF,IAAA,CAAC,EACD,CAAC,GAAG,CAAC,CACN;;AAGD,IAAA,MAAM,oBAAoB,GAAG,WAAW,CAAC,MAAK;AAC5C,QAAA,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE;IAC3B,CAAC,EAAE,EAAE,CAAC;;AAGN,IAAA,MAAM,eAAe,GAAG,GAAG,CAAC,UAAU,EAAE;AACtC,QAAA,WAAW,EAAE,QAAQ;AACrB,QAAA,CAAC,MAAM,IAAI,CAAA,CAAE,GAAG,CAAC,CAAC,IAAI;AACtB,QAAA,CAAC,MAAM,KAAK,CAAA,CAAE,GAAG,CAAC,CAAC,KAAK;AACxB,QAAA,aAAa,EAAE,QAAQ;AACvB,QAAA,YAAY,EAAE,OAAO;AACrB,QAAA,aAAa,EAAE,QAAQ;AACxB,KAAA,CAAC;AAEF,IAAA,MAAM,gBAAgB,GAAG,GAAG,CAAC,oBAAoB,EAAE;AACjD,QAAA,aAAa,EAAE,QAAQ;QACvB,gBAAgB,EAAE,CAAC,CAAC,IAAI;AACzB,KAAA,CAAC;AAEF,IAAA,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,EAAE;AAChC,QAAA,CAAC,MAAM,IAAI,CAAA,CAAE,GAAG,CAAC,CAAC,IAAI;AACvB,KAAA,CAAC;AAEF,IAAA,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,EAAE;AAC5B,QAAA,CAAC,MAAM,QAAQ,CAAA,CAAE,GAAG,CAAC,CAAC,QAAQ;AAC9B,QAAA,CAAC,MAAM,IAAI,CAAA,CAAE,GAAG,CAAC,CAAC,IAAI;AACvB,KAAA,CAAC;IAEF,MAAM,eAAe,GAAG,UAAU,CAChC,eAAe,EACf,kBAAkB,EAClB,SAAS,CACV;;AAGD,IAAA,MAAM,WAAW,GACf,UAAU,KAAK,OAAO,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS,CAAC;AAClE,IAAA,MAAM,WAAW,GACf,OAAO,KAAK;AACV,UAAE,CAAA,EAAG,IAAI,CAAC,MAAM,CAAA,GAAA,EAAM,OAAO,CAAA;UAC3B,SAAS,KAAK;AACd,cAAE,CAAA,EAAG,UAAU,CAAC,MAAM,CAAA,GAAA,EAAM,SAAS,CAAA;cACnC,EAAE;IAEV,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC;AAC7C,IAAA,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC;IAC/B,MAAM,mBAAmB,GAAG,GAAG,CAAC,eAAe,EAAE,WAAW,CAAC;AAC7D,IAAA,MAAM,sBAAsB,GAAG,GAAG,CAAC,kBAAkB,CAAC;IACtD,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;IAC9C,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,EAAE,YAAY,CAAC;AAE/C,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;;;;;;;;;AAUzE,IAAA,MAAM,QAAQ,GAAG,CAAC,KAAa,KAAK,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE;IAC3D,MAAM,cAAc,GAClB,QAAQ,IAAI,YAAY,CAAC,gBAAgB,CAAC,EAAE,IAAI;AAC9C,UAAE,QAAQ,CAAC,gBAAgB;UACzB,SAAS;AACf,IAAA,MAAM,aAAa,GAAgD;AACjE,QAAA,IAAI,EAAE,UAAU;AAChB,QAAA,eAAe,EAAE,QAAQ;QACzB,eAAe,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS;AACjD,QAAA,uBAAuB,EAAE,cAAc;AACvC,QAAA,eAAe,EAAE,SAAS;AAC1B,QAAA,mBAAmB,EAAE,MAAM;KAC5B;AAED,IAAA,MAAM,eAAe,IACnBC,IAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,eAAe,EAC1B,OAAO,EAAE,oBAAoB,EAAA,GACzB,IAAI,EAAA,QAAA,EAAA,CAERA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,gBAAgB,aAC7B,IAAI,KACHD,GAAA,CAAC,IAAI,EAAA,EACH,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAAA,CAC1C,CACH,EACDC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,WAAW,EAAA,QAAA,EAAA,CACxB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,KAAI;AACvB,gCAAA,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC;AACvC,gCAAA,QACEA,IAAA,CAAA,MAAA,EAAA,EAAkB,SAAS,EAAE,UAAU,EAAA,QAAA,EAAA,CACpC,WAAW,IACV,WAAW,CAAC,GAAG,CAAC,IACd,QAAQ,IACVD,GAAA,CAAA,MAAA,EAAA,EAAM,KAAK,EAAE,UAAU,EAAA,QAAA,EAAG,UAAU,GAAQ,KAE5C,UAAU,CACX,EACA,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,KACjCA,GAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,EACpC,OAAO,EAAE,CAAC,IAAG;gDACX,CAAC,CAAC,eAAe,EAAE;gDACnB,SAAS,CAAC,KAAK,CAAC;AAClB,4CAAA,CAAC,EAAA,YAAA,EACW,cAAc,IAAI,CAAA,OAAA,EAAU,UAAU,CAAA,CAAE,EAAA,CACpD,CACH,CAAA,EAAA,EAlBQ,KAAK,CAmBT;AAEX,4BAAA,CAAC,CAAC,EACD,CAAC,YAAY,KACZA,GAAA,CAAA,OAAA,EAAA,EACE,GAAG,EAAE,WAAW,EAChB,IAAI,EAAC,MAAM,EACX,SAAS,EAAE,YAAY,EACvB,EAAE,EAAE,SAAS,EACb,KAAK,EAAE,UAAU,EACjB,WAAW,EAAE,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,WAAW,GAAG,SAAS,EACxD,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,WAAW,MACf,cAAc,IAAI,aAAa,CAAC,EAAA,YAAA,EAKzB,QAAQ,GAAG,SAAS,GAAG,SAAS,GAC5C,CACH,CAAA,EAAA,CACG,EACL,OAAO,KACNA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAE,cAAc,EAAA,QAAA,EAC7BA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAE,WAAW,GAAI,EAAA,CAC3B,CACR,CAAA,EAAA,CACG,EAEL,QAAQ,KACPA,aAAK,SAAS,EAAE,mBAAmB,EAAA,QAAA,EACjCA,GAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,WAAW,EAChB,EAAE,EAAE,SAAS,EACb,SAAS,EAAE,sBAAsB,EACjC,IAAI,EAAC,SAAS,EAAA,iBAAA,EACG,WAAW,EAAA,YAAA,EAChB,WAAW,GAAG,SAAS,GAAG,aAAa,YAElD,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,MAC5BA,GAAA,CAAA,GAAA,EAAA,EAEE,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,EACnB,SAAS,EAAE,GAAG,CAAC,eAAe,EAAE;4BAC9B,WAAW,EAAE,KAAK,KAAK,gBAAgB;yBACxC,CAAC,EACF,OAAO,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,EAC3B,YAAY,EAAE,MAAM,mBAAmB,CAAC,KAAK,CAAC,EAC9C,IAAI,EAAC,QAAQ,EAAA,eAAA,EACE,QAAQ,CAAC,KAAK,CAAC,KAAK,cAAc,EAAA,QAAA,EAEhD,IAAI,IAVA,KAAK,CAWR,CACL,CAAC,EAAA,CACE,EAAA,CACF,CACP,EAEA,WAAW,IAAIA,GAAA,CAAA,OAAA,EAAA,EAAO,SAAS,EAAE,cAAc,EAAA,QAAA,EAAG,WAAW,EAAA,CAAS,EAEtE,IAAI;AACH,gBAAA,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,MACdA,GAAA,CAAA,OAAA,EAAA,EAEE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,EAC3B,IAAI,EAAE,IAAI,EAAA,EAJL,CAAA,UAAA,EAAa,CAAC,CAAA,CAAE,CAKrB,CACH,CAAC,CAAA,EAAA,CACA,CACP;IAED,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,eAAe,EACf,SAAS,CAAA,EAAA,CACJ;IAEZ;AAEA,IAAA,QACEA,IAAA,CAAAC,QAAA,EAAA,EAAA,QAAA,EAAA,CACG,eAAe,EACf,SAAS,CAAA,EAAA,CACT;AAEP,CAAC;AAGH,QAAQ,CAAC,WAAW,GAAG,UAAU;AAEjC;AACO,MAAM,QAAQ,GAAG;;"}
|