@allxsmith/bestax-bulma 5.27.6 → 5.27.8

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.
Files changed (62) hide show
  1. package/dist/bestax.css +1 -1
  2. package/dist/bestax.css.map +1 -1
  3. package/dist/esm/elements/Notification.js +1 -0
  4. package/dist/esm/elements/Notification.js.map +1 -1
  5. package/dist/esm/form/DateInputBase.js +2 -3
  6. package/dist/esm/form/DateInputBase.js.map +1 -1
  7. package/dist/esm/form/DateRangeInputBase.js +18 -3
  8. package/dist/esm/form/DateRangeInputBase.js.map +1 -1
  9. package/dist/esm/form/DateTimeInputBase.js +2 -3
  10. package/dist/esm/form/DateTimeInputBase.js.map +1 -1
  11. package/dist/esm/form/Field.js +39 -7
  12. package/dist/esm/form/Field.js.map +1 -1
  13. package/dist/esm/form/FormContext.js +56 -11
  14. package/dist/esm/form/FormContext.js.map +1 -1
  15. package/dist/esm/form/InputBase.js +6 -5
  16. package/dist/esm/form/InputBase.js.map +1 -1
  17. package/dist/esm/form/SelectBase.js +7 -5
  18. package/dist/esm/form/SelectBase.js.map +1 -1
  19. package/dist/esm/form/TextAreaBase.js +6 -5
  20. package/dist/esm/form/TextAreaBase.js.map +1 -1
  21. package/dist/esm/form/TimeInputBase.js +2 -3
  22. package/dist/esm/form/TimeInputBase.js.map +1 -1
  23. package/dist/esm/form/useAutoLabelId.js +8 -3
  24. package/dist/esm/form/useAutoLabelId.js.map +1 -1
  25. package/dist/esm/helpers/Theme.js +87 -17
  26. package/dist/esm/helpers/Theme.js.map +1 -1
  27. package/dist/esm/helpers/devWarnings.js +8 -3
  28. package/dist/esm/helpers/devWarnings.js.map +1 -1
  29. package/dist/esm/helpers/useFlexboxClasses.js +1 -1
  30. package/dist/esm/helpers/useOtherClasses.js +1 -1
  31. package/dist/esm/helpers/useSpacingClasses.js +1 -1
  32. package/dist/esm/helpers/useTypographyClasses.js +1 -1
  33. package/dist/esm/helpers/useVisibilityClasses.js +1 -1
  34. package/dist/extras.css +1 -1
  35. package/dist/extras.css.map +1 -1
  36. package/dist/index.cjs +226 -55
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/types/elements/Notification.d.ts +5 -0
  39. package/dist/types/form/DateRangeInputBase.d.ts +5 -0
  40. package/dist/types/form/Field.d.ts +2 -2
  41. package/dist/types/form/FormContext.d.ts +50 -10
  42. package/dist/types/form/useAutoLabelId.d.ts +4 -2
  43. package/dist/types/helpers/Theme.d.ts +15 -1
  44. package/dist/types/helpers/devWarnings.d.ts +8 -0
  45. package/dist/types-cjs/elements/Notification.d.ts +5 -0
  46. package/dist/types-cjs/form/DateRangeInputBase.d.ts +5 -0
  47. package/dist/types-cjs/form/Field.d.ts +2 -2
  48. package/dist/types-cjs/form/FormContext.d.ts +50 -10
  49. package/dist/types-cjs/form/useAutoLabelId.d.ts +4 -2
  50. package/dist/types-cjs/helpers/Theme.d.ts +15 -1
  51. package/dist/types-cjs/helpers/devWarnings.d.ts +8 -0
  52. package/dist/versions/bestax-no-dark-mode.css +1 -1
  53. package/dist/versions/bestax-no-dark-mode.css.map +1 -1
  54. package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
  55. package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
  56. package/dist/versions/bestax-no-helpers.css +1 -1
  57. package/dist/versions/bestax-no-helpers.css.map +1 -1
  58. package/dist/versions/bestax-prefixed.css +1 -1
  59. package/dist/versions/bestax-prefixed.css.map +1 -1
  60. package/package.json +18 -18
  61. package/src/scss/elements/_index.scss +1 -0
  62. package/src/scss/elements/_notification.scss +69 -0
