@jobber/components 7.15.3-progress-b-cc1652c.1 → 7.15.4

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.
@@ -4,13 +4,14 @@ var DrawerRoot = require('../DrawerRoot-cjs.js');
4
4
  var MenuSubmenuTrigger = require('../MenuSubmenuTrigger-cjs.js');
5
5
  var React = require('react');
6
6
  var useRenderElement = require('../useRenderElement-cjs.js');
7
- var NumberFieldInput = require('../NumberFieldInput-cjs.js');
7
+ var useBaseUiId = require('../useBaseUiId-cjs.js');
8
8
  var useValueChanged = require('../useValueChanged-cjs.js');
9
9
  var jsxRuntime = require('react/jsx-runtime');
10
10
  var floatingUi_utils_dom = require('../floating-ui.utils.dom-cjs.js');
11
11
  var ReactDOM = require('react-dom');
12
12
  var index_esm = require('../index.esm-cjs.js');
13
13
  var Separator = require('../Separator-cjs.js');
14
+ var NumberFieldInput = require('../NumberFieldInput-cjs.js');
14
15
  require('../floating-ui.react-dom-cjs.js');
15
16
 
16
17
  function _interopNamespaceDefault(e) {
@@ -49,7 +50,7 @@ const DialogDescription = /*#__PURE__*/React__namespace.forwardRef(function Dial
49
50
  const {
50
51
  store
51
52
  } = DrawerRoot.useDialogRootContext();
52
- const id = NumberFieldInput.useBaseUiId(idProp);
53
+ const id = useBaseUiId.useBaseUiId(idProp);
53
54
  store.useSyncedValueWithCleanup('descriptionElementId', id);
54
55
  return useRenderElement.useRenderElement('p', componentProps, {
55
56
  ref: forwardedRef,
@@ -1491,7 +1492,7 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
1491
1492
  const closedOffsetRef = React__namespace.useRef(null);
1492
1493
  const appliedSwipeStylesRef = React__namespace.useRef(false);
1493
1494
  const popupTransitionRef = React__namespace.useRef(null);
1494
- const swipeAreaId = NumberFieldInput.useBaseUiId(componentProps.id);
1495
+ const swipeAreaId = useBaseUiId.useBaseUiId(componentProps.id);
1495
1496
  const registerTrigger = DrawerRoot.useTriggerRegistration(swipeAreaId, store);
1496
1497
  const open = store.useState('open');
1497
1498
  const resolvedSwipeDirection = swipeDirectionProp ?? oppositeSwipeDirection[swipeDirection];
@@ -2882,7 +2883,7 @@ const MenuCheckboxItem = /*#__PURE__*/React__namespace.forwardRef(function MenuC
2882
2883
  label
2883
2884
  });
2884
2885
  const menuPositionerContext = MenuSubmenuTrigger.useMenuPositionerContext(true);
2885
- const id = NumberFieldInput.useBaseUiId(idProp);
2886
+ const id = useBaseUiId.useBaseUiId(idProp);
2886
2887
  const {
2887
2888
  store
2888
2889
  } = MenuSubmenuTrigger.useMenuRootContext();
@@ -5069,7 +5070,7 @@ const ComboboxTrigger = /*#__PURE__*/React__namespace.forwardRef(function Combob
5069
5070
  const {
5070
5071
  buttonRef,
5071
5072
  getButtonProps
5072
- } = NumberFieldInput.useButton({
5073
+ } = useBaseUiId.useButton({
5073
5074
  native: nativeButton,
5074
5075
  disabled
5075
5076
  });
@@ -5202,7 +5203,7 @@ const ComboboxInternalDismissButton = /*#__PURE__*/React__namespace.forwardRef(f
5202
5203
  const {
5203
5204
  buttonRef,
5204
5205
  getButtonProps
5205
- } = NumberFieldInput.useButton({
5206
+ } = useBaseUiId.useButton({
5206
5207
  native: false
5207
5208
  });
5208
5209
  const mergedRef = useRenderElement.useMergedRefs(forwardedRef, buttonRef);
@@ -5274,7 +5275,7 @@ const ComboboxInput = /*#__PURE__*/React__namespace.forwardRef(function Combobox
5274
5275
  const listEmpty = filteredItems.length === 0;
5275
5276
  const isInsidePopup = hasPositionerParent || inline;
5276
5277
  const focusManagerModal = !isInsidePopup || modal;
5277
- const id = NumberFieldInput.useBaseUiId(idProp ?? (!isInsidePopup ? rootId : undefined));
5278
+ const id = useBaseUiId.useBaseUiId(idProp ?? (!isInsidePopup ? rootId : undefined));
5278
5279
  const ariaLabelledBy = resolveAriaLabelledBy(fieldLabelId, undefined);
5279
5280
  const fieldStateForInput = hasPositionerParent ? NumberFieldInput.DEFAULT_FIELD_STATE_ATTRIBUTES : fieldState;
5280
5281
  const [composingValue, setComposingValue] = React__namespace.useState(null);
@@ -5708,7 +5709,7 @@ const ComboboxClear = /*#__PURE__*/React__namespace.forwardRef(function Combobox
5708
5709
  const {
5709
5710
  buttonRef,
5710
5711
  getButtonProps
5711
- } = NumberFieldInput.useButton({
5712
+ } = useBaseUiId.useButton({
5712
5713
  native: nativeButton,
5713
5714
  disabled
5714
5715
  });
@@ -6292,7 +6293,7 @@ const ComboboxGroupLabel = /*#__PURE__*/React__namespace.forwardRef(function Com
6292
6293
  const {
6293
6294
  setLabelId
6294
6295
  } = useComboboxGroupContext();
6295
- const id = NumberFieldInput.useBaseUiId(idProp);
6296
+ const id = useBaseUiId.useBaseUiId(idProp);
6296
6297
  useValueChanged.useIsoLayoutEffect(() => {
6297
6298
  setLabelId(id);
6298
6299
  return () => {
@@ -6419,7 +6420,7 @@ const ComboboxItem = /*#__PURE__*/React__namespace.memo(/*#__PURE__*/React__name
6419
6420
  const {
6420
6421
  getButtonProps,
6421
6422
  buttonRef
6422
- } = NumberFieldInput.useButton({
6423
+ } = useBaseUiId.useButton({
6423
6424
  disabled,
6424
6425
  focusableWhenDisabled: true,
6425
6426
  native: nativeButton,
@@ -6556,7 +6557,7 @@ function ComboboxRoot(props) {
6556
6557
  }
6557
6558
 
6558
6559
  function useRegisteredLabelId(idProp, setLabelId) {
6559
- const id = NumberFieldInput.useBaseUiId(idProp);
6560
+ const id = useBaseUiId.useBaseUiId(idProp);
6560
6561
  useValueChanged.useIsoLayoutEffect(() => {
6561
6562
  setLabelId(id);
6562
6563
  return () => {
@@ -6664,7 +6665,7 @@ const ComboboxLabel = /*#__PURE__*/React__namespace.forwardRef(function Combobox
6664
6665
  }
6665
6666
  const ownerStackMessage = useValueChanged.SafeReact.captureOwnerStack?.() || '';
6666
6667
  const message = '<Combobox.Label> labels <Combobox.Trigger> only. ' + 'When <Combobox.Input> is the form control, use a native <label> or <Field.Label> instead.';
6667
- NumberFieldInput.error(`${message}${ownerStackMessage}`);
6668
+ useBaseUiId.error(`${message}${ownerStackMessage}`);
6668
6669
  }, [inputElement, inputInsidePopup]);
6669
6670
  }
6670
6671
  const labelProps = useLabel({
@@ -6949,7 +6950,7 @@ const ComboboxChipRemove = /*#__PURE__*/React__namespace.forwardRef(function Com
6949
6950
  const {
6950
6951
  buttonRef,
6951
6952
  getButtonProps
6952
- } = NumberFieldInput.useButton({
6953
+ } = useBaseUiId.useButton({
6953
6954
  native: nativeButton,
6954
6955
  disabled: disabled || readOnly,
6955
6956
  focusableWhenDisabled: true
@@ -1,14 +1,15 @@
1
1
  import { u as useDialogRootContext, am as useDrawerProviderContext, an as DrawerBackdropCssVars, ao as DrawerPopupCssVars, ap as DrawerProviderContext, aq as CommonPopupDataAttributes, N as popupStateMapping, ar as useDialogPortalContext, as as DialogStore, l as contains, g as getTarget, at as useDrawerRootContext, al as useTriggerRegistration, au as DrawerPopupDataAttributes, av as useDrawerSnapPoints, aw as DrawerViewportContext, ax as BASE_UI_SWIPE_IGNORE_SELECTOR, ay as DRAWER_CONTENT_ATTRIBUTE, a as DrawerBackdrop, c as DrawerContent, b as DrawerPopup, D as DrawerPortal, d as DrawerRoot, V as inertValue, Z as createSelector, az as useStore, a4 as useOpenInteractionType, a9 as useDismiss, J as useInteractions, a2 as useOnFirstRender, aA as Store, ai as pressableTriggerOpenStateMapping, L as triggerOpenStateMapping, R as FloatingPortal, a7 as useScrollLock, U as InternalBackdrop, X as DROPDOWN_COLLISION_AVOIDANCE, Q as FloatingFocusManager } from '../DrawerRoot-es.js';
2
2
  import { b as DrawerClose, a as DrawerTitle, D as DrawerTrigger, u as useMenuRootContext, p as useMenuPositionerContext, q as useContextMenuRootContext, r as useCompositeListItem, s as useMenuItem, R as REGULAR_ITEM, t as itemMapping, v as useDirection, w as MenuStore, m as MenuGroup, o as MenuGroupLabel, d as MenuItem, c as MenuLinkItem, k as MenuPopup, i as MenuPortal, j as MenuPositioner, l as MenuRadioGroup, e as MenuRadioItem, f as MenuRadioItemIndicator, h as MenuRoot, n as MenuSubmenuRoot, g as MenuSubmenuTrigger, M as MenuTrigger, x as useFloatingRootContext, y as useClick, z as useListNavigation, A as useTypeahead, B as getPseudoElementBounds, C as CompositeList, E as useAnchorPositioning, F as getDisabledMountTransitionStyles, I as IndexGuessBehavior } from '../MenuSubmenuTrigger-es.js';
3
3
  import * as React from 'react';
4
- import { u as useRenderElement, m as mergeProps, f as formatErrorMessage, N as NOOP, E as EMPTY_OBJECT, d as EMPTY_ARRAY, a as useRefWithInit, c as useMergedRefs } from '../useRenderElement-es.js';
5
- import { u as useBaseUiId, b as useFormContext, c as useFieldRootContext, l as useLabelableId, m as useField, f as fieldValidityMapping, a as useLabelableContext, j as useButton, n as DEFAULT_FIELD_STATE_ATTRIBUTES, o as error, p as useNumberFieldRootContext, q as DEFAULT_STEP, s as stateAttributesMapping$9, i as NumberFieldDecrement, d as NumberFieldGroup, h as NumberFieldIncrement, e as NumberFieldInput, N as NumberFieldRoot } from '../NumberFieldInput-es.js';
6
- import { c as useIsoLayoutEffect, u as useStableCallback, t as transitionStatusMapping, k as createChangeEventDetails, V as imperativeAction, s as ownerDocument, g as clamp, a as useTimeout, a3 as swipe, D as useAnimationFrame, X as TransitionStatusDataAttributes, K as triggerHover, h as useControlled, P as itemPress, b as useTransitionStatus, d as useOpenChangeComplete, R as useAnimationsFinished, i as useValueAsRef, r as createGenericEventDetails, o as inputClear, m as inputChange, M as focusOut, Q as outsidePress, y as useValueChanged, n as none, a4 as inputPress, v as visuallyHiddenInput, l as visuallyHidden, z as stopEvent, L as listNavigation, B as closePress, a1 as isAndroid, a5 as isFirefox, J as escapeKey, a6 as clearPress, S as SafeReact, a7 as chipRemovePress, a8 as scrub, _ as isWebKit } from '../useValueChanged-es.js';
4
+ import { u as useRenderElement, m as mergeProps, f as formatErrorMessage, N as NOOP, E as EMPTY_OBJECT, d as EMPTY_ARRAY, b as useRefWithInit, c as useMergedRefs } from '../useRenderElement-es.js';
5
+ import { u as useBaseUiId, a as useButton, e as error } from '../useBaseUiId-es.js';
6
+ import { u as useIsoLayoutEffect, a as useStableCallback, t as transitionStatusMapping, k as createChangeEventDetails, V as imperativeAction, s as ownerDocument, g as clamp, c as useTimeout, a3 as swipe, D as useAnimationFrame, X as TransitionStatusDataAttributes, K as triggerHover, h as useControlled, P as itemPress, d as useTransitionStatus, e as useOpenChangeComplete, R as useAnimationsFinished, i as useValueAsRef, r as createGenericEventDetails, o as inputClear, m as inputChange, M as focusOut, Q as outsidePress, y as useValueChanged, n as none, a4 as inputPress, v as visuallyHiddenInput, l as visuallyHidden, z as stopEvent, L as listNavigation, B as closePress, a1 as isAndroid, a5 as isFirefox, J as escapeKey, a6 as clearPress, S as SafeReact, a7 as chipRemovePress, a8 as scrub, _ as isWebKit } from '../useValueChanged-es.js';
7
7
  import { jsx, jsxs } from 'react/jsx-runtime';
8
8
  import { a as isHTMLElement, f as getComputedStyle, b as isElement, k as getWindow } from '../floating-ui.utils.dom-es.js';
9
9
  import * as ReactDOM from 'react-dom';
10
10
  import { y as round } from '../index.esm-es.js';
11
11
  import { S as Separator } from '../Separator-es.js';
12
+ import { a as useFormContext, b as useFieldRootContext, i as useLabelableId, j as useField, f as fieldValidityMapping, u as useLabelableContext, k as DEFAULT_FIELD_STATE_ATTRIBUTES, l as useNumberFieldRootContext, m as DEFAULT_STEP, s as stateAttributesMapping$9, h as NumberFieldDecrement, c as NumberFieldGroup, e as NumberFieldIncrement, d as NumberFieldInput, N as NumberFieldRoot } from '../NumberFieldInput-es.js';
12
13
  import '../floating-ui.react-dom-es.js';
13
14
 
14
15
  /**
@@ -0,0 +1,275 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var floatingUi_utils_dom = require('./floating-ui.utils.dom-cjs.js');
5
+ var useValueChanged = require('./useValueChanged-cjs.js');
6
+ var useRenderElement = require('./useRenderElement-cjs.js');
7
+
8
+ function _interopNamespaceDefault(e) {
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n.default = e;
22
+ return Object.freeze(n);
23
+ }
24
+
25
+ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
26
+
27
+ let set;
28
+ if (process.env.NODE_ENV !== 'production') {
29
+ set = new Set();
30
+ }
31
+ function error(...messages) {
32
+ if (process.env.NODE_ENV !== 'production') {
33
+ const messageKey = messages.join(' ');
34
+ if (!set.has(messageKey)) {
35
+ set.add(messageKey);
36
+ console.error(`Base UI: ${messageKey}`);
37
+ }
38
+ }
39
+ }
40
+
41
+ const CompositeRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
42
+ if (process.env.NODE_ENV !== "production") CompositeRootContext.displayName = "CompositeRootContext";
43
+ function useCompositeRootContext(optional = false) {
44
+ const context = React__namespace.useContext(CompositeRootContext);
45
+ if (context === undefined && !optional) {
46
+ throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: CompositeRootContext is missing. Composite parts must be placed within <Composite.Root>.' : useRenderElement.formatErrorMessage(16));
47
+ }
48
+ return context;
49
+ }
50
+
51
+ function useFocusableWhenDisabled(parameters) {
52
+ const {
53
+ focusableWhenDisabled,
54
+ disabled,
55
+ composite = false,
56
+ tabIndex: tabIndexProp = 0,
57
+ isNativeButton
58
+ } = parameters;
59
+ const isFocusableComposite = composite && focusableWhenDisabled !== false;
60
+ const isNonFocusableComposite = composite && focusableWhenDisabled === false;
61
+
62
+ // we can't explicitly assign `undefined` to any of these props because it
63
+ // would otherwise prevent subsequently merged props from setting them
64
+ const props = React__namespace.useMemo(() => {
65
+ const additionalProps = {
66
+ // allow Tabbing away from focusableWhenDisabled elements
67
+ onKeyDown(event) {
68
+ if (disabled && focusableWhenDisabled && event.key !== 'Tab') {
69
+ event.preventDefault();
70
+ }
71
+ }
72
+ };
73
+ if (!composite) {
74
+ additionalProps.tabIndex = tabIndexProp;
75
+ if (!isNativeButton && disabled) {
76
+ additionalProps.tabIndex = focusableWhenDisabled ? tabIndexProp : -1;
77
+ }
78
+ }
79
+ if (isNativeButton && (focusableWhenDisabled || isFocusableComposite) || !isNativeButton && disabled) {
80
+ additionalProps['aria-disabled'] = disabled;
81
+ }
82
+ if (isNativeButton && (!focusableWhenDisabled || isNonFocusableComposite)) {
83
+ additionalProps.disabled = disabled;
84
+ }
85
+ return additionalProps;
86
+ }, [composite, disabled, focusableWhenDisabled, isFocusableComposite, isNonFocusableComposite, isNativeButton, tabIndexProp]);
87
+ return {
88
+ props
89
+ };
90
+ }
91
+
92
+ function useButton(parameters = {}) {
93
+ const {
94
+ disabled = false,
95
+ focusableWhenDisabled,
96
+ tabIndex = 0,
97
+ native: isNativeButton = true,
98
+ composite: compositeProp
99
+ } = parameters;
100
+ const elementRef = React__namespace.useRef(null);
101
+ const compositeRootContext = useCompositeRootContext(true);
102
+ const isCompositeItem = compositeProp ?? compositeRootContext !== undefined;
103
+ const {
104
+ props: focusableWhenDisabledProps
105
+ } = useFocusableWhenDisabled({
106
+ focusableWhenDisabled,
107
+ disabled,
108
+ composite: isCompositeItem,
109
+ tabIndex,
110
+ isNativeButton
111
+ });
112
+ if (process.env.NODE_ENV !== 'production') {
113
+ // eslint-disable-next-line react-hooks/rules-of-hooks
114
+ React__namespace.useEffect(() => {
115
+ if (!elementRef.current) {
116
+ return;
117
+ }
118
+ const isButtonTag = isButtonElement(elementRef.current);
119
+ if (isNativeButton) {
120
+ if (!isButtonTag) {
121
+ const ownerStackMessage = useValueChanged.SafeReact.captureOwnerStack?.() || '';
122
+ const message = 'A component that acts as a button expected a native <button> because the ' + '`nativeButton` prop is true. Rendering a non-<button> removes native button ' + 'semantics, which can impact forms and accessibility. Use a real <button> in the ' + '`render` prop, or set `nativeButton` to `false`.';
123
+ error(`${message}${ownerStackMessage}`);
124
+ }
125
+ } else if (isButtonTag) {
126
+ const ownerStackMessage = useValueChanged.SafeReact.captureOwnerStack?.() || '';
127
+ const message = 'A component that acts as a button expected a non-<button> because the `nativeButton` ' + 'prop is false. Rendering a <button> keeps native behavior while Base UI applies ' + 'non-native attributes and handlers, which can add unintended extra attributes (such ' + 'as `role` or `aria-disabled`). Use a non-<button> in the `render` prop, or set ' + '`nativeButton` to `true`.';
128
+ error(`${message}${ownerStackMessage}`);
129
+ }
130
+ }, [isNativeButton]);
131
+ }
132
+
133
+ // handles a disabled composite button rendering another button, e.g.
134
+ // <Toolbar.Button disabled render={<Menu.Trigger />} />
135
+ // the `disabled` prop needs to pass through 2 `useButton`s then finally
136
+ // delete the `disabled` attribute from DOM
137
+ const updateDisabled = React__namespace.useCallback(() => {
138
+ const element = elementRef.current;
139
+ if (!isButtonElement(element)) {
140
+ return;
141
+ }
142
+ if (isCompositeItem && disabled && focusableWhenDisabledProps.disabled === undefined && element.disabled) {
143
+ element.disabled = false;
144
+ }
145
+ }, [disabled, focusableWhenDisabledProps.disabled, isCompositeItem]);
146
+ useValueChanged.useIsoLayoutEffect(updateDisabled, [updateDisabled]);
147
+ const getButtonProps = React__namespace.useCallback((externalProps = {}) => {
148
+ const {
149
+ onClick: externalOnClick,
150
+ onMouseDown: externalOnMouseDown,
151
+ onKeyUp: externalOnKeyUp,
152
+ onKeyDown: externalOnKeyDown,
153
+ onPointerDown: externalOnPointerDown,
154
+ ...otherExternalProps
155
+ } = externalProps;
156
+ const type = isNativeButton ? 'button' : undefined;
157
+ return useRenderElement.mergeProps({
158
+ type,
159
+ onClick(event) {
160
+ if (disabled) {
161
+ event.preventDefault();
162
+ return;
163
+ }
164
+ externalOnClick?.(event);
165
+ },
166
+ onMouseDown(event) {
167
+ if (!disabled) {
168
+ externalOnMouseDown?.(event);
169
+ }
170
+ },
171
+ onKeyDown(event) {
172
+ if (disabled) {
173
+ return;
174
+ }
175
+ useRenderElement.makeEventPreventable(event);
176
+ externalOnKeyDown?.(event);
177
+ if (event.baseUIHandlerPrevented) {
178
+ return;
179
+ }
180
+ const isCurrentTarget = event.target === event.currentTarget;
181
+ const currentTarget = event.currentTarget;
182
+ const isButton = isButtonElement(currentTarget);
183
+ const isLink = !isNativeButton && isValidLinkElement(currentTarget);
184
+ const shouldClick = isCurrentTarget && (isNativeButton ? isButton : !isLink);
185
+ const isEnterKey = event.key === 'Enter';
186
+ const isSpaceKey = event.key === ' ';
187
+ const role = currentTarget.getAttribute('role');
188
+ const isTextNavigationRole = role?.startsWith('menuitem') || role === 'option' || role === 'gridcell';
189
+ if (isCurrentTarget && isCompositeItem && isSpaceKey) {
190
+ if (event.defaultPrevented && isTextNavigationRole) {
191
+ return;
192
+ }
193
+ event.preventDefault();
194
+ if (isLink || isNativeButton && isButton) {
195
+ currentTarget.click();
196
+ event.preventBaseUIHandler();
197
+ } else if (shouldClick) {
198
+ externalOnClick?.(event);
199
+ event.preventBaseUIHandler();
200
+ }
201
+ return;
202
+ }
203
+
204
+ // Keyboard accessibility for native and non-native elements.
205
+ if (shouldClick) {
206
+ if (!isNativeButton && (isSpaceKey || isEnterKey)) {
207
+ event.preventDefault();
208
+ }
209
+ if (!isNativeButton && isEnterKey) {
210
+ externalOnClick?.(event);
211
+ }
212
+ }
213
+ },
214
+ onKeyUp(event) {
215
+ if (disabled) {
216
+ return;
217
+ }
218
+
219
+ // calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed
220
+ // https://codesandbox.io/p/sandbox/button-keyup-preventdefault-dn7f0
221
+ useRenderElement.makeEventPreventable(event);
222
+ externalOnKeyUp?.(event);
223
+ if (event.target === event.currentTarget && isNativeButton && isCompositeItem && isButtonElement(event.currentTarget) && event.key === ' ') {
224
+ event.preventDefault();
225
+ return;
226
+ }
227
+ if (event.baseUIHandlerPrevented) {
228
+ return;
229
+ }
230
+
231
+ // Keyboard accessibility for non interactive elements
232
+ if (event.target === event.currentTarget && !isNativeButton && !isCompositeItem && event.key === ' ') {
233
+ externalOnClick?.(event);
234
+ }
235
+ },
236
+ onPointerDown(event) {
237
+ if (disabled) {
238
+ event.preventDefault();
239
+ return;
240
+ }
241
+ externalOnPointerDown?.(event);
242
+ }
243
+ }, !isNativeButton ? {
244
+ role: 'button'
245
+ } : undefined, focusableWhenDisabledProps, otherExternalProps);
246
+ }, [disabled, focusableWhenDisabledProps, isCompositeItem, isNativeButton]);
247
+ const buttonRef = useValueChanged.useStableCallback(element => {
248
+ elementRef.current = element;
249
+ updateDisabled();
250
+ });
251
+ return {
252
+ getButtonProps,
253
+ buttonRef
254
+ };
255
+ }
256
+ function isButtonElement(elem) {
257
+ return floatingUi_utils_dom.isHTMLElement(elem) && elem.tagName === 'BUTTON';
258
+ }
259
+ function isValidLinkElement(elem) {
260
+ return Boolean(elem?.tagName === 'A' && elem?.href);
261
+ }
262
+
263
+ /**
264
+ * Wraps `useId` and prefixes generated `id`s with `base-ui-`
265
+ * @param {string | undefined} idOverride overrides the generated id when provided
266
+ * @returns {string | undefined}
267
+ */
268
+ function useBaseUiId(idOverride) {
269
+ return useValueChanged.useId(idOverride, 'base-ui');
270
+ }
271
+
272
+ exports.error = error;
273
+ exports.useBaseUiId = useBaseUiId;
274
+ exports.useButton = useButton;
275
+ exports.useCompositeRootContext = useCompositeRootContext;
@@ -0,0 +1,251 @@
1
+ import * as React from 'react';
2
+ import { a as isHTMLElement } from './floating-ui.utils.dom-es.js';
3
+ import { S as SafeReact, u as useIsoLayoutEffect, a as useStableCallback, b as useId } from './useValueChanged-es.js';
4
+ import { f as formatErrorMessage, m as mergeProps, a as makeEventPreventable } from './useRenderElement-es.js';
5
+
6
+ let set;
7
+ if (process.env.NODE_ENV !== 'production') {
8
+ set = new Set();
9
+ }
10
+ function error(...messages) {
11
+ if (process.env.NODE_ENV !== 'production') {
12
+ const messageKey = messages.join(' ');
13
+ if (!set.has(messageKey)) {
14
+ set.add(messageKey);
15
+ console.error(`Base UI: ${messageKey}`);
16
+ }
17
+ }
18
+ }
19
+
20
+ const CompositeRootContext = /*#__PURE__*/React.createContext(undefined);
21
+ if (process.env.NODE_ENV !== "production") CompositeRootContext.displayName = "CompositeRootContext";
22
+ function useCompositeRootContext(optional = false) {
23
+ const context = React.useContext(CompositeRootContext);
24
+ if (context === undefined && !optional) {
25
+ throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: CompositeRootContext is missing. Composite parts must be placed within <Composite.Root>.' : formatErrorMessage(16));
26
+ }
27
+ return context;
28
+ }
29
+
30
+ function useFocusableWhenDisabled(parameters) {
31
+ const {
32
+ focusableWhenDisabled,
33
+ disabled,
34
+ composite = false,
35
+ tabIndex: tabIndexProp = 0,
36
+ isNativeButton
37
+ } = parameters;
38
+ const isFocusableComposite = composite && focusableWhenDisabled !== false;
39
+ const isNonFocusableComposite = composite && focusableWhenDisabled === false;
40
+
41
+ // we can't explicitly assign `undefined` to any of these props because it
42
+ // would otherwise prevent subsequently merged props from setting them
43
+ const props = React.useMemo(() => {
44
+ const additionalProps = {
45
+ // allow Tabbing away from focusableWhenDisabled elements
46
+ onKeyDown(event) {
47
+ if (disabled && focusableWhenDisabled && event.key !== 'Tab') {
48
+ event.preventDefault();
49
+ }
50
+ }
51
+ };
52
+ if (!composite) {
53
+ additionalProps.tabIndex = tabIndexProp;
54
+ if (!isNativeButton && disabled) {
55
+ additionalProps.tabIndex = focusableWhenDisabled ? tabIndexProp : -1;
56
+ }
57
+ }
58
+ if (isNativeButton && (focusableWhenDisabled || isFocusableComposite) || !isNativeButton && disabled) {
59
+ additionalProps['aria-disabled'] = disabled;
60
+ }
61
+ if (isNativeButton && (!focusableWhenDisabled || isNonFocusableComposite)) {
62
+ additionalProps.disabled = disabled;
63
+ }
64
+ return additionalProps;
65
+ }, [composite, disabled, focusableWhenDisabled, isFocusableComposite, isNonFocusableComposite, isNativeButton, tabIndexProp]);
66
+ return {
67
+ props
68
+ };
69
+ }
70
+
71
+ function useButton(parameters = {}) {
72
+ const {
73
+ disabled = false,
74
+ focusableWhenDisabled,
75
+ tabIndex = 0,
76
+ native: isNativeButton = true,
77
+ composite: compositeProp
78
+ } = parameters;
79
+ const elementRef = React.useRef(null);
80
+ const compositeRootContext = useCompositeRootContext(true);
81
+ const isCompositeItem = compositeProp ?? compositeRootContext !== undefined;
82
+ const {
83
+ props: focusableWhenDisabledProps
84
+ } = useFocusableWhenDisabled({
85
+ focusableWhenDisabled,
86
+ disabled,
87
+ composite: isCompositeItem,
88
+ tabIndex,
89
+ isNativeButton
90
+ });
91
+ if (process.env.NODE_ENV !== 'production') {
92
+ // eslint-disable-next-line react-hooks/rules-of-hooks
93
+ React.useEffect(() => {
94
+ if (!elementRef.current) {
95
+ return;
96
+ }
97
+ const isButtonTag = isButtonElement(elementRef.current);
98
+ if (isNativeButton) {
99
+ if (!isButtonTag) {
100
+ const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
101
+ const message = 'A component that acts as a button expected a native <button> because the ' + '`nativeButton` prop is true. Rendering a non-<button> removes native button ' + 'semantics, which can impact forms and accessibility. Use a real <button> in the ' + '`render` prop, or set `nativeButton` to `false`.';
102
+ error(`${message}${ownerStackMessage}`);
103
+ }
104
+ } else if (isButtonTag) {
105
+ const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
106
+ const message = 'A component that acts as a button expected a non-<button> because the `nativeButton` ' + 'prop is false. Rendering a <button> keeps native behavior while Base UI applies ' + 'non-native attributes and handlers, which can add unintended extra attributes (such ' + 'as `role` or `aria-disabled`). Use a non-<button> in the `render` prop, or set ' + '`nativeButton` to `true`.';
107
+ error(`${message}${ownerStackMessage}`);
108
+ }
109
+ }, [isNativeButton]);
110
+ }
111
+
112
+ // handles a disabled composite button rendering another button, e.g.
113
+ // <Toolbar.Button disabled render={<Menu.Trigger />} />
114
+ // the `disabled` prop needs to pass through 2 `useButton`s then finally
115
+ // delete the `disabled` attribute from DOM
116
+ const updateDisabled = React.useCallback(() => {
117
+ const element = elementRef.current;
118
+ if (!isButtonElement(element)) {
119
+ return;
120
+ }
121
+ if (isCompositeItem && disabled && focusableWhenDisabledProps.disabled === undefined && element.disabled) {
122
+ element.disabled = false;
123
+ }
124
+ }, [disabled, focusableWhenDisabledProps.disabled, isCompositeItem]);
125
+ useIsoLayoutEffect(updateDisabled, [updateDisabled]);
126
+ const getButtonProps = React.useCallback((externalProps = {}) => {
127
+ const {
128
+ onClick: externalOnClick,
129
+ onMouseDown: externalOnMouseDown,
130
+ onKeyUp: externalOnKeyUp,
131
+ onKeyDown: externalOnKeyDown,
132
+ onPointerDown: externalOnPointerDown,
133
+ ...otherExternalProps
134
+ } = externalProps;
135
+ const type = isNativeButton ? 'button' : undefined;
136
+ return mergeProps({
137
+ type,
138
+ onClick(event) {
139
+ if (disabled) {
140
+ event.preventDefault();
141
+ return;
142
+ }
143
+ externalOnClick?.(event);
144
+ },
145
+ onMouseDown(event) {
146
+ if (!disabled) {
147
+ externalOnMouseDown?.(event);
148
+ }
149
+ },
150
+ onKeyDown(event) {
151
+ if (disabled) {
152
+ return;
153
+ }
154
+ makeEventPreventable(event);
155
+ externalOnKeyDown?.(event);
156
+ if (event.baseUIHandlerPrevented) {
157
+ return;
158
+ }
159
+ const isCurrentTarget = event.target === event.currentTarget;
160
+ const currentTarget = event.currentTarget;
161
+ const isButton = isButtonElement(currentTarget);
162
+ const isLink = !isNativeButton && isValidLinkElement(currentTarget);
163
+ const shouldClick = isCurrentTarget && (isNativeButton ? isButton : !isLink);
164
+ const isEnterKey = event.key === 'Enter';
165
+ const isSpaceKey = event.key === ' ';
166
+ const role = currentTarget.getAttribute('role');
167
+ const isTextNavigationRole = role?.startsWith('menuitem') || role === 'option' || role === 'gridcell';
168
+ if (isCurrentTarget && isCompositeItem && isSpaceKey) {
169
+ if (event.defaultPrevented && isTextNavigationRole) {
170
+ return;
171
+ }
172
+ event.preventDefault();
173
+ if (isLink || isNativeButton && isButton) {
174
+ currentTarget.click();
175
+ event.preventBaseUIHandler();
176
+ } else if (shouldClick) {
177
+ externalOnClick?.(event);
178
+ event.preventBaseUIHandler();
179
+ }
180
+ return;
181
+ }
182
+
183
+ // Keyboard accessibility for native and non-native elements.
184
+ if (shouldClick) {
185
+ if (!isNativeButton && (isSpaceKey || isEnterKey)) {
186
+ event.preventDefault();
187
+ }
188
+ if (!isNativeButton && isEnterKey) {
189
+ externalOnClick?.(event);
190
+ }
191
+ }
192
+ },
193
+ onKeyUp(event) {
194
+ if (disabled) {
195
+ return;
196
+ }
197
+
198
+ // calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed
199
+ // https://codesandbox.io/p/sandbox/button-keyup-preventdefault-dn7f0
200
+ makeEventPreventable(event);
201
+ externalOnKeyUp?.(event);
202
+ if (event.target === event.currentTarget && isNativeButton && isCompositeItem && isButtonElement(event.currentTarget) && event.key === ' ') {
203
+ event.preventDefault();
204
+ return;
205
+ }
206
+ if (event.baseUIHandlerPrevented) {
207
+ return;
208
+ }
209
+
210
+ // Keyboard accessibility for non interactive elements
211
+ if (event.target === event.currentTarget && !isNativeButton && !isCompositeItem && event.key === ' ') {
212
+ externalOnClick?.(event);
213
+ }
214
+ },
215
+ onPointerDown(event) {
216
+ if (disabled) {
217
+ event.preventDefault();
218
+ return;
219
+ }
220
+ externalOnPointerDown?.(event);
221
+ }
222
+ }, !isNativeButton ? {
223
+ role: 'button'
224
+ } : undefined, focusableWhenDisabledProps, otherExternalProps);
225
+ }, [disabled, focusableWhenDisabledProps, isCompositeItem, isNativeButton]);
226
+ const buttonRef = useStableCallback(element => {
227
+ elementRef.current = element;
228
+ updateDisabled();
229
+ });
230
+ return {
231
+ getButtonProps,
232
+ buttonRef
233
+ };
234
+ }
235
+ function isButtonElement(elem) {
236
+ return isHTMLElement(elem) && elem.tagName === 'BUTTON';
237
+ }
238
+ function isValidLinkElement(elem) {
239
+ return Boolean(elem?.tagName === 'A' && elem?.href);
240
+ }
241
+
242
+ /**
243
+ * Wraps `useId` and prefixes generated `id`s with `base-ui-`
244
+ * @param {string | undefined} idOverride overrides the generated id when provided
245
+ * @returns {string | undefined}
246
+ */
247
+ function useBaseUiId(idOverride) {
248
+ return useId(idOverride, 'base-ui');
249
+ }
250
+
251
+ export { useButton as a, useCompositeRootContext as b, error as e, useBaseUiId as u };
@@ -566,4 +566,4 @@ function renderTag(Tag, props) {
566
566
  return /*#__PURE__*/React.createElement(Tag, props);
567
567
  }
568
568
 
569
- export { EMPTY_OBJECT as E, NOOP as N, useRefWithInit as a, makeEventPreventable as b, useMergedRefs as c, EMPTY_ARRAY as d, formatErrorMessage as f, isReactVersionAtLeast as i, mergeProps as m, useRenderElement as u };
569
+ export { EMPTY_OBJECT as E, NOOP as N, makeEventPreventable as a, useRefWithInit as b, useMergedRefs as c, EMPTY_ARRAY as d, formatErrorMessage as f, isReactVersionAtLeast as i, mergeProps as m, useRenderElement as u };