@jobber/components 9.14.5 → 9.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,19 @@
1
1
  import * as React from 'react';
2
2
  import { B as useCoreFilter, D as AriaCombobox, E as useComboboxInputValueContext, e as ComboboxTrigger, d as ComboboxInputGroup, p as ComboboxItem, L as ListboxSeparator, l as ComboboxArrow, i as ComboboxBackdrop, x as ComboboxClear, v as ComboboxCollection, w as ComboboxEmpty, n as ComboboxGroup, o as ComboboxGroupLabel, m as ComboboxIcon, c as ComboboxInput, f as ComboboxList, k as ComboboxPopup, h as ComboboxPortal, j as ComboboxPositioner, u as ComboboxRow, g as ComboboxStatus, A as useFilteredItems, s as ComboboxChip, t as ComboboxChipRemove, r as ComboboxChips, q as ComboboxItemIndicator, a as ComboboxLabel, C as ComboboxRoot, y as ComboboxSeparator, b as ComboboxValue, z as useComboboxFilter } from '../ComboboxSeparator-es.js';
3
- import { n as stringifyAsLabel, A as useCompositeListItem, M as DEFAULT_SIDES, b as useFieldRootContext, f as fieldValidityMapping, K as getDefaultLabelId } from '../useCompositeListItem-es.js';
3
+ import { n as stringifyAsLabel, A as useCompositeListItem, M as DEFAULT_SIDES, f as fieldValidityMapping, a as useFormContext, b as useFieldRootContext, u as useLabelableContext, d as useRegisterFieldControl, o as areArraysEqual, K as getDefaultLabelId } from '../useCompositeListItem-es.js';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
5
- import { bX as pointer, c as useIsoLayoutEffect, d as useStableCallback, bf as CommonPopupDataAttributes, u as useBaseUiId, bS as useTriggerRegistration, o as ownerDocument, h as createChangeEventDetails, bj as swipe, ac as isVirtualClick, a8 as useAnimationFrame, q as useTimeout, I as getWindow, y as addEventListener, D as activeElement, g as getComputedStyle, a0 as contains, e as getTarget, i as isHTMLElement, bv as isInteractiveElement, b as getParentNode, a6 as popupStateMapping, v as useControlled, ad as itemPress, s as useTransitionStatus, l as useOpenChangeComplete, aw as round, bz as useAnimationsFinished, af as getSide, a7 as useDirection, a4 as inertValue, bm as mergeCleanups, bY as gecko, b$ as scrub, a9 as webkit, G as createGenericEventDetails, U as useStore, be as triggerOpenStateMapping, t as transitionStatusMapping, p as popupTransitionStateMapping } from '../useScrollLock-es.js';
5
+ import { bX as pointer, c as useIsoLayoutEffect, d as useStableCallback, bf as CommonPopupDataAttributes, u as useBaseUiId, bS as useTriggerRegistration, o as ownerDocument, j as createChangeEventDetails, bj as swipe, ac as isVirtualClick, a8 as useAnimationFrame, f as useTimeout, I as getWindow, y as addEventListener, D as activeElement, g as getComputedStyle, a0 as contains, e as getTarget, i as isHTMLElement, bv as isInteractiveElement, b as getParentNode, a6 as popupStateMapping, v as useControlled, ad as itemPress, m as useTransitionStatus, n as useOpenChangeComplete, aw as round, bz as useAnimationsFinished, af as getSide, a7 as useDirection, a4 as inertValue, h as useButton, L as useValueChanged, B as visuallyHiddenInput, C as visuallyHidden, z as none, by as dispatchClickWithModifiers, t as transitionStatusMapping, bm as mergeCleanups, bY as gecko, b$ as scrub, a9 as webkit, G as createGenericEventDetails, U as useStore, be as triggerOpenStateMapping, q as popupTransitionStateMapping } from '../useScrollLock-es.js';
6
6
  import { b as DialogBackdrop, d as DialogDescription, f as DialogHandle, c as DialogPopup, a as DialogRoot, e as createDialogHandle, D as DrawerDescription, B as BasePopupHandle } from '../DrawerDescription-es.js';
7
7
  import { c as DialogClose, b as DialogTitle, a as DrawerClose, D as DrawerTitle } from '../DrawerTitle-es.js';
8
8
  import { i as DialogPortal, h as DialogTrigger, j as DialogViewport, r as useDrawerProviderContext, s as DrawerBackdropCssVars, t as DrawerPopupCssVars, v as DrawerProviderContext, u as useDialogRootContext, w as useDrawerRootContext, x as useSwipeDismiss, y as getDisplacement, z as DrawerPopupDataAttributes, A as getElementTransform, B as DrawerVirtualKeyboardContext, C as getElementAtPoint, c as DrawerBackdrop, g as DrawerContent, e as DrawerPopup, b as DrawerPortal, a as DrawerRoot, D as DrawerTrigger, d as DrawerViewport, E as useScrollAreaRootContext, F as getOffset, G as scrollAreaStateAttributesMapping, H as useScrollAreaViewportContext, S as ScrollAreaRoot, f as ScrollAreaViewport } from '../ScrollAreaViewport-es.js';
