@allxsmith/bestax-bulma 5.26.0 → 5.26.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
@@ -12190,7 +12190,7 @@ const Calendar = ({ value, focusedDate, onSelect, onFocusedDateChange, min, max,
12190
12190
  Calendar.displayName = 'Calendar';
12191
12191
 
12192
12192
  const isBrowser = typeof window !== 'undefined';
12193
- const PickerPopover = ({ isOpen, onClose, anchorRef, children, position = 'bottom-left', appendToBody = false, className, trapFocus = true, closeOnClickOutside = true, closeOnEscape = true, ariaLabel, ariaLabelledBy, role = 'dialog', id, }) => {
12193
+ const PickerPopover = ({ isOpen, onClose, anchorRef, children, position = 'bottom-left', appendToBody = false, className, trapFocus = true, closeOnClickOutside = true, closeOnEscape = true, ariaLabel, ariaLabelledBy, role = 'dialog', id, restoreFocusRef, }) => {
12194
12194
  const panelRef = useRef(null);
12195
12195
  const resolved = useAnchoredPosition(anchorRef, panelRef, {
12196
12196
  active: isOpen,
@@ -12227,7 +12227,10 @@ const PickerPopover = ({ isOpen, onClose, anchorRef, children, position = 'botto
12227
12227
  document.addEventListener('keydown', handler);
12228
12228
  return () => document.removeEventListener('keydown', handler);
12229
12229
  }, [isOpen, closeOnEscape, onClose]);
12230
- useFocusTrap(panelRef, { active: isOpen && trapFocus });
12230
+ useFocusTrap(panelRef, {
12231
+ active: isOpen && trapFocus,
12232
+ restoreFocus: restoreFocusRef ?? true,
12233
+ });
12231
12234
  const panelClass = usePrefixedClassNames('picker-popover', {
12232
12235
  'is-active': isOpen,
12233
12236
  [`is-${resolved.position}`]: true,
@@ -12632,6 +12635,37 @@ function useSegmentedEntry(params) {
12632
12635
  // change. Kept in a ref because key handlers read+update synchronously
12633
12636
  // within the same event tick.
12634
12637
  const typedDigitsRef = useRef('');
12638
+ // The text focus seeded an empty picker with, until the user edits it or
12639
+ // leaves. While the text still matches it, nothing has been typed.
12640
+ const seedRef = useRef(null);
12641
+ // Whether the input's current focus is the one a closing popover handed
12642
+ // back, until focus leaves the picker.
12643
+ const handedBackRef = useRef(false);
12644
+ // A seed the popover never turned into a value closes with it, wherever
12645
+ // focus goes, so a dismissed empty field stays empty.
12646
+ //
12647
+ // As the popover closes, its focus trap hands focus back to the input. That
12648
+ // focus is not the user arriving: it must not open the popover again under
12649
+ // `openOnFocus`, or seed an empty picker that leaving would then commit.
12650
+ // `closingRef` is set in the layout phase of the commit that closes it and
12651
+ // cleared by that commit's effects, and React runs a commit's effect
12652
+ // cleanups, the trap's among them, before any of its effects, so a focus
12653
+ // in between is the one handed back.
12654
+ const closingRef = useRef(false);
12655
+ const wasOpenRef = useRef(isOpen);
12656
+ useLayoutEffect(() => {
12657
+ if (wasOpenRef.current && !isOpen) {
12658
+ closingRef.current = true;
12659
+ if (!value && seedRef.current !== null && text === seedRef.current) {
12660
+ setText('');
12661
+ }
12662
+ seedRef.current = null;
12663
+ }
12664
+ wasOpenRef.current = isOpen;
12665
+ }, [isOpen, value, text, setText]);
12666
+ useEffect(() => {
12667
+ closingRef.current = false;
12668
+ }, [isOpen]);
12635
12669
  // Segment mode is unavailable for disabled / read-only / non-editable
12636
12670
  // pickers and for Intl-options / variable-width formats (segmentMap null).
12637
12671
  const segmentEditable = !!segmentMap && !!editable && !disabled && !readOnly;
@@ -12688,6 +12722,7 @@ function useSegmentedEntry(params) {
12688
12722
  // segment mode is inactive.
12689
12723
  if (activeSegmentIdx !== null && segmentEditable)
12690
12724
  return;
12725
+ seedRef.current = null;
12691
12726
  setText(e.target.value);
12692
12727
  }, [activeSegmentIdx, segmentEditable, setText]);
12693
12728
  const handleBlur = useCallback((e) => {
@@ -12705,6 +12740,16 @@ function useSegmentedEntry(params) {
12705
12740
  }
12706
12741
  setActiveSegmentIdx(null);
12707
12742
  typedDigitsRef.current = '';
12743
+ seedRef.current = null;
12744
+ const handedBack = handedBackRef.current;
12745
+ handedBackRef.current = false;
12746
+ // Leaving after a dismiss commits only what was typed since. Text that
12747
+ // still shows the value wasn't, and re-parsing it could drop what the
12748
+ // format leaves out, such as seconds.
12749
+ if (handedBack && value && text === formatFn(value, format, locale)) {
12750
+ onBlur?.(e);
12751
+ return;
12752
+ }
12708
12753
  const parsed = tryParse(text);
12709
12754
  if (parsed && isAllowed(parsed)) {
12710
12755
  commitValue(parsed);
@@ -12727,13 +12772,19 @@ function useSegmentedEntry(params) {
12727
12772
  onBlur,
12728
12773
  ]);
12729
12774
  const handleFocus = useCallback((e) => {
12730
- if (openOnFocus && popover && !disabled && !readOnly)
12775
+ const handedBack = closingRef.current;
12776
+ handedBackRef.current = handedBack;
12777
+ if (!handedBack && openOnFocus && popover && !disabled && !readOnly) {
12731
12778
  setOpen(true);
12779
+ }
12732
12780
  // Enter segment mode: prime an initial value (so editing works even when
12733
- // empty), seed the text, and highlight the first editable segment.
12781
+ // empty), seed the text, and highlight the first editable segment. The
12782
+ // segment base doesn't need the seed, so focus handed back skips it.
12734
12783
  if (segmentEditable && segmentMap) {
12735
- if (!value) {
12736
- setText(formatFn(makeBaseDate(), format, locale));
12784
+ if (!value && !handedBack) {
12785
+ const seed = formatFn(makeBaseDate(), format, locale);
12786
+ seedRef.current = seed;
12787
+ setText(seed);
12737
12788
  }
12738
12789
  typedDigitsRef.current = '';
12739
12790
  setActiveSegmentIdx(segmentMap.editable[0]);
@@ -13200,7 +13251,7 @@ const DateInputBase = forwardRef((props, ref) => {
13200
13251
  return (jsxs("div", { ref: containerRef, className: classNames(containerClass, bulmaHelperClasses, className), ...cleanRest, children: [jsx("input", { ref: combinedRef, type: "text", role: "combobox", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": popoverId, autoComplete: "off", className: inputClass, value: text, placeholder: placeholder, disabled: disabled, readOnly: inputReadOnlyAttr, name: name, form: form, required: required, id: id, ...inputHandlers }), popover && triggerIcon && (jsx("button", { type: "button", className: triggerClass, onClick: () => {
13201
13252
  if (canOpen)
13202
13253
  setOpen(!open);
13203
- }, disabled: !canOpen, "aria-label": chooseLabel, "aria-haspopup": "dialog", "aria-controls": popoverId, "aria-expanded": open, tabIndex: canOpen ? 0 : -1, children: jsx(Icon, { name: triggerIconName, size: size }) })), popover && (jsx(PickerPopover, { isOpen: open, onClose: handlePopoverClose, anchorRef: containerRef, position: position, appendToBody: appendToBody, ariaLabel: chooseLabel, id: popoverId, children: calendar }))] }));
13254
+ }, disabled: !canOpen, "aria-label": chooseLabel, "aria-haspopup": "dialog", "aria-controls": popoverId, "aria-expanded": open, tabIndex: canOpen ? 0 : -1, children: jsx(Icon, { name: triggerIconName, size: size }) })), popover && (jsx(PickerPopover, { isOpen: open, onClose: handlePopoverClose, anchorRef: containerRef, position: position, appendToBody: appendToBody, ariaLabel: chooseLabel, id: popoverId, restoreFocusRef: inputRef, children: calendar }))] }));
13204
13255
  });
13205
13256
  DateInputBase.displayName = 'DateInputBase';
13206
13257
 
@@ -14173,9 +14224,6 @@ const TimeInputBase = forwardRef((props, ref) => {
14173
14224
  const mobileFooterClass = usePrefixedClassNames('timeinput-footer-mobile');
14174
14225
  const mobileFooterResetClass = usePrefixedClassNames('timeinput-footer-reset');
14175
14226
  const mobileFooterDoneClass = usePrefixedClassNames('timeinput-footer-done');
14176
- // Set from the moment the popover starts to close until the close has
14177
- // committed. See `setOpenFromInput`.
14178
- const closingRef = useRef(false);
14179
14227
  const setOpen = useCallback((next) => {
14180
14228
  setOpenState(prev => {
14181
14229
  if (prev === next)
@@ -14185,26 +14233,11 @@ const TimeInputBase = forwardRef((props, ref) => {
14185
14233
  onOpen?.();
14186
14234
  }
14187
14235
  else {
14188
- closingRef.current = true;
14189
14236
  onClose?.();
14190
14237
  }
14191
14238
  return next;
14192
14239
  });
14193
14240
  }, [onOpen, onClose, value]);
14194
- // React runs a commit's effect cleanups before any of its effects, so on a
14195
- // close this runs after the popover's focus trap has handed focus back.
14196
- useEffect(() => {
14197
- closingRef.current = false;
14198
- }, [open]);
14199
- // As the popover closes, its focus trap hands focus back to the input.
14200
- // That focus is not the user arriving, so under `openOnFocus` it must not
14201
- // open the popover again. The input asks to open only on focus, click or
14202
- // ArrowDown, so a request while a close commits can only be that one.
14203
- const setOpenFromInput = useCallback((next) => {
14204
- if (next && closingRef.current)
14205
- return;
14206
- setOpen(next);
14207
- }, [setOpen]);
14208
14241
  useEffect(() => {
14209
14242
  setText(value ? formatTime(value, defaultFormat, locale) : '');
14210
14243
  }, [value, defaultFormat, locale]);
@@ -14261,7 +14294,7 @@ const TimeInputBase = forwardRef((props, ref) => {
14261
14294
  openOnFocus,
14262
14295
  closeOnSelect,
14263
14296
  isOpen: open,
14264
- setOpen: setOpenFromInput,
14297
+ setOpen,
14265
14298
  inputRef,
14266
14299
  containerRef,
14267
14300
  onFocus,
@@ -14313,7 +14346,7 @@ const TimeInputBase = forwardRef((props, ref) => {
14313
14346
  return (jsxs("div", { ref: containerRef, className: classNames(containerClass, bulmaHelperClasses, className), ...cleanRest, children: [jsx("input", { ref: combinedRef, type: "text", role: "combobox", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": popoverId, autoComplete: "off", className: inputClass, value: text, placeholder: placeholder, disabled: disabled, readOnly: inputReadOnlyAttr, name: name, form: form, required: required, id: id, ...inputHandlers }), popover && triggerIcon && (jsx("button", { type: "button", className: triggerClass, onClick: () => {
14314
14347
  if (canOpen)
14315
14348
  setOpen(!open);
14316
- }, disabled: !canOpen, "aria-label": t.chooseTime, "aria-haspopup": "dialog", "aria-controls": popoverId, "aria-expanded": open, tabIndex: canOpen ? 0 : -1, children: jsx(Icon, { name: triggerIconName, size: size }) })), popover && (jsx(PickerPopover, { isOpen: open, onClose: () => setOpen(false), anchorRef: containerRef, position: position, appendToBody: appendToBody, ariaLabel: t.chooseTime, id: popoverId, children: panel }))] }));
14349
+ }, disabled: !canOpen, "aria-label": t.chooseTime, "aria-haspopup": "dialog", "aria-controls": popoverId, "aria-expanded": open, tabIndex: canOpen ? 0 : -1, children: jsx(Icon, { name: triggerIconName, size: size }) })), popover && (jsx(PickerPopover, { isOpen: open, onClose: () => setOpen(false), anchorRef: containerRef, position: position, appendToBody: appendToBody, ariaLabel: t.chooseTime, id: popoverId, restoreFocusRef: inputRef, children: panel }))] }));
14317
14350
  });
