@allxsmith/bestax-bulma 5.27.3 → 5.27.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"TimeInputBase.js","sources":["../../../src/form/TimeInputBase.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport {\n PickerPosition,\n HourFormat,\n PickerLabels,\n mergeLabels,\n} from './_pickerInternals/pickerTypes';\nimport {\n formatTime,\n hourCycleFromFormat,\n parseTime,\n DateFormatOption,\n DEFAULT_TIME_FORMAT_24,\n DEFAULT_TIME_FORMAT_12,\n} from './_pickerInternals/formatters';\nimport {\n setTimeOfDay,\n floorMin,\n isWithin,\n snapTimeToIncrement,\n} from './_pickerInternals/dateUtils';\nimport { TimeWheels } from './_pickerInternals/TimeWheels';\nimport { PickerPopover } from './_pickerInternals/PickerPopover';\nimport { useNativeMobilePicker } from './_pickerInternals/useNativeMobilePicker';\nimport { useSegmentedEntry } from './_pickerInternals/useSegmentedEntry';\nimport { useControlLoading } from './controlLoading';\nimport { Icon } from '../elements/Icon';\nimport { Buttons } from '../elements/Buttons';\n\nconst toIsoTime = (d: Date, withSeconds: boolean): string => {\n const hh = String(d.getHours()).padStart(2, '0');\n const mm = String(d.getMinutes()).padStart(2, '0');\n if (!withSeconds) return `${hh}:${mm}`;\n const ss = String(d.getSeconds()).padStart(2, '0');\n return `${hh}:${mm}:${ss}`;\n};\n\nconst fromIsoTime = (s: string): Date | null => {\n // The HTML time value may carry fractional seconds (the spec allows them\n // and some engines normalize to `:ss.sss`); accept and drop.\n const m = /^(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d{1,3})?)?$/.exec(s);\n if (!m) return null;\n const today = new Date();\n return new Date(\n today.getFullYear(),\n today.getMonth(),\n today.getDate(),\n Number(m[1]),\n Number(m[2]),\n m[3] ? Number(m[3]) : 0,\n 0\n );\n};\n\n/**\n * Props for the raw TimeInput base. Use the higher-level `TimeInput` for\n * Field/Control composition; `TimeInputBase` is the input + popover only.\n */\nexport interface TimeInputBaseProps\n extends\n Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n | 'value'\n | 'defaultValue'\n | 'onChange'\n | 'size'\n | 'color'\n | 'min'\n | 'max'\n | 'type'\n | 'popover'\n >,\n Omit<BulmaClassesProps, 'color'> {\n /** Controlled selected time (date portion is preserved). */\n value?: Date | null;\n /** Initial value for uncontrolled usage. */\n defaultValue?: Date | null;\n /** Fired when the value changes. */\n onChange?: (d: Date | null) => void;\n /** Fired when the popover opens. */\n onOpen?: () => void;\n /** Fired when the popover closes. */\n onClose?: () => void;\n /**\n * Earliest selectable time. A `min` before year 1 is raised to midnight on\n * 1 January of year 1, and a `value` dated before then is out of range, so\n * the wheels and typing change nothing on it, as in the date pickers.\n */\n min?: Date;\n /** Latest selectable time. */\n max?: Date;\n /** Disable the input. */\n disabled?: boolean;\n /** Make the input read-only. */\n readOnly?: boolean;\n /** Placeholder text for the input. */\n placeholder?: string;\n /**\n * Token format string or `Intl.DateTimeFormat` options.\n * @defaultValue (see below)\n */\n format?: DateFormatOption;\n /**\n * Custom parser. Enter and leaving the field call it only if the user\n * changed the text, so focus passing through commits nothing and the value\n * keeps what the format leaves out, such as seconds and the date.\n */\n parse?: (s: string) => Date | null;\n /** BCP-47 locale tag for Intl formatting. */\n locale?: string;\n /** Render the spinner inline (no popover). */\n inline?: boolean;\n /** Use `<input type=\"time\">` on coarse-pointer + small-viewport devices. */\n mobileNative?: boolean | 'auto';\n /** Allow segmented keyboard typing in the input (type the time directly, auto-advancing across segments). `false` makes the field picker-only. */\n editable?: boolean;\n /** Whether the spinner popover exists. `false` makes the field input-only (segmented typing, no popover). */\n popover?: boolean;\n /**\n * Open the popover when the input is focused. Focus that a closing popover\n * hands back to the input leaves it closed. Dismissing it commits nothing:\n * an empty field stays empty, and leaving afterwards commits only what was\n * typed since. With it off, the launcher or Alt+ArrowDown opens it.\n */\n openOnFocus?: boolean;\n /** Close the popover after a time is selected (off by default). */\n closeOnSelect?: boolean;\n /** Popover anchor position relative to the input. */\n position?: PickerPosition;\n /**\n * Render the popover into `document.body` via portal. On a narrow screen\n * an in-place popover spans the bottom of the viewport, while a portaled\n * one stays on its `position` corner.\n */\n appendToBody?: boolean;\n /**\n * Bulma color modifier for the input, also carried by the wheels, where it\n * colors the selection band. A focused wheel's keyboard focus ring is drawn\n * inside the band in the color's `-invert`, like the selected value, so it\n * shows on the fill. Unset, the wheels use\n * `--bulma-timeinput-wheel-selected-bg`, which defaults to `primary`.\n */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Size variant. */\n size?: 'small' | 'medium' | 'large';\n /** Render the input with rounded corners. */\n isRounded?: boolean;\n /** Hour format. `'12'` shows an AM/PM toggle. */\n hourFormat?: HourFormat;\n /** Show a seconds column. Note: iOS Safari's native time picker UI does not include a seconds wheel; pass `mobileNative={false}` if you need one on iOS. */\n enableSeconds?: boolean;\n /** Hour step for the spinner. */\n incrementHours?: number;\n /** Minute step. Combine with `min`/`max` for slot-style pickers. */\n incrementMinutes?: number;\n /** Second step. Default `1`. */\n incrementSeconds?: number;\n /** Predicate returning `true` for times that should be skipped. Blocked times are also rejected during manual typing. */\n unselectableTimes?: (d: Date) => boolean;\n /** Decorative left icon glyph for the wrapping `Control` (shown by default). Set `''` to hide. */\n iconLeftName?: string;\n /**\n * Show a clickable launcher button on the right that toggles the popover.\n * Hidden by default while a `Control` it sits in shows its `isLoading`\n * spinner, which shares that right edge.\n * @defaultValue true\n */\n triggerIcon?: boolean;\n /** Glyph for the right launcher button. */\n triggerIconName?: string;\n /** Optional translatable string overrides. */\n labels?: PickerLabels;\n /** Play a short audible click on each wheel-item crossing. Substitute for haptic feedback on iOS Safari (which has no web haptic API as of May 2026); on Android, `navigator.vibrate(5)` fires automatically regardless. */\n audioTick?: boolean;\n /** Auto-route platform-appropriate feedback: vibrate on Android (already happening), audio thunk on iOS (where vibrate is unavailable). One switch instead of platform-sniffing on the consumer side. `audioTick={true}` always wins. */\n haptics?: boolean;\n}\n\n/**\n * Raw TimeInput — input + popover spinner without Field/Control wrapping.\n * Use `TimeInput` for the convenience wrapper.\n *\n * @function\n * @param {TimeInputBaseProps} props\n * @returns {JSX.Element}\n */\nexport const TimeInputBase = forwardRef<HTMLInputElement, TimeInputBaseProps>(\n (props, ref) => {\n const {\n value: controlledValue,\n defaultValue,\n onChange,\n onOpen,\n onClose,\n min,\n max,\n disabled,\n readOnly,\n placeholder,\n format,\n parse,\n locale,\n inline = false,\n mobileNative = 'auto',\n editable = true,\n popover = true,\n openOnFocus = true,\n closeOnSelect = false,\n position = 'bottom-left',\n appendToBody = false,\n color,\n size,\n isRounded,\n hourFormat = '24',\n enableSeconds = false,\n incrementHours = 1,\n incrementMinutes = 1,\n incrementSeconds = 1,\n unselectableTimes,\n className,\n name,\n form,\n required,\n id,\n onFocus,\n onClick,\n onKeyDown,\n onBlur,\n iconLeftName: _iconLeftName,\n triggerIcon: triggerIconProp,\n triggerIconName = 'chevron-down',\n labels,\n audioTick = false,\n haptics = false,\n ...rest\n } = props;\n // The launcher gives way to the loading spinner of a Control this sits in.\n const controlLoading = useControlLoading();\n const triggerIcon = triggerIconProp ?? !controlLoading;\n\n // Platform-appropriate feedback routing: when `haptics` is opted in and\n // the runtime has no Vibration API (notably iOS Safari), enable the\n // audio thunk so the user still gets *some* tactile cue. When vibrate\n // is available (Android Chrome etc.), the existing unconditional\n // `navigator.vibrate(5)` carries the haptic — no audio added unless\n // the consumer explicitly set `audioTick`. `audioTick` always wins.\n const hasVibrate =\n typeof navigator !== 'undefined' &&\n typeof navigator.vibrate === 'function';\n const effectiveAudioTick = audioTick || (haptics && !hasVibrate);\n const t = mergeLabels(labels);\n\n const isControlled = controlledValue !== undefined;\n const [internalValue, setInternalValue] = useState<Date | null>(\n defaultValue ?? null\n );\n const value = isControlled ? (controlledValue ?? null) : internalValue;\n\n const defaultFormat: DateFormatOption =\n format ??\n (hourFormat === '12'\n ? enableSeconds\n ? 'hh:mm:ss A'\n : DEFAULT_TIME_FORMAT_12\n : enableSeconds\n ? 'HH:mm:ss'\n : DEFAULT_TIME_FORMAT_24);\n\n // The displayed format is the source of truth for the hour cycle: an\n // explicit 12-hour `format` must drive a 12-hour wheel even when\n // `hourFormat` was left at its default. Fall back to the raw prop only when\n // the cycle can't be read from the format (an Intl-options object, or no\n // hour token).\n const effectiveHourFormat =\n hourCycleFromFormat(defaultFormat) ?? hourFormat;\n\n const [open, setOpenState] = useState(false);\n const [text, setText] = useState<string>(\n value ? formatTime(value, defaultFormat, locale) : ''\n );\n\n const inputRef = useRef<HTMLInputElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n // Snapshot of value at the moment the popover opens, used by Cancel.\n const valueAtOpenRef = useRef<Date | null>(null);\n const reactId = useId();\n const popoverId = id ? `${id}-popover` : `picker-${reactId}`;\n\n const { bulmaHelperClasses, rest: cleanRest } = useBulmaClasses(rest);\n\n const { shouldUseNative, isSmallViewport } = useNativeMobilePicker({\n force: mobileNative === 'auto' ? undefined : mobileNative,\n });\n const useNative = !inline && shouldUseNative;\n const wheelItemHeight = isSmallViewport ? 40 : 32;\n\n const inputClass = usePrefixedClassNames('input', {\n [`is-${color}`]: !!color,\n [`is-${size}`]: !!size,\n 'is-rounded': isRounded,\n });\n const containerClass = usePrefixedClassNames('timeinput-container');\n const triggerClass = usePrefixedClassNames('timeinput-trigger');\n const panelClass = usePrefixedClassNames('timeinput-panel');\n const footerClass = usePrefixedClassNames('timeinput-footer');\n const footerButton = usePrefixedClassNames('button', 'is-small');\n const footerOkClass = usePrefixedClassNames(\n 'button',\n 'is-small',\n 'timeinput-footer-ok'\n );\n const mobileFooterClass = usePrefixedClassNames('timeinput-footer-mobile');\n const mobileFooterResetClass = usePrefixedClassNames(\n 'timeinput-footer-reset'\n );\n const mobileFooterDoneClass = usePrefixedClassNames(\n 'timeinput-footer-done'\n );\n\n // What the latest request asked for, so a second request in the same\n // event sees it before React renders. The callbacks fire here rather than\n // in a state updater, which StrictMode calls twice, and after the state\n // is set, so a request a callback makes is the one that lands last.\n const requestedOpenRef = useRef(false);\n const setOpen = useCallback(\n (next: boolean) => {\n if (requestedOpenRef.current === next) return;\n requestedOpenRef.current = next;\n setOpenState(next);\n if (next) {\n valueAtOpenRef.current = value;\n onOpen?.();\n } else {\n onClose?.();\n }\n },\n [onOpen, onClose, value]\n );\n\n useEffect(() => {\n setText(value ? formatTime(value, defaultFormat, locale) : '');\n }, [value, defaultFormat, locale]);\n\n // A value's date before year 1 is out of range, as in the date pickers.\n const lowerBound = useMemo(() => floorMin(min), [min]);\n\n const commitValue = useCallback(\n (next: Date | null) => {\n if (!isControlled) setInternalValue(next);\n onChange?.(next);\n },\n [isControlled, onChange]\n );\n\n // An empty field starts from today, at the whole minute or second the\n // wheels show.\n const handleSpinnerChange = useCallback(\n (parts: { hours: number; minutes: number; seconds?: number }) => {\n const next = value\n ? setTimeOfDay(value, parts)\n : setTimeOfDay(new Date(), {\n ...parts,\n seconds: parts.seconds ?? 0,\n milliseconds: 0,\n });\n if (!isWithin(next, lowerBound, max)) return;\n commitValue(next);\n },\n [value, lowerBound, max, commitValue]\n );\n\n const tryParse = useCallback(\n (s: string): Date | null => {\n const trimmed = s.trim();\n if (!trimmed) return null;\n const fmt = typeof format === 'string' ? format : undefined;\n return parse\n ? parse(trimmed)\n : parseTime(\n trimmed,\n fmt ??\n (typeof defaultFormat === 'string'\n ? defaultFormat\n : DEFAULT_TIME_FORMAT_24)\n );\n },\n [parse, format, defaultFormat]\n );\n\n // The Date the user edits when starting without a current value. Noon so\n // the 12h / 24h hour calculations are unambiguous.\n const makeBaseDate = useCallback((): Date => {\n const d = new Date();\n d.setHours(12, 0, 0, 0);\n return d;\n }, []);\n\n const inputReadOnlyAttr = !!readOnly || !editable;\n const canOpen = !!popover && !disabled && !readOnly;\n\n const { inputHandlers } = useSegmentedEntry({\n format: defaultFormat,\n value,\n commitValue,\n formatFn: formatTime,\n tryParse,\n text,\n setText,\n makeBaseDate,\n locale,\n min: lowerBound,\n max,\n isBlocked: unselectableTimes,\n disabled,\n readOnly,\n editable,\n popover,\n openOnFocus,\n closeOnSelect,\n isOpen: open,\n setOpen,\n inputRef,\n containerRef,\n onFocus,\n onClick,\n onKeyDown,\n onBlur,\n });\n\n const combinedRef = useCallback(\n (node: HTMLInputElement | null) => {\n (inputRef as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n if (typeof ref === 'function') ref(node);\n else if (ref)\n (ref as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n },\n [ref]\n );\n\n if (useNative) {\n const nativeStep = enableSeconds\n ? incrementSeconds\n : incrementMinutes * 60;\n return (\n <input\n {...cleanRest}\n ref={combinedRef}\n type=\"time\"\n step={nativeStep}\n className={classNames(inputClass, bulmaHelperClasses, className)}\n value={value ? toIsoTime(value, enableSeconds) : ''}\n onChange={e => {\n const parsed = e.target.value ? fromIsoTime(e.target.value) : null;\n commitValue(parsed);\n }}\n min={min ? toIsoTime(min, enableSeconds) : undefined}\n max={max ? toIsoTime(max, enableSeconds) : undefined}\n disabled={disabled}\n readOnly={readOnly}\n placeholder={placeholder}\n name={name}\n form={form}\n required={required}\n id={id}\n />\n );\n }\n\n const spinnerValue = {\n hours: value?.getHours() ?? 0,\n minutes: value?.getMinutes() ?? 0,\n seconds: enableSeconds ? (value?.getSeconds() ?? 0) : undefined,\n };\n\n const panel = (\n <div className={panelClass}>\n <TimeWheels\n value={spinnerValue}\n onChange={handleSpinnerChange}\n hourFormat={effectiveHourFormat}\n enableSeconds={enableSeconds}\n incrementHours={incrementHours}\n incrementMinutes={incrementMinutes}\n incrementSeconds={incrementSeconds}\n unselectableTimes={unselectableTimes}\n color={color}\n size={size}\n disabled={disabled}\n // The popover panel takes `popoverId`, so the wheels inside it take\n // one of their own. Inline there is no panel, and the wheels keep\n // the id they released with.\n id={inline ? popoverId : `${popoverId}-time`}\n labels={labels}\n itemHeight={wheelItemHeight}\n audioTick={effectiveAudioTick}\n onCommit={() => setOpen(false)}\n />\n {/* Footer is popover-only. Desktop gets the OK / Now / Cancel triad;\n mobile drops to an iOS-style \"Reset / ✓\" pair to match the OS\n picker's footer affordances and free up vertical space on small\n screens. */}\n {!inline && !isSmallViewport && (\n <Buttons className={footerClass} hasAddons>\n <button\n type=\"button\"\n className={footerOkClass}\n onClick={() => setOpen(false)}\n >\n {t.ok}\n </button>\n <button\n type=\"button\"\n className={footerButton}\n onClick={() => {\n commitValue(\n snapTimeToIncrement(new Date(), {\n incrementHours,\n incrementMinutes,\n incrementSeconds,\n enableSeconds,\n })\n );\n setOpen(false);\n }}\n >\n {t.now}\n </button>\n <button\n type=\"button\"\n className={footerButton}\n onClick={() => {\n commitValue(valueAtOpenRef.current);\n setOpen(false);\n }}\n >\n {t.cancel}\n </button>\n </Buttons>\n )}\n {!inline && isSmallViewport && (\n <div className={mobileFooterClass}>\n <button\n type=\"button\"\n className={mobileFooterResetClass}\n onClick={() => {\n commitValue(valueAtOpenRef.current);\n setOpen(false);\n }}\n >\n {t.reset}\n </button>\n <button\n type=\"button\"\n className={mobileFooterDoneClass}\n aria-label={t.done}\n onClick={() => setOpen(false)}\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 22 22\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 11l4 4 8-8\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n )}\n </div>\n );\n\n if (inline) {\n return (\n <div\n {...cleanRest}\n ref={containerRef}\n className={classNames(containerClass, bulmaHelperClasses, className)}\n >\n {panel}\n {name && (\n <input\n type=\"hidden\"\n name={name}\n form={form}\n value={value ? toIsoTime(value, enableSeconds) : ''}\n required={required}\n />\n )}\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n className={classNames(containerClass, bulmaHelperClasses, className)}\n {...cleanRest}\n >\n <input\n ref={combinedRef}\n type=\"text\"\n role=\"combobox\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-controls={popoverId}\n autoComplete=\"off\"\n className={inputClass}\n value={text}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={inputReadOnlyAttr}\n name={name}\n form={form}\n required={required}\n id={id}\n {...inputHandlers}\n />\n {popover && triggerIcon && (\n <button\n type=\"button\"\n className={triggerClass}\n onClick={() => {\n if (canOpen) setOpen(!open);\n }}\n disabled={!canOpen}\n aria-label={t.chooseTime}\n aria-haspopup=\"dialog\"\n aria-controls={popoverId}\n aria-expanded={open}\n tabIndex={canOpen ? 0 : -1}\n >\n <Icon name={triggerIconName} size={size} />\n </button>\n )}\n {popover && (\n <PickerPopover\n isOpen={open}\n onClose={() => setOpen(false)}\n anchorRef={containerRef}\n position={position}\n appendToBody={appendToBody}\n ariaLabel={t.chooseTime}\n id={popoverId}\n restoreFocusRef={inputRef}\n >\n {panel}\n </PickerPopover>\n )}\n </div>\n );\n }\n);\n\nTimeInputBase.displayName = 'TimeInputBase';\n\nexport default TimeInputBase;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"TimeInputBase.js","sources":["../../../src/form/TimeInputBase.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport {\n PickerPosition,\n HourFormat,\n PickerLabels,\n mergeLabels,\n} from './_pickerInternals/pickerTypes';\nimport {\n formatTime,\n hourCycleFromFormat,\n parseTime,\n DateFormatOption,\n DEFAULT_TIME_FORMAT_24,\n DEFAULT_TIME_FORMAT_12,\n} from './_pickerInternals/formatters';\nimport {\n setTimeOfDay,\n floorMin,\n isWithin,\n snapTimeToIncrement,\n} from './_pickerInternals/dateUtils';\nimport { TimeWheels } from './_pickerInternals/TimeWheels';\nimport { PickerPopover } from './_pickerInternals/PickerPopover';\nimport { useNativeMobilePicker } from './_pickerInternals/useNativeMobilePicker';\nimport { useSegmentedEntry } from './_pickerInternals/useSegmentedEntry';\nimport { useControlLoading } from './controlLoading';\nimport { useFieldLabelId } from './FormContext';\nimport { Icon } from '../elements/Icon';\nimport { Buttons } from '../elements/Buttons';\n\nconst toIsoTime = (d: Date, withSeconds: boolean): string => {\n const hh = String(d.getHours()).padStart(2, '0');\n const mm = String(d.getMinutes()).padStart(2, '0');\n if (!withSeconds) return `${hh}:${mm}`;\n const ss = String(d.getSeconds()).padStart(2, '0');\n return `${hh}:${mm}:${ss}`;\n};\n\nconst fromIsoTime = (s: string): Date | null => {\n // The HTML time value may carry fractional seconds (the spec allows them\n // and some engines normalize to `:ss.sss`); accept and drop.\n const m = /^(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d{1,3})?)?$/.exec(s);\n if (!m) return null;\n const today = new Date();\n return new Date(\n today.getFullYear(),\n today.getMonth(),\n today.getDate(),\n Number(m[1]),\n Number(m[2]),\n m[3] ? Number(m[3]) : 0,\n 0\n );\n};\n\n/**\n * Props for the raw TimeInput base. Use the higher-level `TimeInput` for\n * Field/Control composition; `TimeInputBase` is the input + popover only.\n */\nexport interface TimeInputBaseProps\n extends\n Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n | 'value'\n | 'defaultValue'\n | 'onChange'\n | 'size'\n | 'color'\n | 'min'\n | 'max'\n | 'type'\n | 'popover'\n >,\n Omit<BulmaClassesProps, 'color'> {\n /** Controlled selected time (date portion is preserved). */\n value?: Date | null;\n /** Initial value for uncontrolled usage. */\n defaultValue?: Date | null;\n /** Fired when the value changes. */\n onChange?: (d: Date | null) => void;\n /** Fired when the popover opens. */\n onOpen?: () => void;\n /** Fired when the popover closes. */\n onClose?: () => void;\n /**\n * Earliest selectable time. A `min` before year 1 is raised to midnight on\n * 1 January of year 1, and a `value` dated before then is out of range, so\n * the wheels and typing change nothing on it, as in the date pickers.\n */\n min?: Date;\n /** Latest selectable time. */\n max?: Date;\n /** Disable the input. */\n disabled?: boolean;\n /** Make the input read-only. */\n readOnly?: boolean;\n /** Placeholder text for the input. */\n placeholder?: string;\n /**\n * Token format string or `Intl.DateTimeFormat` options.\n * @defaultValue (see below)\n */\n format?: DateFormatOption;\n /**\n * Custom parser. Enter and leaving the field call it only if the user\n * changed the text, so focus passing through commits nothing and the value\n * keeps what the format leaves out, such as seconds and the date.\n */\n parse?: (s: string) => Date | null;\n /** BCP-47 locale tag for Intl formatting. */\n locale?: string;\n /** Render the spinner inline (no popover). */\n inline?: boolean;\n /** Use `<input type=\"time\">` on coarse-pointer + small-viewport devices. */\n mobileNative?: boolean | 'auto';\n /** Allow segmented keyboard typing in the input (type the time directly, auto-advancing across segments). `false` makes the field picker-only. */\n editable?: boolean;\n /** Whether the spinner popover exists. `false` makes the field input-only (segmented typing, no popover). */\n popover?: boolean;\n /**\n * Open the popover when the input is focused. Focus that a closing popover\n * hands back to the input leaves it closed. Dismissing it commits nothing:\n * an empty field stays empty, and leaving afterwards commits only what was\n * typed since. With it off, the launcher or Alt+ArrowDown opens it.\n */\n openOnFocus?: boolean;\n /** Close the popover after a time is selected (off by default). */\n closeOnSelect?: boolean;\n /** Popover anchor position relative to the input. */\n position?: PickerPosition;\n /**\n * Render the popover into `document.body` via portal. On a narrow screen\n * an in-place popover spans the bottom of the viewport, while a portaled\n * one stays on its `position` corner.\n */\n appendToBody?: boolean;\n /**\n * Bulma color modifier for the input, also carried by the wheels, where it\n * colors the selection band. A focused wheel's keyboard focus ring is drawn\n * inside the band in the color's `-invert`, like the selected value, so it\n * shows on the fill. Unset, the wheels use\n * `--bulma-timeinput-wheel-selected-bg`, which defaults to `primary`.\n */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Size variant. */\n size?: 'small' | 'medium' | 'large';\n /** Render the input with rounded corners. */\n isRounded?: boolean;\n /** Hour format. `'12'` shows an AM/PM toggle. */\n hourFormat?: HourFormat;\n /** Show a seconds column. Note: iOS Safari's native time picker UI does not include a seconds wheel; pass `mobileNative={false}` if you need one on iOS. */\n enableSeconds?: boolean;\n /** Hour step for the spinner. */\n incrementHours?: number;\n /** Minute step. Combine with `min`/`max` for slot-style pickers. */\n incrementMinutes?: number;\n /** Second step. Default `1`. */\n incrementSeconds?: number;\n /** Predicate returning `true` for times that should be skipped. Blocked times are also rejected during manual typing. */\n unselectableTimes?: (d: Date) => boolean;\n /** Decorative left icon glyph for the wrapping `Control` (shown by default). Set `''` to hide. */\n iconLeftName?: string;\n /**\n * Show a clickable launcher button on the right that toggles the popover.\n * Hidden by default while a `Control` it sits in shows its `isLoading`\n * spinner, which shares that right edge.\n * @defaultValue true\n */\n triggerIcon?: boolean;\n /** Glyph for the right launcher button. */\n triggerIconName?: string;\n /** Optional translatable string overrides. */\n labels?: PickerLabels;\n /** Play a short audible click on each wheel-item crossing. Substitute for haptic feedback on iOS Safari (which has no web haptic API as of May 2026); on Android, `navigator.vibrate(5)` fires automatically regardless. */\n audioTick?: boolean;\n /** Auto-route platform-appropriate feedback: vibrate on Android (already happening), audio thunk on iOS (where vibrate is unavailable). One switch instead of platform-sniffing on the consumer side. `audioTick={true}` always wins. */\n haptics?: boolean;\n}\n\n/**\n * Raw TimeInput — input + popover spinner without Field/Control wrapping.\n * Use `TimeInput` for the convenience wrapper.\n *\n * @function\n * @param {TimeInputBaseProps} props\n * @returns {JSX.Element}\n */\nexport const TimeInputBase = forwardRef<HTMLInputElement, TimeInputBaseProps>(\n (props, ref) => {\n const {\n value: controlledValue,\n defaultValue,\n onChange,\n onOpen,\n onClose,\n min,\n max,\n disabled,\n readOnly,\n placeholder,\n format,\n parse,\n locale,\n inline = false,\n mobileNative = 'auto',\n editable = true,\n popover = true,\n openOnFocus = true,\n closeOnSelect = false,\n position = 'bottom-left',\n appendToBody = false,\n color,\n size,\n isRounded,\n hourFormat = '24',\n enableSeconds = false,\n incrementHours = 1,\n incrementMinutes = 1,\n incrementSeconds = 1,\n unselectableTimes,\n className,\n name,\n form,\n required,\n id: idProp,\n onFocus,\n onClick,\n onKeyDown,\n onBlur,\n iconLeftName: _iconLeftName,\n triggerIcon: triggerIconProp,\n triggerIconName = 'chevron-down',\n labels,\n audioTick = false,\n haptics = false,\n ...rest\n } = props;\n // Inside a labeled Field the input takes the id the label points at\n // when the caller set none, as InputBase does, and the popover's ids\n // follow it. Inline there is no input to name, so nothing takes the\n // Field's id or builds on it.\n const fieldLabelId = useFieldLabelId();\n const id = idProp ?? (inline ? undefined : fieldLabelId);\n // The launcher gives way to the loading spinner of a Control this sits in.\n const controlLoading = useControlLoading();\n const triggerIcon = triggerIconProp ?? !controlLoading;\n\n // Platform-appropriate feedback routing: when `haptics` is opted in and\n // the runtime has no Vibration API (notably iOS Safari), enable the\n // audio thunk so the user still gets *some* tactile cue. When vibrate\n // is available (Android Chrome etc.), the existing unconditional\n // `navigator.vibrate(5)` carries the haptic — no audio added unless\n // the consumer explicitly set `audioTick`. `audioTick` always wins.\n const hasVibrate =\n typeof navigator !== 'undefined' &&\n typeof navigator.vibrate === 'function';\n const effectiveAudioTick = audioTick || (haptics && !hasVibrate);\n const t = mergeLabels(labels);\n\n const isControlled = controlledValue !== undefined;\n const [internalValue, setInternalValue] = useState<Date | null>(\n defaultValue ?? null\n );\n const value = isControlled ? (controlledValue ?? null) : internalValue;\n\n const defaultFormat: DateFormatOption =\n format ??\n (hourFormat === '12'\n ? enableSeconds\n ? 'hh:mm:ss A'\n : DEFAULT_TIME_FORMAT_12\n : enableSeconds\n ? 'HH:mm:ss'\n : DEFAULT_TIME_FORMAT_24);\n\n // The displayed format is the source of truth for the hour cycle: an\n // explicit 12-hour `format` must drive a 12-hour wheel even when\n // `hourFormat` was left at its default. Fall back to the raw prop only when\n // the cycle can't be read from the format (an Intl-options object, or no\n // hour token).\n const effectiveHourFormat =\n hourCycleFromFormat(defaultFormat) ?? hourFormat;\n\n const [open, setOpenState] = useState(false);\n const [text, setText] = useState<string>(\n value ? formatTime(value, defaultFormat, locale) : ''\n );\n\n const inputRef = useRef<HTMLInputElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n // Snapshot of value at the moment the popover opens, used by Cancel.\n const valueAtOpenRef = useRef<Date | null>(null);\n const reactId = useId();\n const popoverId = id ? `${id}-popover` : `picker-${reactId}`;\n\n const { bulmaHelperClasses, rest: cleanRest } = useBulmaClasses(rest);\n\n const { shouldUseNative, isSmallViewport } = useNativeMobilePicker({\n force: mobileNative === 'auto' ? undefined : mobileNative,\n });\n const useNative = !inline && shouldUseNative;\n const wheelItemHeight = isSmallViewport ? 40 : 32;\n\n const inputClass = usePrefixedClassNames('input', {\n [`is-${color}`]: !!color,\n [`is-${size}`]: !!size,\n 'is-rounded': isRounded,\n });\n const containerClass = usePrefixedClassNames('timeinput-container');\n const triggerClass = usePrefixedClassNames('timeinput-trigger');\n const panelClass = usePrefixedClassNames('timeinput-panel');\n const footerClass = usePrefixedClassNames('timeinput-footer');\n const footerButton = usePrefixedClassNames('button', 'is-small');\n const footerOkClass = usePrefixedClassNames(\n 'button',\n 'is-small',\n 'timeinput-footer-ok'\n );\n const mobileFooterClass = usePrefixedClassNames('timeinput-footer-mobile');\n const mobileFooterResetClass = usePrefixedClassNames(\n 'timeinput-footer-reset'\n );\n const mobileFooterDoneClass = usePrefixedClassNames(\n 'timeinput-footer-done'\n );\n\n // What the latest request asked for, so a second request in the same\n // event sees it before React renders. The callbacks fire here rather than\n // in a state updater, which StrictMode calls twice, and after the state\n // is set, so a request a callback makes is the one that lands last.\n const requestedOpenRef = useRef(false);\n const setOpen = useCallback(\n (next: boolean) => {\n if (requestedOpenRef.current === next) return;\n requestedOpenRef.current = next;\n setOpenState(next);\n if (next) {\n valueAtOpenRef.current = value;\n onOpen?.();\n } else {\n onClose?.();\n }\n },\n [onOpen, onClose, value]\n );\n\n useEffect(() => {\n setText(value ? formatTime(value, defaultFormat, locale) : '');\n }, [value, defaultFormat, locale]);\n\n // A value's date before year 1 is out of range, as in the date pickers.\n const lowerBound = useMemo(() => floorMin(min), [min]);\n\n const commitValue = useCallback(\n (next: Date | null) => {\n if (!isControlled) setInternalValue(next);\n onChange?.(next);\n },\n [isControlled, onChange]\n );\n\n // An empty field starts from today, at the whole minute or second the\n // wheels show.\n const handleSpinnerChange = useCallback(\n (parts: { hours: number; minutes: number; seconds?: number }) => {\n const next = value\n ? setTimeOfDay(value, parts)\n : setTimeOfDay(new Date(), {\n ...parts,\n seconds: parts.seconds ?? 0,\n milliseconds: 0,\n });\n if (!isWithin(next, lowerBound, max)) return;\n commitValue(next);\n },\n [value, lowerBound, max, commitValue]\n );\n\n const tryParse = useCallback(\n (s: string): Date | null => {\n const trimmed = s.trim();\n if (!trimmed) return null;\n const fmt = typeof format === 'string' ? format : undefined;\n return parse\n ? parse(trimmed)\n : parseTime(\n trimmed,\n fmt ??\n (typeof defaultFormat === 'string'\n ? defaultFormat\n : DEFAULT_TIME_FORMAT_24)\n );\n },\n [parse, format, defaultFormat]\n );\n\n // The Date the user edits when starting without a current value. Noon so\n // the 12h / 24h hour calculations are unambiguous.\n const makeBaseDate = useCallback((): Date => {\n const d = new Date();\n d.setHours(12, 0, 0, 0);\n return d;\n }, []);\n\n const inputReadOnlyAttr = !!readOnly || !editable;\n const canOpen = !!popover && !disabled && !readOnly;\n\n const { inputHandlers } = useSegmentedEntry({\n format: defaultFormat,\n value,\n commitValue,\n formatFn: formatTime,\n tryParse,\n text,\n setText,\n makeBaseDate,\n locale,\n min: lowerBound,\n max,\n isBlocked: unselectableTimes,\n disabled,\n readOnly,\n editable,\n popover,\n openOnFocus,\n closeOnSelect,\n isOpen: open,\n setOpen,\n inputRef,\n containerRef,\n onFocus,\n onClick,\n onKeyDown,\n onBlur,\n });\n\n const combinedRef = useCallback(\n (node: HTMLInputElement | null) => {\n (inputRef as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n if (typeof ref === 'function') ref(node);\n else if (ref)\n (ref as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n },\n [ref]\n );\n\n if (useNative) {\n const nativeStep = enableSeconds\n ? incrementSeconds\n : incrementMinutes * 60;\n return (\n <input\n {...cleanRest}\n ref={combinedRef}\n type=\"time\"\n step={nativeStep}\n className={classNames(inputClass, bulmaHelperClasses, className)}\n value={value ? toIsoTime(value, enableSeconds) : ''}\n onChange={e => {\n const parsed = e.target.value ? fromIsoTime(e.target.value) : null;\n commitValue(parsed);\n }}\n min={min ? toIsoTime(min, enableSeconds) : undefined}\n max={max ? toIsoTime(max, enableSeconds) : undefined}\n disabled={disabled}\n readOnly={readOnly}\n placeholder={placeholder}\n name={name}\n form={form}\n required={required}\n id={id}\n />\n );\n }\n\n const spinnerValue = {\n hours: value?.getHours() ?? 0,\n minutes: value?.getMinutes() ?? 0,\n seconds: enableSeconds ? (value?.getSeconds() ?? 0) : undefined,\n };\n\n const panel = (\n <div className={panelClass}>\n <TimeWheels\n value={spinnerValue}\n onChange={handleSpinnerChange}\n hourFormat={effectiveHourFormat}\n enableSeconds={enableSeconds}\n incrementHours={incrementHours}\n incrementMinutes={incrementMinutes}\n incrementSeconds={incrementSeconds}\n unselectableTimes={unselectableTimes}\n color={color}\n size={size}\n disabled={disabled}\n // The popover panel takes `popoverId`, so the wheels inside it take\n // one of their own. Inline there is no panel, and the wheels keep\n // the id they released with.\n id={inline ? popoverId : `${popoverId}-time`}\n labels={labels}\n itemHeight={wheelItemHeight}\n audioTick={effectiveAudioTick}\n onCommit={() => setOpen(false)}\n />\n {/* Footer is popover-only. Desktop gets the OK / Now / Cancel triad;\n mobile drops to an iOS-style \"Reset / ✓\" pair to match the OS\n picker's footer affordances and free up vertical space on small\n screens. */}\n {!inline && !isSmallViewport && (\n <Buttons className={footerClass} hasAddons>\n <button\n type=\"button\"\n className={footerOkClass}\n onClick={() => setOpen(false)}\n >\n {t.ok}\n </button>\n <button\n type=\"button\"\n className={footerButton}\n onClick={() => {\n commitValue(\n snapTimeToIncrement(new Date(), {\n incrementHours,\n incrementMinutes,\n incrementSeconds,\n enableSeconds,\n })\n );\n setOpen(false);\n }}\n >\n {t.now}\n </button>\n <button\n type=\"button\"\n className={footerButton}\n onClick={() => {\n commitValue(valueAtOpenRef.current);\n setOpen(false);\n }}\n >\n {t.cancel}\n </button>\n </Buttons>\n )}\n {!inline && isSmallViewport && (\n <div className={mobileFooterClass}>\n <button\n type=\"button\"\n className={mobileFooterResetClass}\n onClick={() => {\n commitValue(valueAtOpenRef.current);\n setOpen(false);\n }}\n >\n {t.reset}\n </button>\n <button\n type=\"button\"\n className={mobileFooterDoneClass}\n aria-label={t.done}\n onClick={() => setOpen(false)}\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 22 22\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 11l4 4 8-8\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n )}\n </div>\n );\n\n if (inline) {\n return (\n <div\n {...cleanRest}\n ref={containerRef}\n className={classNames(containerClass, bulmaHelperClasses, className)}\n >\n {panel}\n {name && (\n <input\n type=\"hidden\"\n name={name}\n form={form}\n value={value ? toIsoTime(value, enableSeconds) : ''}\n required={required}\n />\n )}\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n className={classNames(containerClass, bulmaHelperClasses, className)}\n {...cleanRest}\n >\n <input\n ref={combinedRef}\n type=\"text\"\n role=\"combobox\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-controls={popoverId}\n autoComplete=\"off\"\n className={inputClass}\n value={text}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={inputReadOnlyAttr}\n name={name}\n form={form}\n required={required}\n id={id}\n {...inputHandlers}\n />\n {popover && triggerIcon && (\n <button\n type=\"button\"\n className={triggerClass}\n onClick={() => {\n if (canOpen) setOpen(!open);\n }}\n disabled={!canOpen}\n aria-label={t.chooseTime}\n aria-haspopup=\"dialog\"\n aria-controls={popoverId}\n aria-expanded={open}\n tabIndex={canOpen ? 0 : -1}\n >\n <Icon name={triggerIconName} size={size} />\n </button>\n )}\n {popover && (\n <PickerPopover\n isOpen={open}\n onClose={() => setOpen(false)}\n anchorRef={containerRef}\n position={position}\n appendToBody={appendToBody}\n ariaLabel={t.chooseTime}\n id={popoverId}\n restoreFocusRef={inputRef}\n >\n {panel}\n </PickerPopover>\n )}\n </div>\n );\n }\n);\n\nTimeInputBase.displayName = 'TimeInputBase';\n\nexport default TimeInputBase;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
@@ -10,10 +10,11 @@ import { useFieldLabelElementId, useFieldLabelId, useFieldLabelFor } from './For
10
10
  * generation entirely: the user has taken over the association (#495 presence
11
11
  * semantics). When the control renders no label of its own, it adopts the id
12
12
  * a labeled Field around it offers, the way the bases do, so that Field's
13
- * label names it (#939); a user `id` still wins there.
13
+ * label names it (#939); a user `id` still wins there. With `needsLabelId`
14
+ * it also returns the id of whichever label names the control (#981).
14
15
  * Internal; not part of the public API.
15
16
  */
16
- function useAutoLabelId({ label, id, labelProps, rendersLabel, hasInput = true, }) {
17
+ function useAutoLabelId({ label, id, labelProps, rendersLabel, hasInput = true, needsLabelId = false, }) {
17
18
  // Called unconditionally per the rules of hooks; SSR-safe on React 18 and 19.
18
19
  const generatedId = useId();
19
20
  // Read outside the control's own Field, so it is set only when an outer
@@ -21,6 +22,8 @@ function useAutoLabelId({ label, id, labelProps, rendersLabel, hasInput = true,
21
22
  const fieldLabelId = useFieldLabelId();
22
23
  // What an outer Field's label points at, even when wired by hand.
23
24
  const fieldLabelFor = useFieldLabelFor();
25
+ // That Field's label element, set under the same conditions.
26
+ const fieldLabelElementId = useFieldLabelElementId();
24
27
  // Truthiness mirrors Field's own `if (label)` render gate.
25
28
  const active = !!label && rendersLabel;
26
29
  // Presence, not truthiness: `htmlFor: undefined` is an explicit opt-out and
@@ -29,21 +32,30 @@ function useAutoLabelId({ label, id, labelProps, rendersLabel, hasInput = true,
29
32
  const adopted = !active && hasInput ? fieldLabelId : undefined;
30
33
  const controlId = id ?? (active && !userWired ? generatedId : adopted);
31
34
  const ownLabelProps = { htmlFor: controlId, ...labelProps };
35
+ const labelTarget = active ? ownLabelProps.htmlFor : fieldLabelFor;
36
+ const labelled = !!controlId && labelTarget === controlId;
37
+ // Only a label that names the control gets an id to point at, with the
38
+ // suffix Field gives its own, from an id that is already unique.
39
+ const ownLabelId = needsLabelId && active && labelled
40
+ ? (labelProps?.id ?? `${generatedId}-label`)
41
+ : undefined;
32
42
  // Inactive with a label still means an own Field may render it (pickers'
33
43
  // inline mode, Taginput at maxTags) — the explicit `htmlFor: undefined`
34
44
  // tells Field the association is owned here, so it must not generate one
35
45
  // that would dangle (#495 presence semantics).
36
46
  const fieldLabelProps = active
37
- ? ownLabelProps
47
+ ? ownLabelId
48
+ ? { ...ownLabelProps, id: ownLabelId }
49
+ : ownLabelProps
38
50
  : label
39
51
  ? { htmlFor: undefined, ...labelProps }
40
52
  : labelProps;
41
- const labelTarget = active ? ownLabelProps.htmlFor : fieldLabelFor;
42
- return {
43
- controlId,
44
- fieldLabelProps,
45
- labelled: !!controlId && labelTarget === controlId,
46
- };
53
+ const labelId = needsLabelId && labelled
54
+ ? active
55
+ ? ownLabelId
56
+ : fieldLabelElementId
57
+ : undefined;
58
+ return { controlId, fieldLabelProps, labelled, labelId };
47
59
  }
48
60
  /**
49
61
  * Group-input counterpart of {@link useAutoLabelId} (#494): a group of
@@ -1 +1 @@
1
- {"version":3,"file":"useAutoLabelId.js","sources":["../../../src/form/useAutoLabelId.ts"],"sourcesContent":["import React, { useId } from 'react';\nimport type { FieldProps } from './Field';\nimport {\n useFieldLabelElementId,\n useFieldLabelFor,\n useFieldLabelId,\n} from './FormContext';\n\ninterface UseAutoLabelIdOptions {\n /** The convenience `label` prop as passed by the caller. */\n label: React.ReactNode;\n /** User-supplied id for the control, if any. */\n id?: string;\n /** User-supplied labelProps, if any. */\n labelProps?: FieldProps['labelProps'];\n /**\n * True when this render actually outputs the label wired to a control —\n * false inside an outer Field (label is dropped), in variants that render\n * no Field, and in modes with no labellable control (e.g. inline pickers).\n */\n rendersLabel: boolean;\n /**\n * False when this render has no input to label at all (an inline picker),\n * so it takes no id from a surrounding Field either. Defaults to true.\n */\n hasInput?: boolean;\n}\n\n/**\n * Associates the convenience `label` prop with its control (#368): generates\n * an id for the control and returns labelProps carrying a matching `htmlFor`.\n * A user-supplied `id` is used as the target instead of the generated one, and\n * an explicit `htmlFor` key in labelProps — even set to `undefined` — disables\n * generation entirely: the user has taken over the association (#495 presence\n * semantics). When the control renders no label of its own, it adopts the id\n * a labeled Field around it offers, the way the bases do, so that Field's\n * label names it (#939); a user `id` still wins there.\n * Internal; not part of the public API.\n */\nexport function useAutoLabelId({\n label,\n id,\n labelProps,\n rendersLabel,\n hasInput = true,\n}: UseAutoLabelIdOptions): {\n controlId: string | undefined;\n fieldLabelProps: FieldProps['labelProps'] | undefined;\n /** Whether a rendered label, its own or a surrounding Field's, points at `controlId`. */\n labelled: boolean;\n} {\n // Called unconditionally per the rules of hooks; SSR-safe on React 18 and 19.\n const generatedId = useId();\n // Read outside the control's own Field, so it is set only when an outer\n // Field holds the control, which then renders no label of its own.\n const fieldLabelId = useFieldLabelId();\n // What an outer Field's label points at, even when wired by hand.\n const fieldLabelFor = useFieldLabelFor();\n // Truthiness mirrors Field's own `if (label)` render gate.\n const active = !!label && rendersLabel;\n // Presence, not truthiness: `htmlFor: undefined` is an explicit opt-out and\n // must not leave an orphan generated id on the control.\n const userWired = !!labelProps && 'htmlFor' in labelProps;\n const adopted = !active && hasInput ? fieldLabelId : undefined;\n const controlId = id ?? (active && !userWired ? generatedId : adopted);\n const ownLabelProps = { htmlFor: controlId, ...labelProps };\n // Inactive with a label still means an own Field may render it (pickers'\n // inline mode, Taginput at maxTags) — the explicit `htmlFor: undefined`\n // tells Field the association is owned here, so it must not generate one\n // that would dangle (#495 presence semantics).\n const fieldLabelProps = active\n ? ownLabelProps\n : label\n ? { htmlFor: undefined, ...labelProps }\n : labelProps;\n const labelTarget = active ? ownLabelProps.htmlFor : fieldLabelFor;\n return {\n controlId,\n fieldLabelProps,\n labelled: !!controlId && labelTarget === controlId,\n };\n}\n\ninterface UseAutoLabelledByOptions {\n /** The convenience `label` prop as passed by the caller. */\n label: React.ReactNode;\n /** User-supplied labelProps, if any. */\n labelProps?: FieldProps['labelProps'];\n /** True when this render actually outputs the label naming the group. */\n rendersLabel: boolean;\n /**\n * The caller's remaining props. A non-empty `aria-label` among them names\n * the group, and so does any `aria-labelledby` key, even an undefined one,\n * since the group spreads them after its own attribute. Either keeps every\n * label off the group, its own and a surrounding Field's alike.\n */\n callerProps: object;\n}\n\n/**\n * Group-input counterpart of {@link useAutoLabelId} (#494): a group of\n * controls cannot take a single `htmlFor`, so instead the rendered `<label>`\n * gets a generated id and the group container points at it with\n * `aria-labelledby`. A user-supplied `labelProps.id` is used as the target\n * instead of generating one. Any caller `htmlFor` is stripped — a group label\n * names the group, never a single control — so the merged labelProps always\n * carry an explicit `htmlFor: undefined`. When the group renders no label of\n * its own, it points at the label of a labeled Field around it instead\n * (#939). A caller who named the group with `aria-label` or\n * `aria-labelledby` gets no `aria-labelledby` from either label, so their\n * name wins wherever the label sits.\n * Internal; not part of the public API.\n */\nexport function useAutoLabelledBy({\n label,\n labelProps,\n rendersLabel,\n callerProps,\n}: UseAutoLabelledByOptions): {\n ariaLabelledBy: string | undefined;\n fieldLabelProps: FieldProps['labelProps'] | undefined;\n} {\n // Called unconditionally per the rules of hooks; SSR-safe on React 18 and 19.\n const generatedId = useId();\n // Set only when an outer Field holds the group (see useAutoLabelId).\n const fieldLabelElementId = useFieldLabelElementId();\n const active = !!label && rendersLabel;\n const labelId = labelProps?.id ?? (active ? generatedId : undefined);\n const fieldLabelProps = active\n ? { ...labelProps, id: labelId, htmlFor: undefined }\n : labelProps;\n const aria = callerProps as React.AriaAttributes;\n // Presence for aria-labelledby: the caller's key replaces the attribute\n // through the spread whatever its value, and pointing it at a label would\n // only take a Rate's fallback name away. Checked before either label, so\n // the caller's name wins over the group's own `label` as it does over a\n // Field's, the way an aria-label beats a `<label for>` on a single input.\n const callerNamed = !!aria['aria-label'] || 'aria-labelledby' in aria;\n const ariaLabelledBy = callerNamed\n ? undefined\n : active\n ? labelId\n : fieldLabelElementId;\n return { ariaLabelledBy, fieldLabelProps };\n}\n"],"names":[],"mappings":";;;;AA4BA;;;;;;;;;;AAUG;AACG,SAAU,cAAc,CAAC,EAC7B,KAAK,EACL,EAAE,EACF,UAAU,EACV,YAAY,EACZ,QAAQ,GAAG,IAAI,GACO,EAAA;;AAOtB,IAAA,MAAM,WAAW,GAAG,KAAK,EAAE;;;AAG3B,IAAA,MAAM,YAAY,GAAG,eAAe,EAAE;;AAEtC,IAAA,MAAM,aAAa,GAAG,gBAAgB,EAAE;;AAExC,IAAA,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,YAAY;;;IAGtC,MAAM,SAAS,GAAG,CAAC,CAAC,UAAU,IAAI,SAAS,IAAI,UAAU;AACzD,IAAA,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,QAAQ,GAAG,YAAY,GAAG,SAAS;AAC9D,IAAA,MAAM,SAAS,GAAG,EAAE,KAAK,MAAM,IAAI,CAAC,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;IACtE,MAAM,aAAa,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE;;;;;IAK3D,MAAM,eAAe,GAAG;AACtB,UAAE;AACF,UAAE;cACE,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,UAAU;cACnC,UAAU;AAChB,IAAA,MAAM,WAAW,GAAG,MAAM,GAAG,aAAa,CAAC,OAAO,GAAG,aAAa;IAClE,OAAO;QACL,SAAS;QACT,eAAe;AACf,QAAA,QAAQ,EAAE,CAAC,CAAC,SAAS,IAAI,WAAW,KAAK,SAAS;KACnD;AACH;AAkBA;;;;;;;;;;;;;AAaG;AACG,SAAU,iBAAiB,CAAC,EAChC,KAAK,EACL,UAAU,EACV,YAAY,EACZ,WAAW,GACc,EAAA;;AAKzB,IAAA,MAAM,WAAW,GAAG,KAAK,EAAE;;AAE3B,IAAA,MAAM,mBAAmB,GAAG,sBAAsB,EAAE;AACpD,IAAA,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,YAAY;AACtC,IAAA,MAAM,OAAO,GAAG,UAAU,EAAE,EAAE,KAAK,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;IACpE,MAAM,eAAe,GAAG;AACtB,UAAE,EAAE,GAAG,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS;UAChD,UAAU;IACd,MAAM,IAAI,GAAG,WAAmC;;;;;;AAMhD,IAAA,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,iBAAiB,IAAI,IAAI;IACrE,MAAM,cAAc,GAAG;AACrB,UAAE;AACF,UAAE;AACA,cAAE;cACA,mBAAmB;AACzB,IAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE;AAC5C;;"}
1
+ {"version":3,"file":"useAutoLabelId.js","sources":["../../../src/form/useAutoLabelId.ts"],"sourcesContent":["import React, { useId } from 'react';\nimport type { FieldProps } from './Field';\nimport {\n useFieldLabelElementId,\n useFieldLabelFor,\n useFieldLabelId,\n} from './FormContext';\n\ninterface UseAutoLabelIdOptions {\n /** The convenience `label` prop as passed by the caller. */\n label: React.ReactNode;\n /** User-supplied id for the control, if any. */\n id?: string;\n /** User-supplied labelProps, if any. */\n labelProps?: FieldProps['labelProps'];\n /**\n * True when this render actually outputs the label wired to a control —\n * false inside an outer Field (label is dropped), in variants that render\n * no Field, and in modes with no labellable control (e.g. inline pickers).\n */\n rendersLabel: boolean;\n /**\n * False when this render has no input to label at all (an inline picker),\n * so it takes no id from a surrounding Field either. Defaults to true.\n */\n hasInput?: boolean;\n /**\n * True when the control also points `aria-labelledby` at the label, as a\n * range Slider's thumbs do (#981), so it needs the label's own id. Its own\n * label then gets one (`labelProps.id` when given, otherwise a generated\n * one), and the hook returns it, or a surrounding Field's, as `labelId`.\n */\n needsLabelId?: boolean;\n}\n\n/**\n * Associates the convenience `label` prop with its control (#368): generates\n * an id for the control and returns labelProps carrying a matching `htmlFor`.\n * A user-supplied `id` is used as the target instead of the generated one, and\n * an explicit `htmlFor` key in labelProps — even set to `undefined` — disables\n * generation entirely: the user has taken over the association (#495 presence\n * semantics). When the control renders no label of its own, it adopts the id\n * a labeled Field around it offers, the way the bases do, so that Field's\n * label names it (#939); a user `id` still wins there. With `needsLabelId`\n * it also returns the id of whichever label names the control (#981).\n * Internal; not part of the public API.\n */\nexport function useAutoLabelId({\n label,\n id,\n labelProps,\n rendersLabel,\n hasInput = true,\n needsLabelId = false,\n}: UseAutoLabelIdOptions): {\n controlId: string | undefined;\n fieldLabelProps: FieldProps['labelProps'] | undefined;\n /** Whether a rendered label, its own or a surrounding Field's, points at `controlId`. */\n labelled: boolean;\n /**\n * With `needsLabelId`, the id of the label that names `controlId`, its own\n * or a surrounding Field's. Undefined when no label names it, or when the\n * Field's label was wired by hand, since that Field hands out no label id.\n */\n labelId: string | undefined;\n} {\n // Called unconditionally per the rules of hooks; SSR-safe on React 18 and 19.\n const generatedId = useId();\n // Read outside the control's own Field, so it is set only when an outer\n // Field holds the control, which then renders no label of its own.\n const fieldLabelId = useFieldLabelId();\n // What an outer Field's label points at, even when wired by hand.\n const fieldLabelFor = useFieldLabelFor();\n // That Field's label element, set under the same conditions.\n const fieldLabelElementId = useFieldLabelElementId();\n // Truthiness mirrors Field's own `if (label)` render gate.\n const active = !!label && rendersLabel;\n // Presence, not truthiness: `htmlFor: undefined` is an explicit opt-out and\n // must not leave an orphan generated id on the control.\n const userWired = !!labelProps && 'htmlFor' in labelProps;\n const adopted = !active && hasInput ? fieldLabelId : undefined;\n const controlId = id ?? (active && !userWired ? generatedId : adopted);\n const ownLabelProps = { htmlFor: controlId, ...labelProps };\n const labelTarget = active ? ownLabelProps.htmlFor : fieldLabelFor;\n const labelled = !!controlId && labelTarget === controlId;\n // Only a label that names the control gets an id to point at, with the\n // suffix Field gives its own, from an id that is already unique.\n const ownLabelId =\n needsLabelId && active && labelled\n ? (labelProps?.id ?? `${generatedId}-label`)\n : undefined;\n // Inactive with a label still means an own Field may render it (pickers'\n // inline mode, Taginput at maxTags) — the explicit `htmlFor: undefined`\n // tells Field the association is owned here, so it must not generate one\n // that would dangle (#495 presence semantics).\n const fieldLabelProps = active\n ? ownLabelId\n ? { ...ownLabelProps, id: ownLabelId }\n : ownLabelProps\n : label\n ? { htmlFor: undefined, ...labelProps }\n : labelProps;\n const labelId =\n needsLabelId && labelled\n ? active\n ? ownLabelId\n : fieldLabelElementId\n : undefined;\n return { controlId, fieldLabelProps, labelled, labelId };\n}\n\ninterface UseAutoLabelledByOptions {\n /** The convenience `label` prop as passed by the caller. */\n label: React.ReactNode;\n /** User-supplied labelProps, if any. */\n labelProps?: FieldProps['labelProps'];\n /** True when this render actually outputs the label naming the group. */\n rendersLabel: boolean;\n /**\n * The caller's remaining props. A non-empty `aria-label` among them names\n * the group, and so does any `aria-labelledby` key, even an undefined one,\n * since the group spreads them after its own attribute. Either keeps every\n * label off the group, its own and a surrounding Field's alike.\n */\n callerProps: object;\n}\n\n/**\n * Group-input counterpart of {@link useAutoLabelId} (#494): a group of\n * controls cannot take a single `htmlFor`, so instead the rendered `<label>`\n * gets a generated id and the group container points at it with\n * `aria-labelledby`. A user-supplied `labelProps.id` is used as the target\n * instead of generating one. Any caller `htmlFor` is stripped — a group label\n * names the group, never a single control — so the merged labelProps always\n * carry an explicit `htmlFor: undefined`. When the group renders no label of\n * its own, it points at the label of a labeled Field around it instead\n * (#939). A caller who named the group with `aria-label` or\n * `aria-labelledby` gets no `aria-labelledby` from either label, so their\n * name wins wherever the label sits.\n * Internal; not part of the public API.\n */\nexport function useAutoLabelledBy({\n label,\n labelProps,\n rendersLabel,\n callerProps,\n}: UseAutoLabelledByOptions): {\n ariaLabelledBy: string | undefined;\n fieldLabelProps: FieldProps['labelProps'] | undefined;\n} {\n // Called unconditionally per the rules of hooks; SSR-safe on React 18 and 19.\n const generatedId = useId();\n // Set only when an outer Field holds the group (see useAutoLabelId).\n const fieldLabelElementId = useFieldLabelElementId();\n const active = !!label && rendersLabel;\n const labelId = labelProps?.id ?? (active ? generatedId : undefined);\n const fieldLabelProps = active\n ? { ...labelProps, id: labelId, htmlFor: undefined }\n : labelProps;\n const aria = callerProps as React.AriaAttributes;\n // Presence for aria-labelledby: the caller's key replaces the attribute\n // through the spread whatever its value, and pointing it at a label would\n // only take a Rate's fallback name away. Checked before either label, so\n // the caller's name wins over the group's own `label` as it does over a\n // Field's, the way an aria-label beats a `<label for>` on a single input.\n const callerNamed = !!aria['aria-label'] || 'aria-labelledby' in aria;\n const ariaLabelledBy = callerNamed\n ? undefined\n : active\n ? labelId\n : fieldLabelElementId;\n return { ariaLabelledBy, fieldLabelProps };\n}\n"],"names":[],"mappings":";;;;AAmCA;;;;;;;;;;;AAWG;SACa,cAAc,CAAC,EAC7B,KAAK,EACL,EAAE,EACF,UAAU,EACV,YAAY,EACZ,QAAQ,GAAG,IAAI,EACf,YAAY,GAAG,KAAK,GACE,EAAA;;AAatB,IAAA,MAAM,WAAW,GAAG,KAAK,EAAE;;;AAG3B,IAAA,MAAM,YAAY,GAAG,eAAe,EAAE;;AAEtC,IAAA,MAAM,aAAa,GAAG,gBAAgB,EAAE;;AAExC,IAAA,MAAM,mBAAmB,GAAG,sBAAsB,EAAE;;AAEpD,IAAA,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,YAAY;;;IAGtC,MAAM,SAAS,GAAG,CAAC,CAAC,UAAU,IAAI,SAAS,IAAI,UAAU;AACzD,IAAA,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,QAAQ,GAAG,YAAY,GAAG,SAAS;AAC9D,IAAA,MAAM,SAAS,GAAG,EAAE,KAAK,MAAM,IAAI,CAAC,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;IACtE,MAAM,aAAa,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE;AAC3D,IAAA,MAAM,WAAW,GAAG,MAAM,GAAG,aAAa,CAAC,OAAO,GAAG,aAAa;IAClE,MAAM,QAAQ,GAAG,CAAC,CAAC,SAAS,IAAI,WAAW,KAAK,SAAS;;;AAGzD,IAAA,MAAM,UAAU,GACd,YAAY,IAAI,MAAM,IAAI;WACrB,UAAU,EAAE,EAAE,IAAI,CAAA,EAAG,WAAW,CAAA,MAAA,CAAQ;UACzC,SAAS;;;;;IAKf,MAAM,eAAe,GAAG;AACtB,UAAE;cACE,EAAE,GAAG,aAAa,EAAE,EAAE,EAAE,UAAU;AACpC,cAAE;AACJ,UAAE;cACE,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,UAAU;cACnC,UAAU;AAChB,IAAA,MAAM,OAAO,GACX,YAAY,IAAI;AACd,UAAE;AACA,cAAE;AACF,cAAE;UACF,SAAS;IACf,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAE;AAC1D;AAkBA;;;;;;;;;;;;;AAaG;AACG,SAAU,iBAAiB,CAAC,EAChC,KAAK,EACL,UAAU,EACV,YAAY,EACZ,WAAW,GACc,EAAA;;AAKzB,IAAA,MAAM,WAAW,GAAG,KAAK,EAAE;;AAE3B,IAAA,MAAM,mBAAmB,GAAG,sBAAsB,EAAE;AACpD,IAAA,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,YAAY;AACtC,IAAA,MAAM,OAAO,GAAG,UAAU,EAAE,EAAE,KAAK,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;IACpE,MAAM,eAAe,GAAG;AACtB,UAAE,EAAE,GAAG,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS;UAChD,UAAU;IACd,MAAM,IAAI,GAAG,WAAmC;;;;;;AAMhD,IAAA,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,iBAAiB,IAAI,IAAI;IACrE,MAAM,cAAc,GAAG;AACrB,UAAE;AACF,UAAE;AACA,cAAE;cACA,mBAAmB;AACzB,IAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE;AAC5C;;"}
package/dist/index.cjs CHANGED
@@ -9068,9 +9068,10 @@ const FieldLabelIdContext = React.createContext(undefined);
9068
9068
  * The id a labeled Field wants its single composed control to adopt (#495).
9069
9069
  * `undefined` outside a Field, in unlabeled/grouped/addons Fields, or when the
9070
9070
  * user took over the association with an explicit `labelProps.htmlFor`.
9071
- * Consumed by the single-control bases (InputBase, SelectBase, TextAreaBase)
9072
- * and, through `useAutoLabelId`, by the convenience inputs that render an
9073
- * input of their own (#939). Internal; not part of the public API.
9071
+ * Consumed by the single-control bases (InputBase, SelectBase, TextAreaBase,
9072
+ * and the date and time picker bases unless inline, #968) and, through
9073
+ * `useAutoLabelId`, by the convenience inputs that render an input of their
9074
+ * own (#939). Internal; not part of the public API.
9074
9075
  */
9075
9076
  const useFieldLabelId = () => React.useContext(FieldLabelIdContext);
9076
9077
  /** Provider for the Field label-target id — used internally by Field. */
@@ -9079,8 +9080,10 @@ const FieldLabelElementIdContext = React.createContext(undefined);
9079
9080
  /**
9080
9081
  * The id of a labeled Field's own `<label>`, for a group control (Radios,
9081
9082
  * Checkboxes, Rate, DateRangeInput) to point `aria-labelledby` at, since a group cannot take
9082
- * the label's `htmlFor` (#939). Set under the same conditions as
9083
- * {@link useFieldLabelId}. Consumed through `useAutoLabelledBy`.
9083
+ * the label's `htmlFor` (#939), and for a range Slider's thumbs, which each
9084
+ * need the label in a name of their own (#981). Set under the same conditions
9085
+ * as {@link useFieldLabelId}. Consumed through `useAutoLabelledBy` and
9086
+ * `useAutoLabelId`.
9084
9087
  * Internal; not part of the public API.
9085
9088
  */
9086
9089
  const useFieldLabelElementId = () => React.useContext(FieldLabelElementIdContext);
@@ -9296,14 +9299,21 @@ const Control = React.forwardRef(({ as = 'div', hasIconsLeft, hasIconsRight, isL
9296
9299
  Control.displayName = 'Control';
9297
9300
 
9298
9301
  /**
9299
- * FieldLabel component for rendering a Bulma field label.
9302
+ * FieldLabel component for rendering a Bulma field label. It renders the
9303
+ * label column of a horizontal `Field` (a `div` with the `field-label` class),
9304
+ * not a `<label>`, so text placed straight in it names nothing. Put a `<label>`
9305
+ * with the `label` class inside it and point its `htmlFor` at the control's
9306
+ * `id`, or give the horizontal `Field` a `label` prop, which renders this
9307
+ * column and its `<label>` for you.
9300
9308
  *
9301
9309
  * @function
9302
9310
  * @param {FieldLabelProps} props - Props for the FieldLabel component.
9303
9311
  * @returns {JSX.Element} The rendered field label.
9304
9312
  *
9305
9313
  * @example
9306
- * <FieldLabel size="normal">Name</FieldLabel>
9314
+ * <FieldLabel size="normal">
9315
+ * <label className="label" htmlFor="name">Name</label>
9316
+ * </FieldLabel>
9307
9317
  */
9308
9318
  const FieldLabel = ({ size, textColor, bgColor, className, children, ...props }) => {
9309
9319
  const { bulmaHelperClasses, rest } = useBulmaClasses({
@@ -9388,8 +9398,8 @@ const FieldComponent = ({ horizontal, grouped, hasAddons, narrow, label, labelSi
9388
9398
  const effectiveLabelSize = labelSize ?? (horizontal ? 'normal' : undefined);
9389
9399
  const labelClass = usePrefixedClassNames('label');
9390
9400
  // Auto-associate the label with a single composed base control (#495): the
9391
- // label points at a generated id shared via context, which InputBase/
9392
- // SelectBase/TextAreaBase adopt when the user supplied no id of their own.
9401
+ // label points at a generated id shared via context, which a composed base
9402
+ // adopts when the user supplied no id of their own.
9393
9403
  // Presence semantics on htmlFor — even an explicit `htmlFor: undefined`
9394
9404
  // means the caller owns the association. Grouped/addons fields hold several
9395
9405
  // controls, so no single association is generated for them.
@@ -9459,10 +9469,11 @@ const Field = withSubComponents(FieldComponent, {
9459
9469
  * generation entirely: the user has taken over the association (#495 presence
9460
9470
  * semantics). When the control renders no label of its own, it adopts the id
9461
9471
  * a labeled Field around it offers, the way the bases do, so that Field's
9462
- * label names it (#939); a user `id` still wins there.
9472
+ * label names it (#939); a user `id` still wins there. With `needsLabelId`
9473
+ * it also returns the id of whichever label names the control (#981).
9463
9474
  * Internal; not part of the public API.
9464
9475
  */
9465
- function useAutoLabelId({ label, id, labelProps, rendersLabel, hasInput = true, }) {
9476
+ function useAutoLabelId({ label, id, labelProps, rendersLabel, hasInput = true, needsLabelId = false, }) {
9466
9477
  // Called unconditionally per the rules of hooks; SSR-safe on React 18 and 19.
9467
9478
  const generatedId = React.useId();
9468
9479
  // Read outside the control's own Field, so it is set only when an outer
@@ -9470,6 +9481,8 @@ function useAutoLabelId({ label, id, labelProps, rendersLabel, hasInput = true,
9470
9481
  const fieldLabelId = useFieldLabelId();
9471
9482
  // What an outer Field's label points at, even when wired by hand.
9472
9483
  const fieldLabelFor = useFieldLabelFor();
9484
+ // That Field's label element, set under the same conditions.
9485
+ const fieldLabelElementId = useFieldLabelElementId();
9473
9486
  // Truthiness mirrors Field's own `if (label)` render gate.
9474
9487
  const active = !!label && rendersLabel;
9475
9488
  // Presence, not truthiness: `htmlFor: undefined` is an explicit opt-out and
@@ -9478,21 +9491,30 @@ function useAutoLabelId({ label, id, labelProps, rendersLabel, hasInput = true,
9478
9491
  const adopted = !active && hasInput ? fieldLabelId : undefined;
9479
9492
  const controlId = id ?? (active && !userWired ? generatedId : adopted);
9480
9493
  const ownLabelProps = { htmlFor: controlId, ...labelProps };
9494
+ const labelTarget = active ? ownLabelProps.htmlFor : fieldLabelFor;
9495
+ const labelled = !!controlId && labelTarget === controlId;
9496
+ // Only a label that names the control gets an id to point at, with the
9497
+ // suffix Field gives its own, from an id that is already unique.
9498
+ const ownLabelId = needsLabelId && active && labelled
9499
+ ? (labelProps?.id ?? `${generatedId}-label`)
9500
+ : undefined;
9481
9501
  // Inactive with a label still means an own Field may render it (pickers'
9482
9502
  // inline mode, Taginput at maxTags) — the explicit `htmlFor: undefined`
9483
9503
  // tells Field the association is owned here, so it must not generate one
9484
9504
  // that would dangle (#495 presence semantics).
9485
9505
  const fieldLabelProps = active
9486
- ? ownLabelProps
9506
+ ? ownLabelId
9507
+ ? { ...ownLabelProps, id: ownLabelId }
9508
+ : ownLabelProps
9487
9509
  : label
9488
9510
  ? { htmlFor: undefined, ...labelProps }
9489
9511
  : labelProps;
9490
- const labelTarget = active ? ownLabelProps.htmlFor : fieldLabelFor;
9491
- return {
9492
- controlId,
9493
- fieldLabelProps,
9494
- labelled: !!controlId && labelTarget === controlId,
9495
- };
9512
+ const labelId = needsLabelId && labelled
9513
+ ? active
9514
+ ? ownLabelId
9515
+ : fieldLabelElementId
9516
+ : undefined;
9517
+ return { controlId, fieldLabelProps, labelled, labelId };
9496
9518
  }
9497
9519
  /**
9498
9520
  * Group-input counterpart of {@link useAutoLabelId} (#494): a group of
@@ -10070,13 +10092,48 @@ const Slider = React.forwardRef((props, ref) => {
10070
10092
  });
10071
10093
  const { bulmaHelperClasses, rest } = useBulmaClasses(restProps);
10072
10094
  // In range mode the low thumb carries `rest` (and any user id), so the
10073
- // label targets it; each thumb keeps its own aria-label for AT.
10074
- const { controlId, fieldLabelProps } = useAutoLabelId({
10095
+ // label's `for` targets it.
10096
+ const { controlId, fieldLabelProps, labelId } = useAutoLabelId({
10075
10097
  label,
10076
10098
  id: restProps.id,
10077
10099
  labelProps,
10078
10100
  rendersLabel: ownField,
10079
- });
10101
+ needsLabelId: !!range,
10102
+ });
10103
+ // A range thumb's default name is an `aria-label`, which outranks the
10104
+ // label's `for`, so a label naming the Slider reaches each thumb through
10105
+ // `aria-labelledby` instead: the label, then a hidden span holding the
10106
+ // thumb's own text, as in "Price Minimum value" (#981). An `ariaLabel`
10107
+ // entry is that thumb's whole name and wins.
10108
+ const thumbTextId = React.useId();
10109
+ const thumbLabels = range
10110
+ ? ariaLabel
10111
+ : undefined;
10112
+ // A caller's `aria-label` or `aria-labelledby` names the Slider in the
10113
+ // label's place, so both thumbs read it before their own text. They are
10114
+ // routed here rather than spread, since the spread reaches only the low
10115
+ // thumb and would leave the pair with two unrelated names. Presence for
10116
+ // aria-labelledby, as on a group (#974): the caller's key takes the naming
10117
+ // over whatever its value, so an undefined one keeps every label out and
10118
+ // leaves both thumbs their bare text. A non-empty one wins over an
10119
+ // aria-label, as it does in the browser's name computation.
10120
+ const { 'aria-label': callerLabel, 'aria-labelledby': callerLabelledBy, ...thumbRest } = rest;
10121
+ const callerNamed = !!callerLabel || 'aria-labelledby' in rest;
10122
+ const stemRef = callerLabelledBy || (callerNamed ? undefined : labelId);
10123
+ const stemText = stemRef ? undefined : callerLabel;
10124
+ const nameThumb = (own, text, textId) => {
10125
+ const wired = !!stemRef && !own;
10126
+ return {
10127
+ text,
10128
+ textId,
10129
+ wired,
10130
+ aria: wired
10131
+ ? { 'aria-labelledby': `${stemRef} ${textId}` }
10132
+ : { 'aria-label': own || (stemText ? `${stemText} ${text}` : text) },
10133
+ };
10134
+ };
10135
+ const lowThumb = nameThumb(thumbLabels?.[0], 'Minimum value', `${thumbTextId}-min`);
10136
+ const highThumb = nameThumb(thumbLabels?.[1], 'Maximum value', `${thumbTextId}-max`);
10080
10137
  // Resolve tooltip mode: explicit tooltip prop takes precedence, else showOutput maps to 'auto'
10081
10138
  const tooltipMode = tooltip ?? (showOutput ? 'auto' : 'hidden');
10082
10139
  // --- Range mode state ---
@@ -10371,7 +10428,7 @@ const Slider = React.forwardRef((props, ref) => {
10371
10428
  : {
10372
10429
  '--slider-progress-low': `${progressLow}%`,
10373
10430
  '--slider-progress-high': `${progressHigh}%`,
10374
- } }), jsxRuntime.jsx("input", { ref: combinedRef, type: "range", min: min, max: max, step: step, value: currentRange[0], disabled: disabled, onChange: handleRangeLowChange, onKeyDown: handleKeyDown, onMouseEnter: () => setShowTooltip(true), onMouseLeave: () => setShowTooltip(false), onFocus: () => setShowTooltip(true), onBlur: () => setShowTooltip(false), className: prefixedClassNames(classPrefix, 'slider-input', 'slider-input-low'), "aria-valuenow": currentRange[0], "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": isVertical ? 'vertical' : undefined, "aria-label": ariaLabel?.[0] ?? 'Minimum value', ...getAriaProps(currentRange[0]), ...rest, id: controlId, ...(nameLow !== undefined ? { name: nameLow } : {}) }), jsxRuntime.jsx("input", { ref: inputHighRef, type: "range", min: min, max: max, step: step, value: currentRange[1], disabled: disabled, onChange: handleRangeHighChange, onMouseEnter: () => setShowTooltipHigh(true), onMouseLeave: () => setShowTooltipHigh(false), onFocus: () => setShowTooltipHigh(true), onBlur: () => setShowTooltipHigh(false), className: prefixedClassNames(classPrefix, 'slider-input', 'slider-input-high'), "aria-valuenow": currentRange[1], "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": isVertical ? 'vertical' : undefined, "aria-label": ariaLabel?.[1] ?? 'Maximum value', ...getAriaProps(currentRange[1]), name: nameHigh }), tooltipMode !== 'hidden' && (jsxRuntime.jsx("output", { ref: outputRef, className: prefixedClassNames(classPrefix, 'slider-output', 'slider-output-low', {
10431
+ } }), jsxRuntime.jsx("input", { ref: combinedRef, type: "range", min: min, max: max, step: step, value: currentRange[0], disabled: disabled, onChange: handleRangeLowChange, onKeyDown: handleKeyDown, onMouseEnter: () => setShowTooltip(true), onMouseLeave: () => setShowTooltip(false), onFocus: () => setShowTooltip(true), onBlur: () => setShowTooltip(false), className: prefixedClassNames(classPrefix, 'slider-input', 'slider-input-low'), "aria-valuenow": currentRange[0], "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": isVertical ? 'vertical' : undefined, ...lowThumb.aria, ...getAriaProps(currentRange[0]), ...thumbRest, id: controlId, ...(nameLow !== undefined ? { name: nameLow } : {}) }), jsxRuntime.jsx("input", { ref: inputHighRef, type: "range", min: min, max: max, step: step, value: currentRange[1], disabled: disabled, onChange: handleRangeHighChange, onMouseEnter: () => setShowTooltipHigh(true), onMouseLeave: () => setShowTooltipHigh(false), onFocus: () => setShowTooltipHigh(true), onBlur: () => setShowTooltipHigh(false), className: prefixedClassNames(classPrefix, 'slider-input', 'slider-input-high'), "aria-valuenow": currentRange[1], "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": isVertical ? 'vertical' : undefined, ...highThumb.aria, ...getAriaProps(currentRange[1]), name: nameHigh }), [lowThumb, highThumb].map(thumb => thumb.wired && (jsxRuntime.jsx("span", { id: thumb.textId, hidden: true, children: thumb.text }, thumb.textId))), tooltipMode !== 'hidden' && (jsxRuntime.jsx("output", { ref: outputRef, className: prefixedClassNames(classPrefix, 'slider-output', 'slider-output-low', {
10375
10432
  'is-visible': showTipLow,
10376
10433
  'is-flipped': flipped,
10377
10434
  'is-flipped-left': isVertical && verticalFlippedLeft,
@@ -14080,7 +14137,13 @@ const SKIPPED_SEGMENTS = {
14080
14137
  * @returns {JSX.Element}
14081
14138
  */
14082
14139
  const DateInputBase = React.forwardRef((props, ref) => {
14083
- const { value: controlledValue, defaultValue, onChange, onOpen, onClose, min, max, disabled, readOnly, placeholder, granularity = 'day', format, parse, locale, inline = false, mobileNative = 'auto', editable = true, popover = true, openOnFocus = true, closeOnSelect = true, position = 'bottom-left', appendToBody = false, color, size, isRounded, shouldDisableDate, unselectableDates, firstDayOfWeek = 0, dayNames, monthNames, nearbyMonthDays = true, className, name, form, required, id, onFocus, onClick, onKeyDown, onBlur, iconLeftName: _iconLeftName, triggerIcon: triggerIconProp, triggerIconName = 'chevron-down', labels, ...rest } = props;
14140
+ const { value: controlledValue, defaultValue, onChange, onOpen, onClose, min, max, disabled, readOnly, placeholder, granularity = 'day', format, parse, locale, inline = false, mobileNative = 'auto', editable = true, popover = true, openOnFocus = true, closeOnSelect = true, position = 'bottom-left', appendToBody = false, color, size, isRounded, shouldDisableDate, unselectableDates, firstDayOfWeek = 0, dayNames, monthNames, nearbyMonthDays = true, className, name, form, required, id: idProp, onFocus, onClick, onKeyDown, onBlur, iconLeftName: _iconLeftName, triggerIcon: triggerIconProp, triggerIconName = 'chevron-down', labels, ...rest } = props;
14141
+ // Inside a labeled Field the input takes the id the label points at
14142
+ // when the caller set none, as InputBase does, and the popover's ids
14143
+ // follow it. Inline there is no input to name, so nothing takes the
14144
+ // Field's id or builds on it.
14145
+ const fieldLabelId = useFieldLabelId();
14146
+ const id = idProp ?? (inline ? undefined : fieldLabelId);
14084
14147
  // The launcher gives way to the loading spinner of a Control this sits in.
14085
14148
  const controlLoading = useControlLoading();
14086
14149
  const triggerIcon = triggerIconProp ?? !controlLoading;
@@ -15256,7 +15319,13 @@ const fromIsoTime = (s) => {
15256
15319
  * @returns {JSX.Element}
15257
15320
  */
15258
15321
  const TimeInputBase = React.forwardRef((props, ref) => {
15259
- const { value: controlledValue, defaultValue, onChange, onOpen, onClose, min, max, disabled, readOnly, placeholder, format, parse, locale, inline = false, mobileNative = 'auto', editable = true, popover = true, openOnFocus = true, closeOnSelect = false, position = 'bottom-left', appendToBody = false, color, size, isRounded, hourFormat = '24', enableSeconds = false, incrementHours = 1, incrementMinutes = 1, incrementSeconds = 1, unselectableTimes, className, name, form, required, id, onFocus, onClick, onKeyDown, onBlur, iconLeftName: _iconLeftName, triggerIcon: triggerIconProp, triggerIconName = 'chevron-down', labels, audioTick = false, haptics = false, ...rest } = props;
15322
+ const { value: controlledValue, defaultValue, onChange, onOpen, onClose, min, max, disabled, readOnly, placeholder, format, parse, locale, inline = false, mobileNative = 'auto', editable = true, popover = true, openOnFocus = true, closeOnSelect = false, position = 'bottom-left', appendToBody = false, color, size, isRounded, hourFormat = '24', enableSeconds = false, incrementHours = 1, incrementMinutes = 1, incrementSeconds = 1, unselectableTimes, className, name, form, required, id: idProp, onFocus, onClick, onKeyDown, onBlur, iconLeftName: _iconLeftName, triggerIcon: triggerIconProp, triggerIconName = 'chevron-down', labels, audioTick = false, haptics = false, ...rest } = props;
15323
+ // Inside a labeled Field the input takes the id the label points at
15324
+ // when the caller set none, as InputBase does, and the popover's ids
15325
+ // follow it. Inline there is no input to name, so nothing takes the
15326
+ // Field's id or builds on it.
15327
+ const fieldLabelId = useFieldLabelId();
15328
+ const id = idProp ?? (inline ? undefined : fieldLabelId);
15260
15329
  // The launcher gives way to the loading spinner of a Control this sits in.
15261
15330
  const controlLoading = useControlLoading();
15262
15331
  const triggerIcon = triggerIconProp ?? !controlLoading;
@@ -15568,7 +15637,13 @@ const fromIsoDateTime = (s) => {
15568
15637
  const DateTimeInputBase = React.forwardRef((props, ref) => {
15569
15638
  const { value: controlledValue, defaultValue, onChange, onOpen, onClose, min, max, disabled, readOnly, placeholder, format, parse, locale, inline = false, mobileNative = 'auto', editable = true, popover = true, openOnFocus = true, closeOnSelect = false, position = 'bottom-left', appendToBody = false, color, size, isRounded, shouldDisableDate, unselectableDates, firstDayOfWeek = 0, dayNames, monthNames, nearbyMonthDays = true, hourFormat = '24', enableSeconds = false, incrementHours = 1,
15570
15639
  // Step between visible wheel values; 1 gives the iOS-style every-minute wheel.
15571
- incrementMinutes = 1, incrementSeconds = 1, unselectableTimes, className, name, form, required, id, onFocus, onClick, onKeyDown, onBlur, iconLeftName: _iconLeftName, triggerIcon: triggerIconProp, triggerIconName = 'chevron-down', audioTick = false, haptics = false, labels, ...rest } = props;
15640
+ incrementMinutes = 1, incrementSeconds = 1, unselectableTimes, className, name, form, required, id: idProp, onFocus, onClick, onKeyDown, onBlur, iconLeftName: _iconLeftName, triggerIcon: triggerIconProp, triggerIconName = 'chevron-down', audioTick = false, haptics = false, labels, ...rest } = props;
15641
+ // Inside a labeled Field the input takes the id the label points at
15642
+ // when the caller set none, as InputBase does, and the popover's ids
15643
+ // follow it. Inline there is no input to name, so nothing takes the
15644
+ // Field's id or builds on it.
15645
+ const fieldLabelId = useFieldLabelId();
15646
+ const id = idProp ?? (inline ? undefined : fieldLabelId);
15572
15647
  // The launcher gives way to the loading spinner of a Control this sits in.
15573
15648
  const controlLoading = useControlLoading();
15574
15649
  const triggerIcon = triggerIconProp ?? !controlLoading;