9
- import { u as useRenderElement, N as NOOP, f as formatErrorMessage, E as EMPTY_OBJECT } from '../useRenderElement-es.js';
9
+ import { u as useRenderElement, N as NOOP, f as formatErrorMessage, E as EMPTY_OBJECT, a as useRefWithInit, b as useMergedRefs, m as mergeProps, c as EMPTY_ARRAY } from '../useRenderElement-es.js';
10
10
  import { c as clamp, g as getMaxScrollOffset, n as normalizeScrollOffset, S as SCROLL_EDGE_TOLERANCE_PX } from '../scrollEdges-es.js';
11
11
  import { f as findScrollableTouchTarget } from '../scrollable-es.js';
12
12
  import { u as useMenuRootContext, o as useMenuPositionerContext, p as useMenuItem, R as REGULAR_ITEM, q as itemMapping, r as createNullMenuStore, h as MenuBackdrop, l as MenuGroup, n as MenuGroupLabel, b as MenuItem, a as MenuLinkItem, j as MenuPopup, g as MenuPortal, i as MenuPositioner, k as MenuRadioGroup, c as MenuRadioItem, d as MenuRadioItemIndicator, f as MenuRoot, m as MenuSubmenuRoot, e as MenuSubmenuTrigger, M as MenuTrigger } from '../MenuSubmenuTrigger-es.js';
13
13
  import * as ReactDOM from 'react-dom';
14
14
  import { m as usePreviousValue, n as useSelectRootContext, s as selectors, o as useSelectPositionerContext, j as SelectGroup, k as SelectGroupLabel, g as SelectItem, i as SelectItemIndicator, h as SelectItemText, f as SelectList, e as SelectPopup, a as SelectPortal, d as SelectPositioner, S as SelectRoot, b as SelectTrigger, c as SelectValue } from '../SelectGroupLabel-es.js';
15
15
  import { S as Separator } from '../Separator-es.js';
16
+ import { a as useFieldItemContext, i as isEligibleInput } from '../useFieldValidation-es.js';
16
17
  import { u as useNumberFieldRootContext, s as stateAttributesMapping$4, c as NumberFieldDecrement, a as NumberFieldGroup, b as NumberFieldIncrement, d as NumberFieldInput, N as NumberFieldRoot } from '../NumberFieldInput-es.js';
17
18
  import { u as useLabel } from '../useLabel-es.js';
18
19
  import '../stringifyLocale-es.js';
@@ -152,7 +153,7 @@ const AutocompleteItem = ComboboxItem;
152
153
  */
153
154
  const AutocompleteSeparator = ListboxSeparator;
154
155
 