14318
14351
  TimeInputBase.displayName = 'TimeInputBase';
14319
14352
 
@@ -14605,7 +14638,7 @@ const DateTimeInputBase = forwardRef((props, ref) => {
14605
14638
  return (jsxs("div", { ref: containerRef, className: classNames(containerClass, bulmaHelperClasses, className), ...cleanRest, children: [jsx("input", { ref: combinedRef, type: "text", role: "combobox", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": popoverId, autoComplete: "off", className: inputClass, value: text, placeholder: placeholder, disabled: disabled, readOnly: inputReadOnlyAttr, name: name, form: form, required: required, id: id, ...inputHandlers }), popover && triggerIcon && (jsx("button", { type: "button", className: triggerClass, onClick: () => {
14606
14639
  if (canOpen)
14607
14640
  setOpen(!open);
14608
- }, disabled: !canOpen, "aria-label": t.chooseDateTime, "aria-haspopup": "dialog", "aria-controls": popoverId, "aria-expanded": open, tabIndex: canOpen ? 0 : -1, children: jsx(Icon, { name: triggerIconName, size: size }) })), popover && (jsx(PickerPopover, { isOpen: open, onClose: () => setOpen(false), anchorRef: containerRef, position: position, appendToBody: appendToBody, ariaLabel: t.chooseDateTime, id: popoverId, children: panel }))] }));
14641
+ }, disabled: !canOpen, "aria-label": t.chooseDateTime, "aria-haspopup": "dialog", "aria-controls": popoverId, "aria-expanded": open, tabIndex: canOpen ? 0 : -1, children: jsx(Icon, { name: triggerIconName, size: size }) })), popover && (jsx(PickerPopover, { isOpen: open, onClose: () => setOpen(false), anchorRef: containerRef, position: position, appendToBody: appendToBody, ariaLabel: t.chooseDateTime, id: popoverId, restoreFocusRef: inputRef, children: panel }))] }));
14609
14642
  });