package/dist/index.cjs CHANGED
@@ -1444,8 +1444,13 @@ function isCustomElement(as) {
1444
1444
 
1445
1445
  // INTERNAL: deliberately not exported from src/index.ts.
1446
1446
  const warnedKeys = new Set();
1447
- // Fail closed: with no bundler and no Node (raw CDN ESM), reading `process`
1448
- // throws and warnings stay off, so production can never warn by accident.
1447
+ /**
1448
+ * Whether this is a development build. Fail closed: with no bundler and no
1449
+ * Node (raw CDN ESM), reading `process` throws and this is false, so
1450
+ * production can never warn by accident. Exported for a caller whose
1451
+ * development-only check costs something before it reaches `warnOnce`, so it
1452
+ * can skip that work in production too.
1453
+ */
1449
1454
  const isDev = () => {
1450
1455
  try {
1451
1456
  return process.env.NODE_ENV !== 'production';
@@ -8131,6 +8136,7 @@ const Notification = ({ className, color, textColor, isLight, hasDelete, onDelet
8131
8136
  const bulmaClasses = usePrefixedClassNames('notification', {
8132
8137
  [`is-${color}`]: color && validColors.includes(color),
8133
8138
  'is-light': isLight,
8139
+ 'has-delete': hasDelete,
8134
8140
  });
8135
8141
  const deleteClasses = usePrefixedClassNames('delete');
8136
8142
  const notificationClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
@@ -9068,10 +9074,14 @@ const FieldLabelIdContext = React.createContext(undefined);
9068
9074
  * The id a labeled Field wants its single composed control to adopt (#495).
9069
9075
  * `undefined` outside a Field, in unlabeled/grouped/addons Fields, or when the
9070
9076
  * user took over the association with an explicit `labelProps.htmlFor`.
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.
9077
+ * Consumed through `useFieldLabelTarget` by the single-control bases
9078
+ * (InputBase, SelectBase, TextAreaBase, and the date and time picker bases
9079
+ * unless inline, #968) and, through `useAutoLabelId`, by the convenience
9080
+ * inputs that render an input of their own (#939). Read it only through
9081
+ * those, which report what they take: a control that read it directly would
9082
+ * report nothing and lose its label (#1004), and
9083
+ * `__tests__/field-label-readers.test.ts` fails on one. Internal; not part of
9084
+ * the public API.
9075
9085
  */
9076
9086
  const useFieldLabelId = () => React.useContext(FieldLabelIdContext);
9077
9087
  /** Provider for the Field label-target id — used internally by Field. */
@@ -9079,8 +9089,9 @@ const FieldLabelIdProvider = FieldLabelIdContext.Provider;
9079
9089
  const FieldLabelElementIdContext = React.createContext(undefined);
9080
9090
  /**
9081
9091
  * The id of a labeled Field's own `<label>`, for a group control (Radios,
9082
- * Checkboxes, Rate, DateRangeInput) to point `aria-labelledby` at, since a group cannot take
9083
- * the label's `htmlFor` (#939). Set under the same conditions as
9092
+ * Checkboxes, Rate, DateRangeInput and DateRangeInputBase) to point
9093
+ * `aria-labelledby` at, since a group cannot take the label's `htmlFor`
9094
+ * (#939, #1005). Set under the same conditions as
9084
9095
  * {@link useFieldLabelId}. Consumed through `useAutoLabelledBy`.
9085
9096
  * Internal; not part of the public API.
9086
9097
  */
@@ -9096,15 +9107,54 @@ const FieldLabelForContext = React.createContext({});
9096
9107
  * the outer label names it, and point at that label by its id, as a range
9097
9108
  * Slider's thumbs (#981) and Autocomplete's suggestion list (#998) do. The
9098
9109
  * `htmlFor` is only ever compared with a control's own id, never adopted, so
9099
- * it hands out no id for a control. The `id` is set only while that label
9100
- * renders with it. Unlike {@link useFieldLabelId}, it is set in a `grouped`
9101
- * or `hasAddons` Field too, so a label wired by hand names the control its
9102
- * `for` picks in those rows as well. Consumed through `useAutoLabelId`.
9110
+ * it hands out no id for a control. It keeps the generated id after the
9111
+ * label drops a `for` nothing took (#1004), which no control's id matches
9112
+ * then, so the value does not change under the content that reported it.
9113
+ * The `id` is set only while that label renders with it. Unlike
9114
+ * {@link useFieldLabelId}, it is set in a `grouped` or `hasAddons` Field
9115
+ * too, so a label wired by hand names the control its `for` picks in those
9116
+ * rows as well. Consumed through `useAutoLabelId`.
9103
9117
  * Internal; not part of the public API.
9104
9118
  */
9105
9119
  const useFieldLabelFor = () => React.useContext(FieldLabelForContext);
9106
9120
  /** Provider for the Field label's `htmlFor` target and id, used internally by Field. */
9107
9121
  const FieldLabelForProvider = FieldLabelForContext.Provider;
9122
+ const FieldLabelForReportContext = React.createContext(undefined);
9123
+ /**
9124
+ * Tells the nearest labeled Field that this content took its generated id
9125
+ * while `takesFor` is true (#1004). Once the Field's content has mounted, its
9126
+ * label keeps the generated `for` only while something has said so, so the
9127
+ * label renders none over a group, a `Checkbox`, `Radio` or `Switch`, an
9128
+ * inner `Field`, an input with an `id` of its own, markup of your own, or
9129
+ * nothing at all. Anything that puts the id from {@link useFieldLabelId} on
9130
+ * an element has to say so, or the label drops the `for` that names it, and
9131
+ * content that takes no id has nothing to do. Set under the same conditions
9132
+ * as {@link useFieldLabelId}, so a label wired by hand and a `grouped` or
9133
+ * `hasAddons` Field hear nothing. It reports from a layout effect, which a
9134
+ * server never runs and a hydrating client runs only after its first render,
9135
+ * so that render writes the `for` the way the server did.
9136
+ * Internal; not part of the public API.
9137
+ */
9138
+ const useReportFieldLabelFor = (takesFor) => {
9139
+ const report = React.useContext(FieldLabelForReportContext);
9140
+ useClientLayoutEffect(() => (takesFor ? report?.() : undefined), [report, takesFor]);
9141
+ };
9142
+ /** Provider for the labeled Field's report function, used internally by Field. */
9143
+ const FieldLabelForReportProvider = FieldLabelForReportContext.Provider;
9144
+ /**
9145
+ * The id a control with one input of its own renders with: the caller's
9146
+ * `id` when one arrived, otherwise the one a labeled Field offers (#495),
9147
+ * unless it has no input to put it on (`hasInput: false`, as in an `inline`
9148
+ * picker). It also tells that Field when it took the Field's id, through
9149
+ * {@link useReportFieldLabelFor}, so the label keeps its `for` (#1004). Used
9150
+ * by the single-control bases. Internal; not part of the public API.
9151
+ */
9152
+ const useFieldLabelTarget = (id, hasInput = true) => {
9153
+ const fieldLabelId = useFieldLabelId();
9154
+ const target = id ?? (hasInput ? fieldLabelId : undefined);
9155
+ useReportFieldLabelFor(fieldLabelId !== undefined && target === fieldLabelId);
9156
+ return target;
9157
+ };
9108
9158
  const RadiosContext = React.createContext(undefined);
9109
9159
  const CheckboxesContext = React.createContext(undefined);
9110
9160
  /**
@@ -9417,8 +9467,9 @@ const FieldComponent = ({ horizontal, grouped, hasAddons, narrow, label, labelSi
9417
9467
  const targetId = label && !userWiredLabel && !grouped && !hasAddons
9418
9468
  ? generatedId
9419
9469
  : undefined;
9420
- // A group control (Radios, Checkboxes, Rate, DateRangeInput) cannot take
9421
- // that `for`, so it points `aria-labelledby` at the label itself (#939).
9470
+ // A group control (Radios, Checkboxes, Rate, DateRangeInput and its base)
9471
+ // cannot take that `for`, so it points `aria-labelledby` at the label
9472
+ // itself (#939).
9422
9473
  // The label gets an id whenever the association is on, unless the caller
9423
9474
  // gave it one.
9424
9475
  const labelId = labelProps?.id ?? (targetId ? `${targetId}-label` : undefined);
@@ -9435,13 +9486,43 @@ const FieldComponent = ({ horizontal, grouped, hasAddons, narrow, label, labelSi
9435
9486
  const labelForTarget = userWiredLabel ? labelProps.htmlFor : targetId;
9436
9487
  const ownLabelFor = React.useMemo(() => ({ htmlFor: labelForTarget, id: labelId }), [labelForTarget, labelId]);
9437
9488
  const labelFor = label ? ownLabelFor : inheritedLabelFor;
9489
+ // Whether the label keeps its generated `for` (#1004). Content that takes
9490
+ // the Field's id says so from a layout effect, and this Field's own layout
9491
+ // effect runs after its content's in the same commit, so by then every
9492
+ // report has landed. Until it runs, on the server and in the first render
9493
+ // while hydrating, the label writes the `for` as it always has. From then
9494
+ // on it keeps the `for` only while some content holds the id, and content
9495
+ // that mounts or changes later reports when it does. Counted in a ref, and
9496
+ // state is set only once settled, so content that takes the id renders
9497
+ // the Field just once.
9498
+ const takersRef = React.useRef(0);
9499
+ const settledRef = React.useRef(false);
9500
+ const [forTaken, setForTaken] = React.useState(true);
9501
+ const settle = React.useCallback(() => {
9502
+ if (settledRef.current)
9503
+ setForTaken(takersRef.current > 0);
9504
+ }, []);
9505
+ const reportLabelFor = React.useCallback(() => {
9506
+ takersRef.current += 1;
9507
+ settle();
9508
+ return () => {
9509
+ takersRef.current -= 1;
9510
+ settle();
9511
+ };
9512
+ }, [settle]);
9513
+ useClientLayoutEffect(() => {
9514
+ settledRef.current = true;
9515
+ if (targetId)
9516
+ settle();
9517
+ }, [targetId, settle]);
9518
+ const renderedTargetId = forTaken ? targetId : undefined;
9438
9519
  let renderedLabel = null;
9439
9520
  if (label) {
9440
9521
  if (horizontal) {
9441
- renderedLabel = (jsxRuntime.jsx(FieldLabel, { size: effectiveLabelSize, children: jsxRuntime.jsx("label", { htmlFor: targetId, ...labelProps, id: labelId, className: classNames(labelClass, labelProps?.className), style: labelProps?.style, children: label }) }));
9522
+ renderedLabel = (jsxRuntime.jsx(FieldLabel, { size: effectiveLabelSize, children: jsxRuntime.jsx("label", { htmlFor: renderedTargetId, ...labelProps, id: labelId, className: classNames(labelClass, labelProps?.className), style: labelProps?.style, children: label }) }));
9442
9523
  }
9443
9524
  else {
9444
- renderedLabel = (jsxRuntime.jsx("label", { htmlFor: targetId, ...labelProps, id: labelId, className: classNames(labelClass, labelProps?.className), style: { display: 'block', ...(labelProps?.style || {}) }, children: label }));
9525
+ renderedLabel = (jsxRuntime.jsx("label", { htmlFor: renderedTargetId, ...labelProps, id: labelId, className: classNames(labelClass, labelProps?.className), style: { display: 'block', ...(labelProps?.style || {}) }, children: label }));
9445
9526
  }
9446
9527
  }
9447
9528
  // If horizontal, wrap children in FieldBody (unless the user already provided
@@ -9464,7 +9545,7 @@ const FieldComponent = ({ horizontal, grouped, hasAddons, narrow, label, labelSi
9464
9545
  content = jsxRuntime.jsx(FieldBody, { children: children });
9465
9546
  }
9466
9547
  }
9467
- return (jsxRuntime.jsx(FieldProvider, { value: true, children: jsxRuntime.jsx(FieldLabelIdProvider, { value: targetId, children: jsxRuntime.jsx(FieldLabelElementIdProvider, { value: targetId ? labelId : undefined, children: jsxRuntime.jsx(FieldLabelForProvider, { value: labelFor, children: jsxRuntime.jsxs("div", { className: fieldClass, ...rest, children: [renderedLabel, content] }) }) }) }) }));
9548
+ return (jsxRuntime.jsx(FieldProvider, { value: true, children: jsxRuntime.jsx(FieldLabelIdProvider, { value: targetId, children: jsxRuntime.jsx(FieldLabelElementIdProvider, { value: targetId ? labelId : undefined, children: jsxRuntime.jsx(FieldLabelForProvider, { value: labelFor, children: jsxRuntime.jsx(FieldLabelForReportProvider, { value: targetId ? reportLabelFor : undefined, children: jsxRuntime.jsxs("div", { className: fieldClass, ...rest, children: [renderedLabel, content] }) }) }) }) }) }));
9468
9549
  };
9469
9550
  FieldLabel.displayName = 'FieldLabel';
9470
9551
  FieldBody.displayName = 'FieldBody';
@@ -9482,8 +9563,10 @@ const Field = withSubComponents(FieldComponent, {
9482
9563
  * generation entirely: the user has taken over the association (#495 presence
9483
9564
  * semantics). When the control renders no label of its own, it adopts the id
9484
9565
  * a labeled Field around it offers, the way the bases do, so that Field's
9485
- * label names it (#939); a user `id` still wins there. With `needsLabelId`
9486
- * it also returns the id of whichever label names the control (#981).
9566
+ * label names it (#939); a user `id` still wins there. It tells that Field
9567
+ * when the control took its id, since the Field's label drops a `for`
9568
+ * nothing took (#1004). With `needsLabelId` it also returns the id of
9569
+ * whichever label names the control (#981).
9487
9570
  * Internal; not part of the public API.
9488
9571
  */
9489
9572
  function useAutoLabelId({ label, id, labelProps, rendersLabel, hasInput = true, needsLabelId = false, }) {
@@ -9504,6 +9587,9 @@ function useAutoLabelId({ label, id, labelProps, rendersLabel, hasInput = true,
9504
9587
  const userWired = !!labelProps && 'htmlFor' in labelProps;
9505
9588
  const adopted = !active && hasInput ? fieldLabelId : undefined;
9506
9589
  const controlId = id ?? (active && !userWired ? generatedId : adopted);
9590
+ // Tells a labeled Field around the control when its label's `for` names
9591
+ // the control, since it drops a `for` nothing took (#1004).
9592
+ useReportFieldLabelFor(fieldLabelId !== undefined && controlId === fieldLabelId);
9507
9593
  const ownLabelProps = { htmlFor: controlId, ...labelProps };
9508
9594
  const labelTarget = active ? ownLabelProps.htmlFor : fieldLabelFor.htmlFor;
9509
9595
  const labelled = !!controlId && labelTarget === controlId;
@@ -11566,7 +11652,9 @@ const InputBase = React.forwardRef(({ color, size, isRounded, isStatic, isHovere
11566
11652
  color,
11567
11653
  ...props,
11568
11654
  });
11569
- const fieldLabelId = useFieldLabelId();
11655
+ // A labeled Field's generated id when no user id arrived (rest.id may be
11656
+ // an undefined own key), reported to that Field (#1004).
11657
+ const id = useFieldLabelTarget(rest.id);
11570
11658
  const mainClass = usePrefixedClassNames('input', {
11571
11659
  [`is-${color}`]: !!color,
11572
11660
  [`is-${size}`]: !!size,
@@ -11578,9 +11666,8 @@ const InputBase = React.forwardRef(({ color, size, isRounded, isStatic, isHovere
11578
11666
  });
11579
11667
  const inputClass = classNames(mainClass, bulmaHelperClasses, className);
11580
11668
  return (jsxRuntime.jsx("input", { ref: ref, className: inputClass, disabled: disabled, readOnly: readOnly, ...rest,
11581
- // After the spread: a labeled Field's generated id is adopted only
11582
- // when no user id arrived (rest.id may be an undefined own key).
11583
- id: rest.id ?? fieldLabelId }));
11669
+ // After the spread, which may carry an undefined id key.
11670
+ id: id }));
11584
11671
  });
11585
11672
  InputBase.displayName = 'InputBase';
11586
11673
 
@@ -11597,7 +11684,9 @@ const SelectBase = React.forwardRef(({ color, size, isRounded, isLoading, isActi
11597
11684
  color,
11598
11685
  ...props,
11599
11686
  });
11600
- const fieldLabelId = useFieldLabelId();
11687
+ // A labeled Field's generated id when no user id arrived (rest.id may be
11688
+ // an undefined own key), reported to that Field (#1004).
11689
+ const id = useFieldLabelTarget(rest.id);
11601
11690
  const mainClass = usePrefixedClassNames('select', {
11602
11691
  [`is-${color}`]: !!color,
11603
11692
  [`is-${size}`]: !!size,
@@ -11623,9 +11712,9 @@ const SelectBase = React.forwardRef(({ color, size, isRounded, isLoading, isActi
11623
11712
  selectProps.size = multipleSize;
11624
11713
  }
11625
11714
  return (jsxRuntime.jsx("div", { className: selectClass, children: jsxRuntime.jsx("select", { ref: ref, className: innerSelectClass || undefined, ...selectProps,
11626
- // After the spread: a labeled Field's generated id is adopted only
11627
- // when no user id arrived; the id belongs on the inner <select>.
11628
- id: selectProps.id ?? fieldLabelId, children: children }) }));
11715
+ // After the spread, which may carry an undefined id key; the id
11716
+ // belongs on the inner <select>.
11717
+ id: id, children: children }) }));
11629
11718
  });
11630
11719
  SelectBase.displayName = 'SelectBase';
11631
11720
 
@@ -11642,7 +11731,9 @@ const TextAreaBase = React.forwardRef(({ color, size, isRounded, isStatic, isHov
11642
11731
  color,
11643
11732
  ...props,
11644
11733
  });
11645
- const fieldLabelId = useFieldLabelId();
11734
+ // A labeled Field's generated id when no user id arrived (rest.id may be
11735
+ // an undefined own key), reported to that Field (#1004).
11736
+ const id = useFieldLabelTarget(rest.id);
11646
11737
  // Note: `is-loading` is intentionally NOT applied to the <textarea> itself —
11647
11738
  // Bulma documents `<div class="control is-loading">` as the loading pattern
11648
11739
  // for textareas, not `<textarea class="textarea is-loading">`. The convenience
@@ -11659,9 +11750,8 @@ const TextAreaBase = React.forwardRef(({ color, size, isRounded, isStatic, isHov
11659
11750
  });
11660
11751
  const textareaClass = classNames(mainClass, bulmaHelperClasses, className);
11661
11752
  return (jsxRuntime.jsx("textarea", { ref: ref, className: textareaClass, disabled: disabled, readOnly: readOnly, rows: rows, ...rest,
11662
- // After the spread: a labeled Field's generated id is adopted only
11663
- // when no user id arrived (rest.id may be an undefined own key).
11664
- id: rest.id ?? fieldLabelId }));
11753
+ // After the spread, which may carry an undefined id key.
11754
+ id: id }));
11665
11755
  });
11666
11756
  TextAreaBase.displayName = 'TextAreaBase';
11667
11757
 
@@ -14156,8 +14246,7 @@ const DateInputBase = React.forwardRef((props, ref) => {
14156
14246
  // when the caller set none, as InputBase does, and the popover's ids
14157
14247
  // follow it. Inline there is no input to name, so nothing takes the
14158
14248
  // Field's id or builds on it.
14159
- const fieldLabelId = useFieldLabelId();
14160
- const id = idProp ?? (inline ? undefined : fieldLabelId);
14249
+ const id = useFieldLabelTarget(idProp, !inline);
14161
14250
  // The launcher gives way to the loading spinner of a Control this sits in.
14162
14251
  const controlLoading = useControlLoading();
14163
14252
  const triggerIcon = triggerIconProp ?? !controlLoading;
@@ -15338,8 +15427,7 @@ const TimeInputBase = React.forwardRef((props, ref) => {
15338
15427
  // when the caller set none, as InputBase does, and the popover's ids
15339
15428
  // follow it. Inline there is no input to name, so nothing takes the
15340
15429
  // Field's id or builds on it.
15341
- const fieldLabelId = useFieldLabelId();
15342
- const id = idProp ?? (inline ? undefined : fieldLabelId);
15430
+ const id = useFieldLabelTarget(idProp, !inline);
15343
15431
  // The launcher gives way to the loading spinner of a Control this sits in.
15344
15432
  const controlLoading = useControlLoading();
15345
15433
  const triggerIcon = triggerIconProp ?? !controlLoading;
@@ -15656,8 +15744,7 @@ const DateTimeInputBase = React.forwardRef((props, ref) => {
15656
15744
  // when the caller set none, as InputBase does, and the popover's ids
15657
15745
  // follow it. Inline there is no input to name, so nothing takes the
15658
15746
  // Field's id or builds on it.
15659
- const fieldLabelId = useFieldLabelId();
15660
- const id = idProp ?? (inline ? undefined : fieldLabelId);
15747
+ const id = useFieldLabelTarget(idProp, !inline);
15661
15748
  // The launcher gives way to the loading spinner of a Control this sits in.
15662
15749
  const controlLoading = useControlLoading();
15663
15750
  const triggerIcon = triggerIconProp ?? !controlLoading;
@@ -16016,6 +16103,11 @@ const today = () => startOfDay(new Date());
16016
16103
  /**
16017
16104
  * Raw DateRangeInput: the two inputs and the popover calendar without
16018
16105
  * Field/Control wrapping. Use `DateRangeInput` for the convenience wrapper.
16106
+ * Composed in a labeled `Field`, its `role="group"` root points
16107
+ * `aria-labelledby` at that `Field`'s label, `inline` too, as the wrapper's
16108
+ * does, and each input keeps its own name. An `aria-label` or
16109
+ * `aria-labelledby` you give it wins over the label, and an `aria-labelledby`
16110
+ * key counts even when undefined, since it is spread over the group's own.
16019
16111
  *
16020
16112
  * @function
16021
16113
  * @param {DateRangeInputBaseProps} props
@@ -16056,6 +16148,15 @@ const DateRangeInputBase = React.forwardRef((props, ref) => {
16056
16148
  const reactId = React.useId();
16057
16149
  const popoverId = id ? `${id}-popover` : `picker-${reactId}`;
16058
16150
  const { bulmaHelperClasses, rest: cleanRest } = useBulmaClasses(rest);
16151
+ // Two inputs can't share a labeled Field's `for`, so inside one the group
16152
+ // points `aria-labelledby` at that Field's label, as `DateRangeInput`
16153
+ // does, in every mode. A name the caller gave the group wins, and so does
16154
+ // the `aria-labelledby` that wrapper always passes, so it decides there.
16155
+ const { ariaLabelledBy } = useAutoLabelledBy({
16156
+ label: undefined,
16157
+ rendersLabel: false,
16158
+ callerProps: rest,
16159
+ });
16059
16160
  const { shouldUseNative } = useNativeMobilePicker({
16060
16161
  force: mobileNative === 'auto' ? undefined : mobileNative,
16061
16162
  });
@@ -16244,14 +16345,14 @@ const DateRangeInputBase = React.forwardRef((props, ref) => {
16244
16345
  };
16245
16346
  const minIso = min ? isoDay(lowerBound) : undefined;
16246
16347
  const maxIso = max ? isoDay(max) : undefined;
16247
- return (jsxRuntime.jsxs("div", { ...cleanRest, ref: containerRef, role: "group", className: classNames(containerClass, bulmaHelperClasses, className), onFocus: onFocus, onFocusCapture: onFocusCapture, children: [jsxRuntime.jsxs("div", { className: fieldClass, children: [jsxRuntime.jsx("input", { ref: combinedRef, type: "date", id: id, "aria-label": t.rangeStart, className: inputClass, value: isoDay(start), onChange: nativeChange(commitStart, isBlockedDay), min: minIso, max: maxIso, disabled: disabled, readOnly: readOnly, required: required }), separator, jsxRuntime.jsx("input", { ref: endRef, type: "date", id: id ? `${id}-end` : undefined, "aria-label": t.rangeEnd, className: inputClass, value: isoDay(end), onChange: nativeChange(commitEnd, isBlockedEnd), min: start ? isoDay(start) : minIso, max: maxIso, disabled: disabled, readOnly: readOnly, required: required })] }), hiddenInputs] }));
16348
+ return (jsxRuntime.jsxs("div", { "aria-labelledby": ariaLabelledBy, ...cleanRest, ref: containerRef, role: "group", className: classNames(containerClass, bulmaHelperClasses, className), onFocus: onFocus, onFocusCapture: onFocusCapture, children: [jsxRuntime.jsxs("div", { className: fieldClass, children: [jsxRuntime.jsx("input", { ref: combinedRef, type: "date", id: id, "aria-label": t.rangeStart, className: inputClass, value: isoDay(start), onChange: nativeChange(commitStart, isBlockedDay), min: minIso, max: maxIso, disabled: disabled, readOnly: readOnly, required: required }), separator, jsxRuntime.jsx("input", { ref: endRef, type: "date", id: id ? `${id}-end` : undefined, "aria-label": t.rangeEnd, className: inputClass, value: isoDay(end), onChange: nativeChange(commitEnd, isBlockedEnd), min: start ? isoDay(start) : minIso, max: maxIso, disabled: disabled, readOnly: readOnly, required: required })] }), hiddenInputs] }));
16248
16349
  }
16249
16350
  const calendar = (jsxRuntime.jsx(Calendar, { range: range, onRangeSelect: handleRangeSelect, allowDisabledInRange: allowDisabledInRange, focusedDate: focusedDate, onFocusedDateChange: setFocusedDate, min: min, max: max, shouldDisableDate: shouldDisableDate, unselectableDates: unselectableDates, firstDayOfWeek: firstDayOfWeek, locale: locale, dayNames: dayNames, monthNames: monthNames, nearbyMonthDays: nearbyMonthDays, color: color, size: size,
16250
16351
  // The popover panel takes `popoverId`, so the calendar inside it takes
16251
16352
  // one of its own. Inline there is no panel.
16252
16353
  id: inline ? popoverId : `${popoverId}-cal`, autoFocusCell: open, labels: labels }));
16253
16354
  if (inline) {
16254
- return (jsxRuntime.jsxs("div", { ...cleanRest, ref: containerRef, role: "group", className: classNames(containerClass, bulmaHelperClasses, className), onFocus: onFocus, onFocusCapture: onFocusCapture, children: [calendar, hiddenInputs] }));
16355
+ return (jsxRuntime.jsxs("div", { "aria-labelledby": ariaLabelledBy, ...cleanRest, ref: containerRef, role: "group", className: classNames(containerClass, bulmaHelperClasses, className), onFocus: onFocus, onFocusCapture: onFocusCapture, children: [calendar, hiddenInputs] }));
16255
16356
  }
16256
16357
  const canOpen = !!popover && !disabled && !readOnly;
16257
16358
  const inputReadOnly = !!readOnly || !editable;
@@ -16286,7 +16387,7 @@ const DateRangeInputBase = React.forwardRef((props, ref) => {
16286
16387
  readOnly: inputReadOnly,
16287
16388
  required,
16288
16389
  };
16289
- return (jsxRuntime.jsxs("div", { ...cleanRest, ref: containerRef, role: "group", className: classNames(containerClass, bulmaHelperClasses, className), onFocus: handleFocus, onFocusCapture: handleFocusCapture, children: [jsxRuntime.jsxs("div", { className: fieldClass, onMouseDown: handleFieldMouseDown, children: [jsxRuntime.jsx("input", { ...comboboxProps, ref: combinedRef, id: id, "aria-label": t.rangeStart, value: startText, ...startHandlers }), separator, jsxRuntime.jsx("input", { ...comboboxProps, ref: endRef, id: id ? `${id}-end` : undefined, "aria-label": t.rangeEnd, value: endText, ...endHandlers })] }), popover && triggerIcon && (jsxRuntime.jsx("button", { type: "button", className: triggerClass,
16390
+ return (jsxRuntime.jsxs("div", { "aria-labelledby": ariaLabelledBy, ...cleanRest, ref: containerRef, role: "group", className: classNames(containerClass, bulmaHelperClasses, className), onFocus: handleFocus, onFocusCapture: handleFocusCapture, children: [jsxRuntime.jsxs("div", { className: fieldClass, onMouseDown: handleFieldMouseDown, children: [jsxRuntime.jsx("input", { ...comboboxProps, ref: combinedRef, id: id, "aria-label": t.rangeStart, value: startText, ...startHandlers }), separator, jsxRuntime.jsx("input", { ...comboboxProps, ref: endRef, id: id ? `${id}-end` : undefined, "aria-label": t.rangeEnd, value: endText, ...endHandlers })] }), popover && triggerIcon && (jsxRuntime.jsx("button", { type: "button", className: triggerClass,
16290
16391
  // Disabled whenever the popover can't open, so a click can.
16291
16392
  onClick: () => setOpen(!open), disabled: !canOpen, "aria-label": t.chooseDateRange, "aria-haspopup": "dialog", "aria-controls": popoverId, "aria-expanded": open, tabIndex: canOpen ? 0 : -1, children: jsxRuntime.jsx(Icon, { name: triggerIconName, size: size }) })), popover && (jsxRuntime.jsx(PickerPopover, { isOpen: open, onClose: handlePopoverClose, anchorRef: containerRef, position: position, appendToBody: appendToBody, ariaLabel: t.chooseDateRange, id: popoverId, restoreFocusRef: restoreFocusRef, initialFocusSelector: CALENDAR_FOCUSED_CELL, children: calendar })), hiddenInputs] }));
16292
16393
  });
@@ -16427,8 +16528,15 @@ const GridComponent = ({ isFixed = false, gap, columnGap, rowGap, minCol, fixedC
16427
16528
  };
16428
16529
  const Grid = withSubComponents(GridComponent, { Cell }, 'Grid');
16429
16530
 
16430
- // --- FULL Bulma v1 CSS variable keys (auto-generated from CSSVAR_KEYS) ---
16431
- const bulmaCssVars = [
16531
+ // --- Bulma v1 CSS variables Theme sets (originally generated from
16532
+ // CSSVAR_KEYS), in two lists by where Bulma declares them ---
16533
+ /**
16534
+ * Variables a value set on an ancestor reaches. Bulma declares them on
16535
+ * `:root` (or a theme scope), or on no component in its plain state, so the
16536
+ * value Theme writes on its wrapper or at `:root` is the one the components
16537
+ * under it use.
16538
+ */
16539
+ const bulmaGlobalVars = [
16432
16540
  // scheme
16433
16541
  '--bulma-scheme-h',
16434
16542
  '--bulma-scheme-s',
@@ -16545,6 +16653,36 @@ const bulmaCssVars = [
16545
16653
  '--bulma-skeleton-block-min-height',
16546
16654
  '--bulma-skeleton-lines-gap',
16547
16655
  '--bulma-skeleton-line-height',
16656
+ // control
16657
+ '--bulma-control-radius',
16658
+ '--bulma-control-radius-small',
16659
+ '--bulma-control-border-width',
16660
+ '--bulma-control-height',
16661
+ '--bulma-control-line-height',
16662
+ '--bulma-control-padding-vertical',
16663
+ '--bulma-control-padding-horizontal',
16664
+ '--bulma-control-size',
16665
+ '--bulma-control-focus-shadow-l',
16666
+ // columns
16667
+ '--bulma-column-gap',
16668
+ // grid
16669
+ '--bulma-grid-cell-column-start',
16670
+ ];
16671
+ /**
16672
+ * Variables Bulma declares on the component's own element, such as
16673
+ * `--bulma-card-radius` on `.card`. An element that declares a variable uses
16674
+ * its own value whatever its ancestors set, so a value Theme writes for one
16675
+ * of these, on its wrapper or at `:root`, never reaches the component.
16676
+ *
16677
+ * They stay in `BulmaVars`, and so stay valid `bulmaVars` keys and variable
16678
+ * props, because taking a key out would be a breaking change. Setting one
16679
+ * warns in development instead; see `warnComponentVars`.
16680
+ *
16681
+ * `scripts/css-var-scopes.test.mjs` holds this split to Bulma's compiled
16682
+ * stylesheet in both directions, so a Bulma upgrade that moves a variable
16683
+ * fails there.
16684
+ */
16685
+ const bulmaComponentVars = [
16548
16686
  // breadcrumb
16549
16687
  '--bulma-breadcrumb-item-color',
16550
16688
  '--bulma-breadcrumb-item-hover-color',
@@ -16894,16 +17032,6 @@ const bulmaCssVars = [
16894
17032
  '--bulma-subtitle-line-height',
16895
17033
  '--bulma-subtitle-strong-color',
16896
17034
  '--bulma-subtitle-strong-weight',
16897
- // control
16898
- '--bulma-control-radius',
16899
- '--bulma-control-radius-small',
16900
- '--bulma-control-border-width',
16901
- '--bulma-control-height',
16902
- '--bulma-control-line-height',
16903
- '--bulma-control-padding-vertical',
16904
- '--bulma-control-padding-horizontal',
16905
- '--bulma-control-size',
16906
- '--bulma-control-focus-shadow-l',
16907
17035
  // file
16908
17036
  '--bulma-file-radius',
16909
17037
  '--bulma-file-name-border-color',
@@ -16954,14 +17082,11 @@ const bulmaCssVars = [
16954
17082
  '--bulma-input-icon-hover-color',
16955
17083
  '--bulma-input-icon-focus-color',
16956
17084
  '--bulma-input-radius',
16957
- // columns
16958
- '--bulma-column-gap',
16959
17085
  // grid
16960
17086
  '--bulma-grid-gap',
16961
17087
  '--bulma-grid-column-count',
16962
17088
  '--bulma-grid-column-min',
16963
17089
  '--bulma-grid-cell-column-span',
16964
- '--bulma-grid-cell-column-start',
16965
17090
  // footer
16966
17091
  '--bulma-footer-background-color',
16967
17092
  '--bulma-footer-color',
@@ -16987,6 +17112,8 @@ const bulmaCssVars = [
16987
17112
  '--bulma-section-padding-medium',
16988
17113
  '--bulma-section-padding-large',
16989
17114
  ];
17115
+ /** Every Bulma CSS variable Theme accepts: the two lists above. */
17116
+ const bulmaCssVars = [...bulmaGlobalVars, ...bulmaComponentVars];
16990
17117
  /**
16991
17118
  * Convert a Bulma CSS variable name to a camelCase prop name.
16992
17119
  * @param {string} varName - CSS variable name (e.g., '--bulma-primary-h').
@@ -17105,6 +17232,44 @@ const themeColumnGapVar = (columnGap) => {
17105
17232
  `bulmaVars={{ '--bulma-column-gap': '${columnGap}' }} instead.`);
17106
17233
  return columnGap;
17107
17234
  };
17235
+ /**
17236
+ * `bulmaComponentVars` as a lookup, built by `warnComponentVars` the first
17237
+ * time it is needed.
17238
+ */
17239
+ let componentVarKeys;
17240
+ /**
17241
+ * Warn in development when a Theme is given variables Bulma declares on the
17242
+ * component itself (`bulmaComponentVars`), whether through `bulmaVars` or a
17243
+ * variable prop such as `cardRadius`. Theme writes them where they can never
17244
+ * win, so nothing changes on the page, and saying so is the only way to find
17245
+ * out short of reading Bulma's stylesheet.
17246
+ *
17247
+ * Keyed by the set of variables, so a Theme that keeps passing the same ones
17248
+ * warns once, and a different set warns again. An empty value writes nothing,
17249
+ * so it is not reported.
17250
+ *
17251
+ * All of this is development-only, so it returns before doing anything in
17252
+ * production, and it builds its lookup on the first development call rather
17253
+ * than when the module loads.
17254
+ */
17255
+ const warnComponentVars = (vars) => {
17256
+ if (!isDev()) {
17257
+ return;
17258
+ }
17259
+ const keys = (componentVarKeys ?? (componentVarKeys = new Set(bulmaComponentVars)));
17260
+ const inert = Object.entries(vars)
17261
+ .filter(([key, value]) => value && keys.has(key))
17262
+ .map(([key]) => key)
17263
+ .sort();
17264
+ if (inert.length === 0) {
17265
+ return;
17266
+ }
17267
+ const one = inert.length === 1;
17268
+ warnOnce(`Theme:component-vars:${inert.join(',')}`, `[bestax-bulma] <Theme>: Bulma declares ${inert.join(', ')} on the ` +
17269
+ `component itself, so a value set on Theme never reaches ` +
17270
+ `${one ? 'it' : 'them'}. Set ${one ? 'it' : 'them'} on that ` +
17271
+ 'component instead, with className or style, or through Sass.');
17272
+ };
17108
17273
  /** The one `<style>` element every `isRoot` Theme writes into. */
17109
17274
  const ROOT_STYLE_ID = 'bestax-bulma-theme-vars';
17110
17275
  /**
@@ -17266,6 +17431,12 @@ const Theme = ({ bulmaVars = {}, children, className, isRoot = false, colorMode,
17266
17431
  }
17267
17432
  return vars;
17268
17433
  }, [bulmaVars, bulmaVarProps, radiusVar, columnGapVar]);
17434
+ // From an effect rather than the render body, so rendering does none of
17435
+ // this work, and a server render none at all. In production it returns
17436
+ // at its development check before looking at the variables.
17437
+ React.useEffect(() => {
17438
+ warnComponentVars(mergedVars);
17439
+ }, [mergedVars]);
17269
17440
  // This Theme's place among root Themes; see `rootThemeRules`.
17270
17441
  const [rootOrder] = React.useState(() => nextRootOrder++);
17271
17442
  // The `:root` rules this Theme contributes, or '' when it contributes none.