155
- var index_parts$7 = /*#__PURE__*/Object.freeze({
156
+ var index_parts$8 = /*#__PURE__*/Object.freeze({
156
157
  __proto__: null,
157
158
  Arrow: ComboboxArrow,
158
159
  Backdrop: ComboboxBackdrop,
@@ -179,7 +180,7 @@ var index_parts$7 = /*#__PURE__*/Object.freeze({
179
180
  useFilteredItems: useFilteredItems
180
181
  });
181
182
 
182
- var index_parts$6 = /*#__PURE__*/Object.freeze({
183
+ var index_parts$7 = /*#__PURE__*/Object.freeze({
183
184
  __proto__: null,
184
185
  Backdrop: DialogBackdrop,
185
186
  Close: DialogClose,
@@ -1481,7 +1482,7 @@ function createDrawerHandle() {
1481
1482
  return new DrawerHandle();
1482
1483
  }
1483
1484
 
1484
- var index_parts$5 = /*#__PURE__*/Object.freeze({
1485
+ var index_parts$6 = /*#__PURE__*/Object.freeze({
1485
1486
  __proto__: null,
1486
1487
  Backdrop: DrawerBackdrop,
1487
1488
  Close: DrawerClose,
@@ -2286,7 +2287,7 @@ function createMenuHandle() {
2286
2287
  return new MenuHandle();
2287
2288
  }
2288
2289
 
2289
- var index_parts$4 = /*#__PURE__*/Object.freeze({
2290
+ var index_parts$5 = /*#__PURE__*/Object.freeze({
2290
2291
  __proto__: null,
2291
2292
  Arrow: MenuArrow,
2292
2293
  Backdrop: MenuBackdrop,
@@ -2659,7 +2660,7 @@ const ScrollAreaCorner = /*#__PURE__*/React.forwardRef(function ScrollAreaCorner
2659
2660
  });
2660
2661
  if (process.env.NODE_ENV !== "production") ScrollAreaCorner.displayName = "ScrollAreaCorner";
2661
2662
 
2662
- var index_parts$3 = /*#__PURE__*/Object.freeze({
2663
+ var index_parts$4 = /*#__PURE__*/Object.freeze({
2663
2664
  __proto__: null,
2664
2665
  Content: ScrollAreaContent,
2665
2666
  Corner: ScrollAreaCorner,
@@ -2669,6 +2670,689 @@ var index_parts$3 = /*#__PURE__*/Object.freeze({
2669
2670
  Viewport: ScrollAreaViewport
2670
2671
  });
2671
2672
 
2673
+ /**
2674
+ * Returns the default button a browser uses for implicit form submission.
2675
+ *
2676
+ * This is useful for custom form controls that need to mirror native Enter key behavior.
2677
+ * Clicking the returned submitter preserves browser semantics such as the submitter's click
2678
+ * event, `SubmitEvent.submitter`, and submitter-specific attributes.
2679
+ *
2680
+ * The function follows the controls exposed by `form.elements`, which includes controls associated
2681
+ * through the `form` attribute. Disabled submitters can be returned because the default button is
2682
+ * determined before disabled state is considered; clicking a disabled submitter is a no-op.
2683
+ */
2684
+ function getDefaultFormSubmitter(form) {
2685
+ if (!form) {
2686
+ return null;
2687
+ }
2688
+ for (const candidate of form.elements) {
2689
+ const tagName = candidate.tagName;
2690
+ if (tagName === 'BUTTON' || tagName === 'INPUT') {
2691
+ const button = candidate;
2692
+
2693
+ // Intentionally excludes input[type="image"]: Chromium omits it from form.elements,
2694
+ // so supporting it would require separate traversal for an exotic submitter type.
2695
+ if (button.type === 'submit') {
2696
+ return button;
2697
+ }
2698
+ }
2699
+ }
2700
+ return null;
2701
+ }
2702
+
2703
+ function getCheckboxStateAttributesMapping(state) {
2704
+ return {
2705
+ checked(value) {
2706
+ if (state.indeterminate) {
2707
+ // `data-indeterminate` is already handled by the `indeterminate` prop.
2708
+ return {};
2709
+ }
2710
+ if (value) {
2711
+ return {
2712
+ 'data-checked': ''
2713
+ };
2714
+ }
2715
+ return {
2716
+ 'data-unchecked': ''
2717
+ };
2718
+ },
2719
+ ...fieldValidityMapping
2720
+ };
2721
+ }
2722
+
2723
+ function useAriaLabelledBy(explicitAriaLabelledBy, labelId, labelSourceRef, enableFallback = true, labelSourceId) {
2724
+ const [fallbackAriaLabelledBy, setFallbackAriaLabelledBy] = React.useState();
2725
+ const generatedLabelId = useBaseUiId(labelSourceId ? `${labelSourceId}-label` : undefined);
2726
+ const ariaLabelledBy = explicitAriaLabelledBy ?? labelId ?? fallbackAriaLabelledBy;
2727
+
2728
+ // Fallback for <span> controls labelled by wrapping/sibling native <label>.
2729
+ // Run after every commit so DOM association changes (e.g. label mount/unmount)
2730
+ // are reflected even when props/state deps are unchanged.
2731
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2732
+ useIsoLayoutEffect(() => {
2733
+ const nextAriaLabelledBy = explicitAriaLabelledBy || labelId || !enableFallback ? undefined : getAriaLabelledBy(labelSourceRef.current, generatedLabelId);
2734
+ if (fallbackAriaLabelledBy !== nextAriaLabelledBy) {
2735
+ setFallbackAriaLabelledBy(nextAriaLabelledBy);
2736
+ }
2737
+ });
2738
+ return ariaLabelledBy;
2739
+ }
2740
+ function getAriaLabelledBy(labelSource, generatedLabelId) {
2741
+ const label = findAssociatedLabel(labelSource);
2742
+ if (!label) {
2743
+ return undefined;
2744
+ }
2745
+ if (!label.id && generatedLabelId) {
2746
+ label.id = generatedLabelId;
2747
+ }
2748
+ return label.id || undefined;
2749
+ }
2750
+ function findAssociatedLabel(labelSource) {
2751
+ if (!labelSource) {
2752
+ return undefined;
2753
+ }
2754
+
2755
+ // Fast path before the expensive `.labels` read.
2756
+ const parent = labelSource.parentElement;
2757
+ if (parent && parent.tagName === 'LABEL') {
2758
+ return parent;
2759
+ }
2760
+ const controlId = labelSource.id;
2761
+ if (controlId) {
2762
+ const nextSibling = labelSource.nextElementSibling;
2763
+ if (nextSibling && nextSibling.htmlFor === controlId) {
2764
+ return nextSibling;
2765
+ }
2766
+ }
2767
+ const labels = labelSource.labels;
2768
+ return labels && labels[0];
2769
+ }
2770
+
2771
+ const CheckboxGroupContext = /*#__PURE__*/React.createContext(undefined);
2772
+ if (process.env.NODE_ENV !== "production") CheckboxGroupContext.displayName = "CheckboxGroupContext";
2773
+ function useCheckboxGroupContext() {
2774
+ return React.useContext(CheckboxGroupContext);
2775
+ }
2776
+
2777
+ const CheckboxRootContext = /*#__PURE__*/React.createContext(undefined);
2778
+ if (process.env.NODE_ENV !== "production") CheckboxRootContext.displayName = "CheckboxRootContext";
2779
+ function useCheckboxRootContext() {
2780
+ const context = React.useContext(CheckboxRootContext);
2781
+ if (context === undefined) {
2782
+ throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: CheckboxRootContext is missing. Checkbox parts must be placed within <Checkbox.Root>.' : formatErrorMessage(14));
2783
+ }
2784
+ return context;
2785
+ }
2786
+
2787
+ const PARENT_CHECKBOX = 'data-parent';
2788
+
2789
+ /**
2790
+ * Represents the checkbox itself.
2791
+ * Renders a `<span>` element and a hidden `<input>` beside.
2792
+ *
2793
+ * Documentation: [Base UI Checkbox](https://base-ui.com/react/components/checkbox)
2794
+ */
2795
+ const CheckboxRoot = /*#__PURE__*/React.forwardRef(function CheckboxRoot(componentProps, forwardedRef) {
2796
+ const {
2797
+ checked: checkedProp,
2798
+ className,
2799
+ defaultChecked = false,
2800
+ 'aria-labelledby': ariaLabelledByProp,
2801
+ disabled: disabledProp = false,
2802
+ form,
2803
+ id: idProp,
2804
+ indeterminate = false,
2805
+ inputRef: inputRefProp,
2806
+ name: nameProp,
2807
+ onCheckedChange,
2808
+ parent = false,
2809
+ readOnly = false,
2810
+ render,
2811
+ required = false,
2812
+ uncheckedValue,
2813
+ value: valueProp,
2814
+ nativeButton = false,
2815
+ style,
2816
+ ...elementProps
2817
+ } = componentProps;
2818
+ const {
2819
+ clearErrors
2820
+ } = useFormContext();
2821
+ const {
2822
+ disabled: rootDisabled,
2823
+ name: fieldName,
2824
+ setDirty,
2825
+ setFilled,
2826
+ setFocused,
2827
+ setTouched,
2828
+ state: fieldState,
2829
+ validationMode,
2830
+ validityData,
2831
+ validation: localValidation
2832
+ } = useFieldRootContext();
2833
+ const fieldItemContext = useFieldItemContext();
2834
+ const {
2835
+ labelId,
2836
+ controlId,
2837
+ registerControlId,
2838
+ getDescriptionProps
2839
+ } = useLabelableContext();
2840
+ const groupContext = useCheckboxGroupContext();
2841
+ const parentContext = groupContext?.allValues === undefined ? undefined : groupContext.parent;
2842
+ const isGroupedWithParent = parentContext !== undefined;
2843
+ const disabled = rootDisabled || fieldItemContext.disabled || groupContext?.disabled || disabledProp;
2844
+ const name = fieldName ?? nameProp;
2845
+ const value = valueProp ?? name;
2846
+ const id = useBaseUiId();
2847
+ const generatedInputId = useBaseUiId();
2848
+ let inputId = idProp || controlId;
2849
+ if (isGroupedWithParent) {
2850
+ if (parent) {
2851
+ inputId = generatedInputId;
2852
+ } else if (value !== undefined) {
2853
+ inputId = `${parentContext.id}-${value}`;
2854
+ } else {
2855
+ inputId ||= generatedInputId;
2856
+ }
2857
+ }
2858
+ let groupProps = {};
2859
+ if (isGroupedWithParent) {
2860
+ if (parent) {
2861
+ groupProps = parentContext.getParentProps();
2862
+ } else if (value !== undefined) {
2863
+ groupProps = parentContext.getChildProps(value);
2864
+ }
2865
+ }
2866
+ const {
2867
+ checked: groupChecked = checkedProp,
2868
+ indeterminate: groupIndeterminate = indeterminate,
2869
+ onCheckedChange: groupOnChange,
2870
+ ...otherGroupProps
2871
+ } = groupProps;
2872
+ const groupValue = groupContext?.value;
2873
+ const controlRef = React.useRef(null);
2874
+ const controlSourceRef = useRefWithInit(() => Symbol());
2875
+ const hasRegisteredRef = React.useRef(false);
2876
+ const {
2877
+ getButtonProps,
2878
+ buttonRef
2879
+ } = useButton({
2880
+ disabled,
2881
+ native: nativeButton
2882
+ });
2883
+ const validation = groupContext?.validation ?? localValidation;
2884
+ const [checked, setCheckedState] = useControlled({
2885
+ controlled: value !== undefined && groupValue !== undefined && !parent ? groupValue.includes(value) : groupChecked,
2886
+ default: defaultChecked,
2887
+ name: 'Checkbox',
2888
+ state: 'checked'
2889
+ });
2890
+ const computedChecked = isGroupedWithParent ? Boolean(groupChecked) : checked;
2891
+ const computedIndeterminate = isGroupedWithParent ? groupIndeterminate || indeterminate : indeterminate;
2892
+
2893
+ // can't use useLabelableId because of optional groupContext and/or parent
2894
+ useIsoLayoutEffect(() => {
2895
+ if (registerControlId === NOOP) {
2896
+ return undefined;
2897
+ }
2898
+ hasRegisteredRef.current = true;
2899
+ registerControlId(controlSourceRef.current, inputId);
2900
+ return undefined;
2901
+ }, [inputId, registerControlId, controlSourceRef]);
2902
+ React.useEffect(() => {
2903
+ const controlSource = controlSourceRef.current;
2904
+ return () => {
2905
+ if (!hasRegisteredRef.current || registerControlId === NOOP) {
2906
+ return;
2907
+ }
2908
+ hasRegisteredRef.current = false;
2909
+ registerControlId(controlSource, undefined);
2910
+ };
2911
+ }, [registerControlId, controlSourceRef]);
2912
+ useRegisterFieldControl(controlRef, id, checked, undefined, !groupContext && !disabled, nameProp);
2913
+ const inputRef = React.useRef(null);
2914
+ const registerFieldInput = validation.registerInput;
2915
+ const registeredInputValue = groupContext ? value : undefined;
2916
+ const registerInput = React.useCallback(element => registerFieldInput(element, {
2917
+ controlRef,
2918
+ value: registeredInputValue
2919
+ }), [registerFieldInput, registeredInputValue]);
2920
+ const mergedInputRef = useMergedRefs(inputRefProp, inputRef, parent ? undefined : registerInput);
2921
+ const ariaLabelledBy = useAriaLabelledBy(ariaLabelledByProp, labelId, inputRef, !nativeButton, inputId ?? undefined);
2922
+ useIsoLayoutEffect(() => {
2923
+ if (inputRef.current) {
2924
+ inputRef.current.indeterminate = computedIndeterminate;
2925
+ if (checked) {
2926
+ setFilled(true);
2927
+ }
2928
+ }
2929
+ }, [checked, computedIndeterminate, setFilled]);
2930
+ useValueChanged(checked, () => {
2931
+ if (groupContext) {
2932
+ return;
2933
+ }
2934
+ clearErrors(name);
2935
+ setFilled(checked);
2936
+ setDirty(checked !== validityData.initialValue);
2937
+ validation.change(checked);
2938
+ });
2939
+ const inputProps = mergeProps({
2940
+ checked,
2941
+ disabled,
2942
+ form,
2943
+ // parent checkboxes unset `name` to be excluded from form submission
2944
+ name: parent ? undefined : name,
2945
+ // Set `id` to stop Chrome warning about an unassociated input.
2946
+ // When using a native button, the `id` is applied to the button instead.
2947
+ id: nativeButton ? undefined : inputId ?? undefined,
2948
+ required,
2949
+ ref: mergedInputRef,
2950
+ style: name ? visuallyHiddenInput : visuallyHidden,
2951
+ tabIndex: -1,
2952
+ type: 'checkbox',
2953
+ 'aria-hidden': true,
2954
+ onChange(event) {
2955
+ // Workaround for https://github.com/react/react/issues/9023
2956
+ if (event.nativeEvent.defaultPrevented) {
2957
+ return;
2958
+ }
2959
+ if (readOnly) {
2960
+ event.preventDefault();
2961
+ return;
2962
+ }
2963
+ const nextChecked = event.currentTarget.checked;
2964
+ const details = createChangeEventDetails(none, event.nativeEvent);
2965
+ onCheckedChange?.(nextChecked, details);
2966
+ if (details.isCanceled) {
2967
+ return;
2968
+ }
2969
+ groupOnChange?.(nextChecked, details);
2970
+ if (details.isCanceled) {
2971
+ return;
2972
+ }
2973
+ setCheckedState(nextChecked);
2974
+ if (value !== undefined && groupContext !== undefined && !parent && !isGroupedWithParent) {
2975
+ const nextGroupValue = nextChecked ? [...groupContext.value, value] : groupContext.value.filter(item => item !== value);
2976
+ groupContext.setValue(nextGroupValue, details);
2977
+ }
2978
+ },
2979
+ onClick(event) {
2980
+ // The click dispatched from the root's `onClick` is an implementation detail
2981
+ // and must not reach ancestors, which already receive the original click.
2982
+ event.stopPropagation();
2983
+ },
2984
+ onFocus() {
2985
+ controlRef.current?.focus();
2986
+ }
2987
+ },
2988
+ // React <19 sets an empty value if `undefined` is passed explicitly
2989
+ // To avoid this, we only set the value if it's defined
2990
+ valueProp !== undefined ? {
2991
+ value: (groupContext ? checked && valueProp : valueProp) || ''
2992
+ } : EMPTY_OBJECT, getDescriptionProps, props => validation.getValidationProps(disabled, props));
2993
+ React.useEffect(() => {
2994
+ if (!parentContext || value === undefined) {
2995
+ return undefined;
2996
+ }
2997
+ const disabledStates = parentContext.disabledStatesRef.current;
2998
+ disabledStates.set(value, disabled);
2999
+ return () => {
3000
+ disabledStates.delete(value);
3001
+ };
3002
+ }, [parentContext, disabled, value]);
3003
+ const state = React.useMemo(() => ({
3004
+ ...fieldState,
3005
+ checked: computedChecked,
3006
+ disabled,
3007
+ readOnly,
3008
+ required,
3009
+ indeterminate: computedIndeterminate
3010
+ }), [fieldState, computedChecked, disabled, readOnly, required, computedIndeterminate]);
3011
+ const stateAttributesMapping = getCheckboxStateAttributesMapping(state);
3012
+ const element = useRenderElement('span', componentProps, {
3013
+ state,
3014
+ ref: [buttonRef, controlRef, forwardedRef],
3015
+ props: [{
3016
+ id: nativeButton ? inputId ?? undefined : id,
3017
+ role: 'checkbox',
3018
+ 'aria-checked': computedIndeterminate ? 'mixed' : computedChecked,
3019
+ 'aria-readonly': readOnly || undefined,
3020
+ 'aria-required': required || undefined,
3021
+ 'aria-labelledby': ariaLabelledBy,
3022
+ [PARENT_CHECKBOX]: parent ? '' : undefined,
3023
+ onFocus() {
3024
+ if (!disabled) {
3025
+ setFocused(true);
3026
+ }
3027
+ },
3028
+ onBlur() {
3029
+ const inputEl = inputRef.current;
3030
+ if (!inputEl) {
3031
+ return;
3032
+ }
3033
+ setTouched(true);
3034
+ setFocused(false);
3035
+ if (validationMode === 'onBlur') {
3036
+ validation.commit(groupContext ? groupValue : inputEl.checked);
3037
+ }
3038
+ },
3039
+ onKeyDown(event) {
3040
+ if (event.key !== 'Enter') {
3041
+ return;
3042
+ }
3043
+
3044
+ // Let consumer `preventDefault()` handlers opt out while defensively stopping
3045
+ // any remaining Base UI Enter handling from treating the checkbox as a button.
3046
+ event.preventBaseUIHandler();
3047
+ if (event.defaultPrevented) {
3048
+ return;
3049
+ }
3050
+ const formToSubmit = inputRef.current?.form ?? null;
3051
+ const currentTarget = event.currentTarget;
3052
+ const nativeEvent = event.nativeEvent;
3053
+ const originalPreventDefault = event.preventDefault;
3054
+ const originalNativePreventDefault = nativeEvent.preventDefault;
3055
+ let preventDefaultCalledAfterPropagation = false;
3056
+ event.preventDefault = () => {
3057
+ preventDefaultCalledAfterPropagation = true;
3058
+ originalPreventDefault.call(event);
3059
+ };
3060
+ nativeEvent.preventDefault = () => {
3061
+ preventDefaultCalledAfterPropagation = true;
3062
+ originalNativePreventDefault.call(nativeEvent);
3063
+ };
3064
+
3065
+ // Enter should not activate/toggle the checkbox. Cancel the native button behavior
3066
+ // without setting React's synthetic `defaultPrevented`, so ancestor React handlers
3067
+ // can still opt out by calling `preventDefault()` during propagation.
3068
+ originalNativePreventDefault.call(nativeEvent);
3069
+ getWindow(currentTarget).queueMicrotask(() => {
3070
+ event.preventDefault = originalPreventDefault;
3071
+ nativeEvent.preventDefault = originalNativePreventDefault;
3072
+ if (!preventDefaultCalledAfterPropagation) {
3073
+ getDefaultFormSubmitter(formToSubmit)?.click();
3074
+ }
3075
+ });
3076
+ },
3077
+ onClick(event) {
3078
+ if (readOnly || disabled) {
3079
+ return;
3080
+ }
3081
+ event.preventDefault();
3082
+ const input = inputRef.current;
3083
+ if (!input) {
3084
+ return;
3085
+ }
3086
+ dispatchClickWithModifiers(input, event);
3087
+ }
3088
+ }, elementProps, otherGroupProps, getButtonProps, getDescriptionProps, props => validation.getValidationProps(disabled, props)],
3089
+ stateAttributesMapping
3090
+ });
3091
+ return /*#__PURE__*/jsxs(CheckboxRootContext.Provider, {
3092
+ value: state,
3093
+ children: [element, !checked && !groupContext && name && !parent && uncheckedValue !== undefined && /*#__PURE__*/jsx("input", {
3094
+ type: "hidden",
3095
+ form: form,
3096
+ name: name,
3097
+ value: uncheckedValue,
3098
+ disabled: disabled
3099
+ }), /*#__PURE__*/jsx("input", {
3100
+ ...inputProps,
3101
+ suppressHydrationWarning: true
3102
+ })]
3103
+ });
3104
+ });
3105
+ if (process.env.NODE_ENV !== "production") CheckboxRoot.displayName = "CheckboxRoot";
3106
+
3107
+ /**
3108
+ * Indicates whether the checkbox is ticked.
3109
+ * Renders a `<span>` element.
3110
+ *
3111
+ * Documentation: [Base UI Checkbox](https://base-ui.com/react/components/checkbox)
3112
+ */
3113
+ const CheckboxIndicator = /*#__PURE__*/React.forwardRef(function CheckboxIndicator(componentProps, forwardedRef) {
3114
+ const {
3115
+ render,
3116
+ className,
3117
+ style,
3118
+ keepMounted = false,
3119
+ ...elementProps
3120
+ } = componentProps;
3121
+ const rootState = useCheckboxRootContext();
3122
+ const rendered = rootState.checked || rootState.indeterminate;
3123
+ const {
3124
+ mounted,
3125
+ transitionStatus,
3126
+ setMounted
3127
+ } = useTransitionStatus(rendered);
3128
+ const indicatorRef = React.useRef(null);
3129
+ const state = {
3130
+ ...rootState,
3131
+ transitionStatus
3132
+ };
3133
+ useOpenChangeComplete({
3134
+ open: rendered,
3135
+ ref: indicatorRef,
3136
+ onComplete() {
3137
+ if (!rendered) {
3138
+ setMounted(false);
3139
+ }
3140
+ }
3141
+ });
3142
+ const baseStateAttributesMapping = getCheckboxStateAttributesMapping(rootState);
3143
+ const stateAttributesMapping = {
3144
+ ...baseStateAttributesMapping,
3145
+ ...transitionStatusMapping
3146
+ };
3147
+ const shouldRender = keepMounted || mounted;
3148
+ const element = useRenderElement('span', componentProps, {
3149
+ ref: [forwardedRef, indicatorRef],
3150
+ state,
3151
+ stateAttributesMapping,
3152
+ props: elementProps
3153
+ });
3154
+ if (!shouldRender) {
3155
+ return null;
3156
+ }
3157
+ return element;
3158
+ });
3159
+ if (process.env.NODE_ENV !== "production") CheckboxIndicator.displayName = "CheckboxIndicator";
3160
+
3161
+ var index_parts$3 = /*#__PURE__*/Object.freeze({
3162
+ __proto__: null,
3163
+ Indicator: CheckboxIndicator,
3164
+ Root: CheckboxRoot
3165
+ });
3166
+
3167
+ function useCheckboxGroupParent(params) {
3168
+ const {
3169
+ allValues = EMPTY_ARRAY,
3170
+ value,
3171
+ onValueChange: onValueChangeProp
3172
+ } = params;
3173
+ const uncontrolledStateRef = React.useRef(value);
3174
+ const disabledStatesRef = React.useRef(new Map());
3175
+ const [status, setStatus] = React.useState('mixed');
3176
+ const id = useBaseUiId();
3177
+ const checked = value.length === allValues.length;
3178
+ const indeterminate = value.length !== allValues.length && value.length > 0;
3179
+ const onValueChange = useStableCallback(onValueChangeProp);
3180
+ const getParentProps = React.useCallback(() => ({
3181
+ id,
3182
+ indeterminate,
3183
+ checked,
3184
+ // TODO: custom `id` on child checkboxes breaks this
3185
+ // https://github.com/mui/base-ui/issues/2691
3186
+ 'aria-controls': allValues.map(v => `${id}-${v}`).join(' '),
3187
+ onCheckedChange(_, eventDetails) {
3188
+ const uncontrolledState = uncontrolledStateRef.current;
3189
+
3190
+ // None except the disabled ones that are checked, which can't be changed.
3191
+ const none = allValues.filter(v => disabledStatesRef.current.get(v) && uncontrolledState.includes(v));
3192
+ // "All" that are valid:
3193
+ // - any that aren't disabled
3194
+ // - disabled ones that are checked
3195
+ const all = allValues.filter(v => !disabledStatesRef.current.get(v) || uncontrolledState.includes(v));
3196
+ const allOnOrOff = uncontrolledState.length === all.length || uncontrolledState.length === 0;
3197
+ if (allOnOrOff) {
3198
+ if (value.length === all.length) {
3199
+ onValueChange(none, eventDetails);
3200
+ } else {
3201
+ onValueChange(all, eventDetails);
3202
+ }
3203
+ return;
3204
+ }
3205
+ let nextStatus = 'mixed';
3206
+ let nextValue = uncontrolledState;
3207
+ if (status === 'mixed') {
3208
+ nextStatus = 'on';
3209
+ nextValue = all;
3210
+ } else if (status === 'on') {
3211
+ nextStatus = 'off';
3212
+ nextValue = none;
3213
+ }
3214
+ onValueChange(nextValue, eventDetails);
3215
+ if (!eventDetails.isCanceled) {
3216
+ setStatus(nextStatus);
3217
+ }
3218
+ }
3219
+ }), [allValues, checked, id, indeterminate, onValueChange, status, value.length]);
3220
+ const getChildProps = React.useCallback(childValue => ({
3221
+ checked: value.includes(childValue),
3222
+ onCheckedChange(nextChecked, eventDetails) {
3223
+ const newValue = value.slice();
3224
+ if (nextChecked) {
3225
+ newValue.push(childValue);
3226
+ } else {
3227
+ newValue.splice(newValue.indexOf(childValue), 1);
3228
+ }
3229
+ onValueChange(newValue, eventDetails);
3230
+ if (!eventDetails.isCanceled) {
3231
+ uncontrolledStateRef.current = newValue;
3232
+ setStatus('mixed');
3233
+ }
3234
+ }
3235
+ }), [onValueChange, value]);
3236
+ return React.useMemo(() => ({
3237
+ id,
3238
+ getParentProps,
3239
+ getChildProps,
3240
+ disabledStatesRef
3241
+ }), [id, getParentProps, getChildProps]);
3242
+ }
3243
+
3244
+ const CheckboxGroup = /*#__PURE__*/React.forwardRef(function CheckboxGroup(componentProps, forwardedRef) {
3245
+ const {
3246
+ allValues,
3247
+ className,
3248
+ defaultValue: defaultValueProp,
3249
+ disabled: disabledProp = false,
3250
+ id: idProp,
3251
+ onValueChange,
3252
+ render,
3253
+ value: externalValue,
3254
+ style,
3255
+ ...elementProps
3256
+ } = componentProps;
3257
+ const {
3258
+ disabled: fieldDisabled,
3259
+ name: fieldName,
3260
+ state: fieldState,
3261
+ validation,
3262
+ setFilled,
3263
+ setDirty,
3264
+ validityData
3265
+ } = useFieldRootContext();
3266
+ const {
3267
+ labelId,
3268
+ getDescriptionProps
3269
+ } = useLabelableContext();
3270
+ const {
3271
+ clearErrors,
3272
+ elementRef
3273
+ } = useFormContext();
3274
+ const disabled = fieldDisabled || disabledProp;
3275
+ const defaultValue = defaultValueProp ?? EMPTY_ARRAY;
3276
+
3277
+ // A controlled value can still be `undefined` at runtime even though `useControlled`'s
3278
+ // generic return type says otherwise. Keep the fallback to prevent group consumers from crashing.
3279
+ const [value = EMPTY_ARRAY, setValueUnwrapped] = useControlled({
3280
+ controlled: externalValue,
3281
+ default: defaultValue,
3282
+ name: 'CheckboxGroup',
3283
+ state: 'value'
3284
+ });
3285
+ const setValue = useStableCallback((v, eventDetails) => {
3286
+ onValueChange?.(v, eventDetails);
3287
+ if (eventDetails.isCanceled) {
3288
+ return;
3289
+ }
3290
+ setValueUnwrapped(v);
3291
+ });
3292
+ const parent = useCheckboxGroupParent({
3293
+ allValues,
3294
+ value,
3295
+ onValueChange: setValue
3296
+ });
3297
+ const id = useBaseUiId(idProp);
3298
+ const getInputControl = validation.getInputControl;
3299
+ const controlRef = React.useMemo(() => ({
3300
+ get current() {
3301
+ return getInputControl();
3302
+ }
3303
+ }), [getInputControl]);
3304
+ const getFormValue = useStableCallback(() => {
3305
+ const formElement = elementRef.current;
3306
+ if (!formElement) {
3307
+ return value;
3308
+ }
3309
+ const successfulValues = new Set();
3310
+ for (const [input, registration] of validation.registeredInputs) {
3311
+ if (registration.value !== undefined && input.checked && isEligibleInput(input, formElement)) {
3312
+ successfulValues.add(registration.value);
3313
+ }
3314
+ }
3315
+ return value.filter(inputValue => successfulValues.has(inputValue));
3316
+ });
3317
+ useRegisterFieldControl(controlRef, id, value, getFormValue, !!fieldName && !disabled, fieldName);
3318
+ useValueChanged(value, () => {
3319
+ if (fieldName) {
3320
+ clearErrors(fieldName);
3321
+ }
3322
+ const initialValue = Array.isArray(validityData.initialValue) ? validityData.initialValue : EMPTY_ARRAY;
3323
+ setFilled(value.length > 0);
3324
+ setDirty(!areArraysEqual(value, initialValue));
3325
+ validation.change(value);
3326
+ });
3327
+ const state = {
3328
+ ...fieldState,
3329
+ disabled
3330
+ };
3331
+ const contextValue = React.useMemo(() => ({
3332
+ allValues,
3333
+ value,
3334
+ setValue,
3335
+ parent,
3336
+ disabled,
3337
+ validation
3338
+ }), [allValues, value, setValue, parent, disabled, validation]);
3339
+ const element = useRenderElement('div', componentProps, {
3340
+ state,
3341
+ ref: forwardedRef,
3342
+ props: [{
3343
+ id: idProp,
3344
+ role: 'group',
3345
+ 'aria-labelledby': labelId
3346
+ }, elementProps, getDescriptionProps],
3347
+ stateAttributesMapping: fieldValidityMapping
3348
+ });
3349
+ return /*#__PURE__*/jsx(CheckboxGroupContext.Provider, {
3350
+ value: contextValue,
3351
+ children: element
3352
+ });
3353
+ });
3354
+ if (process.env.NODE_ENV !== "production") CheckboxGroup.displayName = "CheckboxGroup";
3355
+
2672
3356
  var index_parts$2 = /*#__PURE__*/Object.freeze({
2673
3357
  __proto__: null,
2674
3358
  Arrow: ComboboxArrow,
@@ -3448,4 +4132,4 @@ function useRender(params) {
3448
4132
  return useRenderElement(params.defaultTagName ?? 'div', params, params);
3449
4133
  }
3450
4134
 
3451
- export { index_parts$7 as Autocomplete, index_parts$2 as Combobox, index_parts$6 as Dialog, index_parts$5 as Drawer, index_parts$4 as Menu, index_parts$1 as NumberField, index_parts$3 as ScrollArea, index_parts as Select, Separator, useRender };
4135
+ export { index_parts$8 as Autocomplete, index_parts$3 as Checkbox, CheckboxGroup, index_parts$2 as Combobox, index_parts$7 as Dialog, index_parts$6 as Drawer, index_parts$5 as Menu, index_parts$1 as NumberField, index_parts$4 as ScrollArea, index_parts as Select, Separator, useRender };