14610
14643
  DateTimeInputBase.displayName = 'DateTimeInputBase';
14611
14644
 
@@ -15522,6 +15555,25 @@ const Theme = ({ bulmaVars = {}, children, className, isRoot = false, colorMode,
15522
15555
  }
15523
15556
  return { bulmaVarProps: varProps, otherProps: otherPropsObj };
15524
15557
  }, [restProps]);
15558
+ // Everything left in `otherProps` lands on the wrapper div, as a helper
15559
+ // class or an attribute, and so does `className`. A root Theme renders no
15560
+ // wrapper, so under `isRoot` all of it is dropped. `radius` and `columnGap`
15561
+ // are not in `otherProps`; the checks above cover them.
15562
+ if (isRoot) {
15563
+ const dropped = Object.entries(otherProps)
15564
+ .filter(([, value]) => value !== undefined && value !== null && value !== false)
15565
+ .map(([key]) => key);
15566
+ if (className) {
15567
+ dropped.unshift('className');
15568
+ }
15569
+ if (dropped.length > 0) {
15570
+ warnOnce('Theme:root-dropped-props', `[bestax-bulma] <Theme isRoot>: a root Theme renders no wrapper ` +
15571
+ `element, so ${dropped.join(', ')} ` +
15572
+ `${dropped.length === 1 ? 'has' : 'have'} nothing to apply to. ` +
15573
+ 'Put helper props and classes on an element inside the Theme ' +
15574
+ 'instead.');
15575
+ }
15576
+ }
15525
15577
  // Use Bulma classes for styling (only when not isRoot). Only a helper value
15526
15578
  // of `radius` reaches the helper; a legacy string went to the variable.
15527
15579
  const { bulmaHelperClasses, rest } = useBulmaClasses({