@allxsmith/bestax-bulma 5.8.1 → 5.8.2

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/index.esm.js CHANGED
@@ -5901,6 +5901,25 @@ const CheckboxesComponent = ({ label, labelSize, labelProps, horizontal, message
5901
5901
  };
5902
5902
  const Checkboxes = withSubComponents(CheckboxesComponent, { Checkbox }, 'Checkboxes');
5903
5903
 
5904
+ /**
5905
+ * Associates the convenience `label` prop with its control (#368): generates
5906
+ * an id for the control and returns labelProps carrying a matching `htmlFor`.
5907
+ * A user-supplied `id` is used as the target instead of the generated one, and
5908
+ * an explicit `labelProps.htmlFor` disables generation entirely — the user has
5909
+ * taken over the association. Internal; not part of the public API.
5910
+ */
5911
+ function useAutoLabelId({ label, id, labelProps, rendersLabel, }) {
5912
+ // Called unconditionally per the rules of hooks; SSR-safe on React 18 and 19.
5913
+ const generatedId = useId();
5914
+ // Truthiness mirrors Field's own `if (label)` render gate.
5915
+ const active = !!label && rendersLabel;
5916
+ const controlId = id ?? (active && !labelProps?.htmlFor ? generatedId : undefined);
5917
+ const fieldLabelProps = active
5918
+ ? { htmlFor: controlId, ...labelProps }
5919
+ : labelProps;
5920
+ return { controlId, fieldLabelProps };
5921
+ }
5922
+
5904
5923
  /**
5905
5924
  * The `File` component provides a Bulma-styled file input, supporting color, size, boxed/fullwidth/align styles, icons, "has name", and filename display.
5906
5925
  *
@@ -5913,6 +5932,12 @@ const File = forwardRef(({
5913
5932
  // Field props
5914
5933
  label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName, color, size, isBoxed, isFullwidth, isRight, isCentered, hasName, buttonLabel, iconLeft, iconRight, className, inputClassName, fileName, ...props }, ref) => {
5915
5934
  const insideField = useInsideField();
5935
+ const { controlId, fieldLabelProps } = useAutoLabelId({
5936
+ label,
5937
+ id: props.id,
5938
+ labelProps,
5939
+ rendersLabel: !insideField,
5940
+ });
5916
5941
  const { classPrefix } = useConfig();
5917
5942
  const { bulmaHelperClasses, rest } = useBulmaClasses({
5918
5943
  color,
@@ -5942,9 +5967,9 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
5942
5967
  [`is-${messageColor}`]: !!messageColor,
5943
5968
  });
5944
5969
  const messageEl = message ? jsx("p", { className: helpClass, children: message }) : null;
5945
- const fileElement = (jsx("div", { className: fileClass, children: jsxs("label", { className: usePrefixedClassNames('file-label'), children: [jsx("input", { ref: ref, className: classNames(usePrefixedClassNames('file-input'), inputClassName), type: "file", ...rest }), jsxs("span", { className: usePrefixedClassNames('file-cta'), children: [iconLeft && (jsx("span", { className: prefixedClassNames(classPrefix, 'file-icon'), children: iconLeft })), jsx("span", { className: usePrefixedClassNames('file-label'), children: buttonLabel || 'Choose a file\u2026' }), iconRight && (jsx("span", { className: prefixedClassNames(classPrefix, 'file-icon'), children: iconRight }))] }), hasName && fileName && (jsx("span", { className: prefixedClassNames(classPrefix, 'file-name'), children: fileName }))] }) }));
5970
+ const fileElement = (jsx("div", { className: fileClass, children: jsxs("label", { className: usePrefixedClassNames('file-label'), children: [jsx("input", { ref: ref, className: classNames(usePrefixedClassNames('file-input'), inputClassName), type: "file", id: controlId, ...rest }), jsxs("span", { className: usePrefixedClassNames('file-cta'), children: [iconLeft && (jsx("span", { className: prefixedClassNames(classPrefix, 'file-icon'), children: iconLeft })), jsx("span", { className: usePrefixedClassNames('file-label'), children: buttonLabel || 'Choose a file\u2026' }), iconRight && (jsx("span", { className: prefixedClassNames(classPrefix, 'file-icon'), children: iconRight }))] }), hasName && fileName && (jsx("span", { className: prefixedClassNames(classPrefix, 'file-name'), children: fileName }))] }) }));
5946
5971
  if (!insideField) {
5947
- return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, className: fieldClassName, children: [fileElement, messageEl] }));
5972
+ return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [fileElement, messageEl] }));
5948
5973
  }
5949
5974
  return (jsxs(Fragment, { children: [fileElement, messageEl] }));
5950
5975
  });
@@ -6237,6 +6262,14 @@ const Slider = forwardRef((props, ref) => {
6237
6262
  const insideField = useInsideField();
6238
6263
  const insideControl = useInsideControl();
6239
6264
  const { bulmaHelperClasses, rest } = useBulmaClasses(restProps);
6265
+ // In range mode the low thumb carries `rest` (and any user id), so the
6266
+ // label targets it; each thumb keeps its own aria-label for AT.
6267
+ const { controlId, fieldLabelProps } = useAutoLabelId({
6268
+ label,
6269
+ id: restProps.id,
6270
+ labelProps,
6271
+ rendersLabel: !insideField,
6272
+ });
6240
6273
  // Resolve tooltip mode: explicit tooltip prop takes precedence, else showOutput maps to 'auto'
6241
6274
  const tooltipMode = tooltip ?? (showOutput ? 'auto' : 'hidden');
6242
6275
  // --- Range mode state ---
@@ -6501,7 +6534,7 @@ const Slider = forwardRef((props, ref) => {
6501
6534
  // --- Single slider ---
6502
6535
  const sliderElement = !range ? (jsxs("div", { ref: wrapperRef, className: combinedClasses, style: wrapperStyle, children: [jsx("input", { ref: combinedRef, type: "range", min: min, max: max, step: step, value: currentSingle, disabled: disabled, onChange: handleSingleChange, onKeyDown: handleKeyDown, onMouseEnter: () => setShowTooltip(true), onMouseLeave: () => setShowTooltip(false), onFocus: () => setShowTooltip(true), onBlur: () => setShowTooltip(false), className: prefixedClassNames(classPrefix, 'slider-input'), style: {
6503
6536
  '--slider-progress': `${progressSingle}%`,
6504
- }, "aria-valuenow": currentSingle, "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": isVertical ? 'vertical' : undefined, "aria-label": ariaLabel, ...getAriaProps(currentSingle), ...rest }), tooltipMode !== 'hidden' && (jsx("output", { ref: outputRef, className: prefixedClassNames(classPrefix, 'slider-output', {
6537
+ }, "aria-valuenow": currentSingle, "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": isVertical ? 'vertical' : undefined, "aria-label": ariaLabel, ...getAriaProps(currentSingle), id: controlId, ...rest }), tooltipMode !== 'hidden' && (jsx("output", { ref: outputRef, className: prefixedClassNames(classPrefix, 'slider-output', {
6505
6538
  'is-visible': showTipLow,
6506
6539
  'is-flipped': flipped,
6507
6540
  'is-flipped-left': isVertical && verticalFlippedLeft,
@@ -6529,7 +6562,7 @@ const Slider = forwardRef((props, ref) => {
6529
6562
  : {
6530
6563
  '--slider-progress-low': `${progressLow}%`,
6531
6564
  '--slider-progress-high': `${progressHigh}%`,
6532
- } }), 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, ...(nameLow !== undefined ? { name: nameLow } : {}) }), 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' && (jsx("output", { ref: outputRef, className: prefixedClassNames(classPrefix, 'slider-output', 'slider-output-low', {
6565
+ } }), 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]), id: controlId, ...rest, ...(nameLow !== undefined ? { name: nameLow } : {}) }), 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' && (jsx("output", { ref: outputRef, className: prefixedClassNames(classPrefix, 'slider-output', 'slider-output-low', {
6533
6566
  'is-visible': showTipLow,
6534
6567
  'is-flipped': flipped,
6535
6568
  'is-flipped-left': isVertical && verticalFlippedLeft,
@@ -6575,7 +6608,7 @@ const Slider = forwardRef((props, ref) => {
6575
6608
  content = jsx(Control, { children: content });
6576
6609
  }
6577
6610
  if (!insideField) {
6578
- return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
6611
+ return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
6579
6612
  }
6580
6613
  return (jsxs(Fragment, { children: [content, messageEl] }));
6581
6614
  });
@@ -6613,6 +6646,13 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
6613
6646
  const isStepper = variant === 'stepper';
6614
6647
  const isAddons = compact || isStepper;
6615
6648
  const effectiveControlsPosition = isStepper ? 'right' : controlsPosition;
6649
+ // The plusminus bare branch renders no Field and no label at all.
6650
+ const { controlId, fieldLabelProps } = useAutoLabelId({
6651
+ label,
6652
+ id: props.id,
6653
+ labelProps,
6654
+ rendersLabel: !insideField && (isStepper || !effectiveBare),
6655
+ });
6616
6656
  // Clamp value to min/max
6617
6657
  const clampValue = useCallback((val) => {
6618
6658
  let clamped = val;
@@ -6711,12 +6751,12 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
6711
6751
  }
6712
6752
  };
6713
6753
  // Shared input element
6714
- const inputControl = (jsx("div", { className: expandedControlClasses, children: jsx("input", { ref: combinedRef, type: "number", className: inputClasses, value: currentValue ?? '', min: min, max: max, step: step, disabled: disabled, readOnly: !editable, onChange: handleInputChange, onKeyDown: handleKeyDown, "aria-valuenow": currentValue ?? undefined, "aria-valuemin": min, "aria-valuemax": max, ...rest }) }));
6754
+ const inputControl = (jsx("div", { className: expandedControlClasses, children: jsx("input", { ref: combinedRef, type: "number", className: inputClasses, value: currentValue ?? '', min: min, max: max, step: step, disabled: disabled, readOnly: !editable, onChange: handleInputChange, onKeyDown: handleKeyDown, "aria-valuenow": currentValue ?? undefined, "aria-valuemin": min, "aria-valuemax": max, id: controlId, ...rest }) }));
6715
6755
  // Stepper variant
6716
6756
  if (isStepper) {
6717
6757
  const stepperElement = (jsxs("div", { className: combinedClasses, children: [inputControl, jsx("div", { className: controlClasses, children: jsxs("div", { className: stepperClasses, children: [jsx("button", { type: "button", className: stepperButtonClasses, onClick: handleIncrement, disabled: disabled || isAtMax, tabIndex: -1, "aria-label": "Increase value", children: jsx(ArrowDropUp, {}) }), jsx("button", { type: "button", className: stepperButtonClasses, onClick: handleDecrement, disabled: disabled || isAtMin, tabIndex: -1, "aria-label": "Decrease value", children: jsx(ArrowDropDown, {}) })] }) })] }));
6718
6758
  if (!insideField) {
6719
- return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, className: fieldClassName, children: [stepperElement, messageEl] }));
6759
+ return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [stepperElement, messageEl] }));
6720
6760
  }
6721
6761
  return (jsxs(Fragment, { children: [stepperElement, messageEl] }));
6722
6762
  }
@@ -6750,7 +6790,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
6750
6790
  numberinputElement = (jsxs("div", { className: combinedClasses, children: [decrementControl, inputControl, incrementControl] }));
6751
6791
  }
6752
6792
  if (!insideField) {
6753
- return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, className: fieldClassName, children: [numberinputElement, messageEl] }));
6793
+ return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [numberinputElement, messageEl] }));
6754
6794
  }
6755
6795
  return (jsxs(Fragment, { children: [numberinputElement, messageEl] }));
6756
6796
  });
@@ -7694,16 +7734,22 @@ fieldClassName, controlClassName,
7694
7734
  ...inputProps }, ref) => {
7695
7735
  const insideField = useInsideField();
7696
7736
  const insideControl = useInsideControl();
7737
+ const { controlId, fieldLabelProps } = useAutoLabelId({
7738
+ label,
7739
+ id: inputProps.id,
7740
+ labelProps,
7741
+ rendersLabel: !insideField,
7742
+ });
7697
7743
  const helpClass = usePrefixedClassNames('help', {
7698
7744
  [`is-${messageColor}`]: !!messageColor,
7699
7745
  });
7700
- let content = jsx(InputBase, { ref: ref, ...inputProps });
7746
+ let content = jsx(InputBase, { ref: ref, id: controlId, ...inputProps });
7701
7747
  if (!insideControl) {
7702
7748
  content = (jsx(Control, { iconLeft: iconLeft, iconRight: iconRight, iconLeftName: iconLeftName, iconRightName: iconRightName, iconLeftSize: iconLeftSize, iconRightSize: iconRightSize, hasIconsLeft: hasIconsLeft, hasIconsRight: hasIconsRight, isLoading: isLoading, isExpanded: isExpanded, size: controlSize, className: controlClassName, children: content }));
7703
7749
  }
7704
7750
  const messageEl = message ? jsx("p", { className: helpClass, children: message }) : null;
7705
7751
  if (!insideField) {
7706
- return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
7752
+ return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
7707
7753
  }
7708
7754
  return (jsxs(Fragment, { children: [content, messageEl] }));
7709
7755
  });
@@ -7738,16 +7784,22 @@ fieldClassName, controlClassName,
7738
7784
  ...selectProps }, ref) => {
7739
7785
  const insideField = useInsideField();
7740
7786
  const insideControl = useInsideControl();
7787
+ const { controlId, fieldLabelProps } = useAutoLabelId({
7788
+ label,
7789
+ id: selectProps.id,
7790
+ labelProps,
7791
+ rendersLabel: !insideField,
7792
+ });
7741
7793
  const helpClass = usePrefixedClassNames('help', {
7742
7794
  [`is-${messageColor}`]: !!messageColor,
7743
7795
  });
7744
- let content = jsx(SelectBase, { ref: ref, ...selectProps });
7796
+ let content = jsx(SelectBase, { ref: ref, id: controlId, ...selectProps });
7745
7797
  if (!insideControl) {
7746
7798
  content = (jsx(Control, { iconLeft: iconLeft, iconLeftName: iconLeftName, iconLeftSize: iconLeftSize, hasIconsLeft: hasIconsLeft, isExpanded: isExpanded, size: controlSize, className: controlClassName, children: content }));
7747
7799
  }
7748
7800
  const messageEl = message ? jsx("p", { className: helpClass, children: message }) : null;
7749
7801
  if (!insideField) {
7750
- return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
7802
+ return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
7751
7803
  }
7752
7804
  return (jsxs(Fragment, { children: [content, messageEl] }));
7753
7805
  });
@@ -7783,16 +7835,22 @@ fieldClassName, controlClassName,
7783
7835
  ...textAreaProps }, ref) => {
7784
7836
  const insideField = useInsideField();
7785
7837
  const insideControl = useInsideControl();
7838
+ const { controlId, fieldLabelProps } = useAutoLabelId({
7839
+ label,
7840
+ id: textAreaProps.id,
7841
+ labelProps,
7842
+ rendersLabel: !insideField,
7843
+ });
7786
7844
  const helpClass = usePrefixedClassNames('help', {
7787
7845
  [`is-${messageColor}`]: !!messageColor,
7788
7846
  });
7789
- let content = jsx(TextAreaBase, { ref: ref, ...textAreaProps });
7847
+ let content = jsx(TextAreaBase, { ref: ref, id: controlId, ...textAreaProps });
7790
7848
  if (!insideControl) {
7791
7849
  content = (jsx(Control, { isLoading: controlIsLoading, size: controlSize, className: controlClassName, children: content }));
7792
7850
  }
7793
7851
  const messageEl = message ? jsx("p", { className: helpClass, children: message }) : null;
7794
7852
  if (!insideField) {
7795
- return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
7853
+ return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
7796
7854
  }
7797
7855
  return (jsxs(Fragment, { children: [content, messageEl] }));
7798
7856
  });
@@ -9469,12 +9527,19 @@ DateInputBase.displayName = 'DateInputBase';
9469
9527
  const DateInput = forwardRef(({ label, labelSize, labelProps, horizontal, iconLeft, iconRight, iconLeftName = 'calendar', iconRightName, iconLeftSize, iconRightSize, hasIconsLeft, hasIconsRight, isLoading, isExpanded, controlSize, message, messageColor, fieldClassName, controlClassName, ...baseProps }, ref) => {
9470
9528
  const insideField = useInsideField();
9471
9529
  const insideControl = useInsideControl();
9530
+ const { controlId, fieldLabelProps } = useAutoLabelId({
9531
+ label,
9532
+ id: baseProps.id,
9533
+ labelProps,
9534
+ // Inline mode renders a bare calendar with no input to label.
9535
+ rendersLabel: !insideField && !baseProps.inline,
9536
+ });
9472
9537
  const helpClass = usePrefixedClassNames('help', {
9473
9538
  [`is-${messageColor}`]: !!messageColor,
9474
9539
  });
9475
9540
  // The right-side launcher is on by default; suppress it while the Control
9476
9541
  // shows its loading spinner (also on the right) unless explicitly set.
9477
- let content = (jsx(DateInputBase, { ref: ref, ...baseProps, triggerIcon: baseProps.triggerIcon ?? !isLoading }));
9542
+ let content = (jsx(DateInputBase, { ref: ref, id: controlId, ...baseProps, triggerIcon: baseProps.triggerIcon ?? !isLoading }));
9478
9543
  // Inline mode renders a bare calendar with no input, so the Control's
9479
9544
  // icon-left container has nothing to anchor to. Skip the Control wrap.
9480
9545
  if (!insideControl && !baseProps.inline) {
@@ -9482,7 +9547,7 @@ const DateInput = forwardRef(({ label, labelSize, labelProps, horizontal, iconLe
9482
9547
  }
9483
9548
  const messageEl = message ? jsx("p", { className: helpClass, children: message }) : null;
9484
9549
  if (!insideField) {
9485
- return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
9550
+ return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
9486
9551
  }
9487
9552
  return (jsxs(Fragment, { children: [content, messageEl] }));
9488
9553
  });
@@ -10553,12 +10618,19 @@ TimeInputBase.displayName = 'TimeInputBase';
10553
10618
  const TimeInput = forwardRef(({ label, labelSize, labelProps, horizontal, iconLeft, iconRight, iconLeftName = 'clock', iconRightName, iconLeftSize, iconRightSize, hasIconsLeft, hasIconsRight, isLoading, isExpanded, controlSize, message, messageColor, fieldClassName, controlClassName, ...baseProps }, ref) => {
10554
10619
  const insideField = useInsideField();
10555
10620
  const insideControl = useInsideControl();
10621
+ const { controlId, fieldLabelProps } = useAutoLabelId({
10622
+ label,
10623
+ id: baseProps.id,
10624
+ labelProps,
10625
+ // Inline mode renders a bare panel with no input to label.
10626
+ rendersLabel: !insideField && !baseProps.inline,
10627
+ });
10556
10628
  const helpClass = usePrefixedClassNames('help', {
10557
10629
  [`is-${messageColor}`]: !!messageColor,
10558
10630
  });
10559
10631
  // The right-side launcher is on by default; suppress it while the Control
10560
10632
  // shows its loading spinner (also on the right) unless explicitly set.
10561
- let content = (jsx(TimeInputBase, { ref: ref, ...baseProps, triggerIcon: baseProps.triggerIcon ?? !isLoading }));
10633
+ let content = (jsx(TimeInputBase, { ref: ref, id: controlId, ...baseProps, triggerIcon: baseProps.triggerIcon ?? !isLoading }));
10562
10634
  // Inline mode renders a bare panel with no input, so the Control's
10563
10635
  // icon-left container has nothing to anchor to. Skip the Control wrap.
10564
10636
  if (!insideControl && !baseProps.inline) {
@@ -10566,7 +10638,7 @@ const TimeInput = forwardRef(({ label, labelSize, labelProps, horizontal, iconLe
10566
10638
  }
10567
10639
  const messageEl = message ? jsx("p", { className: helpClass, children: message }) : null;
10568
10640
  if (!insideField) {
10569
- return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
10641
+ return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
10570
10642
  }
10571
10643
  return (jsxs(Fragment, { children: [content, messageEl] }));
10572
10644
  });
@@ -10842,12 +10914,19 @@ DateTimeInputBase.displayName = 'DateTimeInputBase';
10842
10914
  const DateTimeInput = forwardRef(({ label, labelSize, labelProps, horizontal, iconLeft, iconRight, iconLeftName = 'calendar-alt', iconRightName, iconLeftSize, iconRightSize, hasIconsLeft, hasIconsRight, isLoading, isExpanded, controlSize, message, messageColor, fieldClassName, controlClassName, ...baseProps }, ref) => {
10843
10915
  const insideField = useInsideField();
10844
10916
  const insideControl = useInsideControl();
10917
+ const { controlId, fieldLabelProps } = useAutoLabelId({
10918
+ label,
10919
+ id: baseProps.id,
10920
+ labelProps,
10921
+ // Inline mode renders a bare picker with no input to label.
10922
+ rendersLabel: !insideField && !baseProps.inline,
10923
+ });
10845
10924
  const helpClass = usePrefixedClassNames('help', {
10846
10925
  [`is-${messageColor}`]: !!messageColor,
10847
10926
  });
10848
10927
  // The right-side launcher is on by default; suppress it while the Control
10849
10928
  // shows its loading spinner (also on the right) unless explicitly set.
10850
- let content = (jsx(DateTimeInputBase, { ref: ref, ...baseProps, triggerIcon: baseProps.triggerIcon ?? !isLoading }));
10929
+ let content = (jsx(DateTimeInputBase, { ref: ref, id: controlId, ...baseProps, triggerIcon: baseProps.triggerIcon ?? !isLoading }));
10851
10930
  // Inline mode renders a bare picker with no input, so the Control's
10852
10931
  // icon-left container has nothing to anchor to. Skip the Control wrap.
10853
10932
  if (!insideControl && !baseProps.inline) {
@@ -10855,7 +10934,7 @@ const DateTimeInput = forwardRef(({ label, labelSize, labelProps, horizontal, ic
10855
10934
  }
10856
10935
  const messageEl = message ? jsx("p", { className: helpClass, children: message }) : null;
10857
10936
  if (!insideField) {
10858
- return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: labelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
10937
+ return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [content, messageEl] }));
10859
10938
  }
10860
10939
  return (jsxs(Fragment, { children: [content, messageEl] }));
10861
10940
  });