@jobber/components 8.20.2 → 8.21.0
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/BottomSheet-cjs.js +9 -58
- package/dist/BottomSheet-es.js +2 -47
- package/dist/Card/index.cjs +4 -0
- package/dist/Card/index.mjs +4 -0
- package/dist/ComboboxChipRemove-cjs.js +3418 -0
- package/dist/ComboboxChipRemove-es.js +3366 -0
- package/dist/ComboboxPrimitive-cjs.js +170 -0
- package/dist/ComboboxPrimitive-es.js +168 -0
- package/dist/DataDump/index.cjs +4 -0
- package/dist/DataDump/index.mjs +4 -0
- package/dist/InputNumberExperimental-cjs.js +45 -44
- package/dist/InputNumberExperimental-es.js +3 -2
- package/dist/InternalBackdrop-cjs.js +4278 -0
- package/dist/InternalBackdrop-es.js +4204 -0
- package/dist/Menu/index.cjs +4 -0
- package/dist/Menu/index.mjs +4 -0
- package/dist/Menu-cjs.js +9 -8
- package/dist/Menu-es.js +2 -1
- package/dist/MenuSubmenuTrigger-cjs.js +208 -1969
- package/dist/MenuSubmenuTrigger-es.js +7 -1759
- package/dist/NumberFieldInput-cjs.js +56 -439
- package/dist/NumberFieldInput-es.js +6 -376
- package/dist/Page/index.cjs +4 -0
- package/dist/Page/index.mjs +4 -0
- package/dist/ScrollAreaViewport-cjs.js +108 -4356
- package/dist/ScrollAreaViewport-es.js +6 -4201
- package/dist/buttonRenderAdapter-cjs.js +56 -0
- package/dist/buttonRenderAdapter-es.js +51 -0
- package/dist/clamp-cjs.js +0 -1194
- package/dist/clamp-es.js +1 -1091
- package/dist/docs/empty-states/empty-states.md +29 -0
- package/dist/index.cjs +4 -0
- package/dist/index.mjs +4 -0
- package/dist/primitives/BottomSheet/index.cjs +5 -2
- package/dist/primitives/BottomSheet/index.mjs +5 -2
- package/dist/primitives/ComboboxPrimitive/ComboboxPrimitive.d.ts +32 -0
- package/dist/primitives/ComboboxPrimitive/ComboboxPrimitive.types.d.ts +30 -0
- package/dist/primitives/ComboboxPrimitive/index.cjs +28 -0
- package/dist/primitives/ComboboxPrimitive/index.d.ts +2 -0
- package/dist/primitives/ComboboxPrimitive/index.mjs +22 -0
- package/dist/primitives/InputNumberExperimental/index.cjs +4 -2
- package/dist/primitives/InputNumberExperimental/index.mjs +4 -2
- package/dist/primitives/index.cjs +11 -2
- package/dist/primitives/index.d.ts +1 -0
- package/dist/primitives/index.mjs +10 -2
- package/dist/styles.css +767 -0
- package/dist/unstyledPrimitives/index.cjs +237 -3588
- package/dist/unstyledPrimitives/index.mjs +96 -3447
- package/dist/useButton-cjs.js +1196 -0
- package/dist/useButton-es.js +1091 -0
- package/dist/useCompositeListItem-cjs.js +1792 -0
- package/dist/useCompositeListItem-es.js +1762 -0
- package/dist/useLabel-cjs.js +411 -0
- package/dist/useLabel-es.js +378 -0
- package/package.json +2 -2
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var useRenderElement = require('../useRenderElement-cjs.js');
|
|
4
|
+
var useButton = require('../useButton-cjs.js');
|
|
5
|
+
var ComboboxChipRemove = require('../ComboboxChipRemove-cjs.js');
|
|
7
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
-
var NumberFieldInput = require('../NumberFieldInput-cjs.js');
|
|
9
|
-
var MenuSubmenuTrigger = require('../MenuSubmenuTrigger-cjs.js');
|
|
10
|
-
var ReactDOM = require('react-dom');
|
|
11
7
|
var Separator = require('../Separator-cjs.js');
|
|
8
|
+
var ScrollAreaViewport = require('../ScrollAreaViewport-cjs.js');
|
|
9
|
+
var MenuSubmenuTrigger = require('../MenuSubmenuTrigger-cjs.js');
|
|
10
|
+
var useRenderElement = require('../useRenderElement-cjs.js');
|
|
12
11
|
var floatingUi_utils_dom = require('../floating-ui.utils.dom-cjs.js');
|
|
12
|
+
var clamp = require('../clamp-cjs.js');
|
|
13
|
+
var InternalBackdrop = require('../InternalBackdrop-cjs.js');
|
|
14
|
+
var ReactDOM = require('react-dom');
|
|
15
|
+
var useCompositeListItem = require('../useCompositeListItem-cjs.js');
|
|
13
16
|
var index_esm = require('../index.esm-cjs.js');
|
|
17
|
+
var NumberFieldInput = require('../NumberFieldInput-cjs.js');
|
|
18
|
+
require('../useLabel-cjs.js');
|
|
14
19
|
require('../floating-ui.react-dom-cjs.js');
|
|
15
20
|
|
|
16
21
|
function _interopNamespaceDefault(e) {
|
|
@@ -33,3098 +38,140 @@ function _interopNamespaceDefault(e) {
|
|
|
33
38
|
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
34
39
|
var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM);
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
if (process.env.NODE_ENV !== "production") ComboboxRootContext.displayName = "ComboboxRootContext";
|
|
38
|
-
const ComboboxFloatingContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
39
|
-
if (process.env.NODE_ENV !== "production") ComboboxFloatingContext.displayName = "ComboboxFloatingContext";
|
|
40
|
-
const ComboboxDerivedItemsContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
41
|
-
// `inputValue` can't be placed in the store.
|
|
42
|
-
// https://github.com/mui/base-ui/issues/2703
|
|
43
|
-
if (process.env.NODE_ENV !== "production") ComboboxDerivedItemsContext.displayName = "ComboboxDerivedItemsContext";
|
|
44
|
-
const ComboboxInputValueContext = /*#__PURE__*/React__namespace.createContext('');
|
|
45
|
-
if (process.env.NODE_ENV !== "production") ComboboxInputValueContext.displayName = "ComboboxInputValueContext";
|
|
46
|
-
function useComboboxRootContext() {
|
|
47
|
-
const context = React__namespace.useContext(ComboboxRootContext);
|
|
48
|
-
if (!context) {
|
|
49
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ComboboxRootContext is missing. Combobox parts must be placed within <Combobox.Root>.' : useRenderElement.formatErrorMessage(22));
|
|
50
|
-
}
|
|
51
|
-
return context;
|
|
52
|
-
}
|
|
53
|
-
function useComboboxFloatingContext() {
|
|
54
|
-
const context = React__namespace.useContext(ComboboxFloatingContext);
|
|
55
|
-
if (!context) {
|
|
56
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ComboboxFloatingContext is missing. Combobox parts must be placed within <Combobox.Root>.' : useRenderElement.formatErrorMessage(23));
|
|
57
|
-
}
|
|
58
|
-
return context;
|
|
59
|
-
}
|
|
60
|
-
function useComboboxDerivedItemsContext() {
|
|
61
|
-
const context = React__namespace.useContext(ComboboxDerivedItemsContext);
|
|
62
|
-
if (!context) {
|
|
63
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ComboboxItemsContext is missing. Combobox parts must be placed within <Combobox.Root>.' : useRenderElement.formatErrorMessage(24));
|
|
64
|
-
}
|
|
65
|
-
return context;
|
|
66
|
-
}
|
|
67
|
-
function useComboboxInputValueContext() {
|
|
68
|
-
return React__namespace.useContext(ComboboxInputValueContext);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const defaultItemEquality = (itemValue, selectedValue) => Object.is(itemValue, selectedValue);
|
|
72
|
-
function compareItemEquality(itemValue, selectedValue, comparer) {
|
|
73
|
-
if (itemValue == null || selectedValue == null) {
|
|
74
|
-
return Object.is(itemValue, selectedValue);
|
|
75
|
-
}
|
|
76
|
-
return comparer(itemValue, selectedValue);
|
|
77
|
-
}
|
|
78
|
-
function selectedValueIncludes(selectedValues, itemValue, comparer) {
|
|
79
|
-
if (!selectedValues || selectedValues.length === 0) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
return selectedValues.some(selectedValue => {
|
|
83
|
-
if (selectedValue === undefined) {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
return compareItemEquality(itemValue, selectedValue, comparer);
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
function findItemIndex(itemValues, selectedValue, comparer) {
|
|
90
|
-
if (!itemValues || itemValues.length === 0) {
|
|
91
|
-
return -1;
|
|
92
|
-
}
|
|
93
|
-
return itemValues.findIndex(itemValue => {
|
|
94
|
-
if (itemValue === undefined) {
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
return compareItemEquality(itemValue, selectedValue, comparer);
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
function removeItem(selectedValues, itemValue, comparer) {
|
|
101
|
-
return selectedValues.filter(selectedValue => !compareItemEquality(itemValue, selectedValue, comparer));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function serializeValue(value) {
|
|
105
|
-
if (value == null) {
|
|
106
|
-
return '';
|
|
107
|
-
}
|
|
108
|
-
if (typeof value === 'string') {
|
|
109
|
-
return value;
|
|
110
|
-
}
|
|
111
|
-
try {
|
|
112
|
-
return JSON.stringify(value);
|
|
113
|
-
} catch {
|
|
114
|
-
return String(value);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function isGroupedItems(items) {
|
|
119
|
-
return items != null && items.length > 0 && typeof items[0] === 'object' && items[0] != null && 'items' in items[0];
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Checks if the items array contains an item with a null value that has a non-null label.
|
|
124
|
-
*/
|
|
125
|
-
function hasNullItemLabel(items) {
|
|
126
|
-
if (!Array.isArray(items)) {
|
|
127
|
-
return items != null && 'null' in items;
|
|
128
|
-
}
|
|
129
|
-
const arrayItems = items;
|
|
130
|
-
if (isGroupedItems(arrayItems)) {
|
|
131
|
-
for (const group of arrayItems) {
|
|
132
|
-
for (const item of group.items) {
|
|
133
|
-
if (item && item.value == null && item.label != null) {
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
for (const item of arrayItems) {
|
|
141
|
-
if (item && item.value == null && item.label != null) {
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
function stringifyAsLabel(item, itemToStringLabel) {
|
|
148
|
-
if (itemToStringLabel && item != null) {
|
|
149
|
-
return itemToStringLabel(item) ?? '';
|
|
150
|
-
}
|
|
151
|
-
if (item && typeof item === 'object') {
|
|
152
|
-
if ('label' in item && item.label != null) {
|
|
153
|
-
return String(item.label);
|
|
154
|
-
}
|
|
155
|
-
if ('value' in item) {
|
|
156
|
-
return String(item.value);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
return serializeValue(item);
|
|
160
|
-
}
|
|
161
|
-
function stringifyAsValue(item, itemToStringValue) {
|
|
162
|
-
if (itemToStringValue && item != null) {
|
|
163
|
-
return itemToStringValue(item) ?? '';
|
|
164
|
-
}
|
|
165
|
-
if (item && typeof item === 'object' && 'value' in item && 'label' in item) {
|
|
166
|
-
return serializeValue(item.value);
|
|
167
|
-
}
|
|
168
|
-
return serializeValue(item);
|
|
169
|
-
}
|
|
170
|
-
function resolveSelectedLabel(value, items, itemToStringLabel) {
|
|
171
|
-
function fallback() {
|
|
172
|
-
return stringifyAsLabel(value, itemToStringLabel);
|
|
173
|
-
}
|
|
174
|
-
if (itemToStringLabel && value != null) {
|
|
175
|
-
return itemToStringLabel(value);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Custom object with explicit label takes precedence
|
|
179
|
-
if (value && typeof value === 'object' && 'label' in value && value.label != null) {
|
|
180
|
-
return value.label;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Items provided as plain record map
|
|
184
|
-
if (items && !Array.isArray(items)) {
|
|
185
|
-
return items[value] ?? fallback();
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Items provided as array (flat or grouped)
|
|
189
|
-
if (Array.isArray(items)) {
|
|
190
|
-
const arrayItems = items;
|
|
191
|
-
const flatItems = isGroupedItems(arrayItems) ? arrayItems.flatMap(group => group.items) : arrayItems;
|
|
192
|
-
if (value == null || typeof value !== 'object') {
|
|
193
|
-
const match = flatItems.find(item => item.value === value);
|
|
194
|
-
if (match && match.label != null) {
|
|
195
|
-
return match.label;
|
|
196
|
-
}
|
|
197
|
-
return fallback();
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Object without explicit label: try matching by its `value` property
|
|
201
|
-
if ('value' in value) {
|
|
202
|
-
const match = flatItems.find(item => item && item.value === value.value);
|
|
203
|
-
if (match && match.label != null) {
|
|
204
|
-
return match.label;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
return fallback();
|
|
209
|
-
}
|
|
210
|
-
function resolveMultipleLabels(values, items, itemToStringLabel) {
|
|
211
|
-
return values.reduce((acc, value, index) => {
|
|
212
|
-
if (index > 0) {
|
|
213
|
-
acc.push(', ');
|
|
214
|
-
}
|
|
215
|
-
acc.push(/*#__PURE__*/jsxRuntime.jsx(React__namespace.Fragment, {
|
|
216
|
-
children: resolveSelectedLabel(value, items, itemToStringLabel)
|
|
217
|
-
}, index));
|
|
218
|
-
return acc;
|
|
219
|
-
}, []);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const selectors = {
|
|
223
|
-
id: ScrollAreaViewport.createSelector(state => state.id),
|
|
224
|
-
labelId: ScrollAreaViewport.createSelector(state => state.labelId),
|
|
225
|
-
query: ScrollAreaViewport.createSelector(state => state.query),
|
|
226
|
-
items: ScrollAreaViewport.createSelector(state => state.items),
|
|
227
|
-
selectedValue: ScrollAreaViewport.createSelector(state => state.selectedValue),
|
|
228
|
-
hasSelectionChips: ScrollAreaViewport.createSelector(state => {
|
|
229
|
-
const selectedValue = state.selectedValue;
|
|
230
|
-
return Array.isArray(selectedValue) && selectedValue.length > 0;
|
|
231
|
-
}),
|
|
232
|
-
hasSelectedValue: ScrollAreaViewport.createSelector(state => {
|
|
233
|
-
const {
|
|
234
|
-
selectedValue,
|
|
235
|
-
selectionMode
|
|
236
|
-
} = state;
|
|
237
|
-
if (selectedValue == null) {
|
|
238
|
-
return false;
|
|
239
|
-
}
|
|
240
|
-
if (selectionMode === 'multiple' && Array.isArray(selectedValue)) {
|
|
241
|
-
return selectedValue.length > 0;
|
|
242
|
-
}
|
|
243
|
-
return true;
|
|
244
|
-
}),
|
|
245
|
-
hasNullItemLabel: ScrollAreaViewport.createSelector((state, enabled) => {
|
|
246
|
-
return enabled ? hasNullItemLabel(state.items) : false;
|
|
247
|
-
}),
|
|
248
|
-
open: ScrollAreaViewport.createSelector(state => state.open),
|
|
249
|
-
mounted: ScrollAreaViewport.createSelector(state => state.mounted),
|
|
250
|
-
forceMounted: ScrollAreaViewport.createSelector(state => state.forceMounted),
|
|
251
|
-
inline: ScrollAreaViewport.createSelector(state => state.inline),
|
|
252
|
-
activeIndex: ScrollAreaViewport.createSelector(state => state.activeIndex),
|
|
253
|
-
selectedIndex: ScrollAreaViewport.createSelector(state => state.selectedIndex),
|
|
254
|
-
isActive: ScrollAreaViewport.createSelector((state, index) => state.activeIndex === index),
|
|
255
|
-
isSelected: ScrollAreaViewport.createSelector((state, itemValue) => {
|
|
256
|
-
const comparer = state.isItemEqualToValue;
|
|
257
|
-
const selectedValue = state.selectedValue;
|
|
258
|
-
if (Array.isArray(selectedValue)) {
|
|
259
|
-
return selectedValue.some(selectedItem => compareItemEquality(itemValue, selectedItem, comparer));
|
|
260
|
-
}
|
|
261
|
-
return compareItemEquality(itemValue, selectedValue, comparer);
|
|
262
|
-
}),
|
|
263
|
-
transitionStatus: ScrollAreaViewport.createSelector(state => state.transitionStatus),
|
|
264
|
-
popupProps: ScrollAreaViewport.createSelector(state => state.popupProps),
|
|
265
|
-
inputProps: ScrollAreaViewport.createSelector(state => state.inputProps),
|
|
266
|
-
triggerProps: ScrollAreaViewport.createSelector(state => state.triggerProps),
|
|
267
|
-
getItemProps: ScrollAreaViewport.createSelector(state => state.getItemProps),
|
|
268
|
-
positionerElement: ScrollAreaViewport.createSelector(state => state.positionerElement),
|
|
269
|
-
listElement: ScrollAreaViewport.createSelector(state => state.listElement),
|
|
270
|
-
triggerElement: ScrollAreaViewport.createSelector(state => state.triggerElement),
|
|
271
|
-
inputElement: ScrollAreaViewport.createSelector(state => state.inputElement),
|
|
272
|
-
inputGroupElement: ScrollAreaViewport.createSelector(state => state.inputGroupElement),
|
|
273
|
-
popupSide: ScrollAreaViewport.createSelector(state => state.popupSide),
|
|
274
|
-
openMethod: ScrollAreaViewport.createSelector(state => state.openMethod),
|
|
275
|
-
inputInsidePopup: ScrollAreaViewport.createSelector(state => state.inputInsidePopup),
|
|
276
|
-
selectionMode: ScrollAreaViewport.createSelector(state => state.selectionMode),
|
|
277
|
-
listRef: ScrollAreaViewport.createSelector(state => state.listRef),
|
|
278
|
-
labelsRef: ScrollAreaViewport.createSelector(state => state.labelsRef),
|
|
279
|
-
popupRef: ScrollAreaViewport.createSelector(state => state.popupRef),
|
|
280
|
-
emptyRef: ScrollAreaViewport.createSelector(state => state.emptyRef),
|
|
281
|
-
inputRef: ScrollAreaViewport.createSelector(state => state.inputRef),
|
|
282
|
-
keyboardActiveRef: ScrollAreaViewport.createSelector(state => state.keyboardActiveRef),
|
|
283
|
-
chipsContainerRef: ScrollAreaViewport.createSelector(state => state.chipsContainerRef),
|
|
284
|
-
clearRef: ScrollAreaViewport.createSelector(state => state.clearRef),
|
|
285
|
-
valuesRef: ScrollAreaViewport.createSelector(state => state.valuesRef),
|
|
286
|
-
allValuesRef: ScrollAreaViewport.createSelector(state => state.allValuesRef),
|
|
287
|
-
name: ScrollAreaViewport.createSelector(state => state.name),
|
|
288
|
-
disabled: ScrollAreaViewport.createSelector(state => state.disabled),
|
|
289
|
-
readOnly: ScrollAreaViewport.createSelector(state => state.readOnly),
|
|
290
|
-
required: ScrollAreaViewport.createSelector(state => state.required),
|
|
291
|
-
grid: ScrollAreaViewport.createSelector(state => state.grid),
|
|
292
|
-
isGrouped: ScrollAreaViewport.createSelector(state => state.isGrouped),
|
|
293
|
-
virtualized: ScrollAreaViewport.createSelector(state => state.virtualized),
|
|
294
|
-
onOpenChangeComplete: ScrollAreaViewport.createSelector(state => state.onOpenChangeComplete),
|
|
295
|
-
openOnInputClick: ScrollAreaViewport.createSelector(state => state.openOnInputClick),
|
|
296
|
-
itemToStringLabel: ScrollAreaViewport.createSelector(state => state.itemToStringLabel),
|
|
297
|
-
isItemEqualToValue: ScrollAreaViewport.createSelector(state => state.isItemEqualToValue),
|
|
298
|
-
modal: ScrollAreaViewport.createSelector(state => state.modal),
|
|
299
|
-
autoHighlight: ScrollAreaViewport.createSelector(state => state.autoHighlight),
|
|
300
|
-
submitOnItemClick: ScrollAreaViewport.createSelector(state => state.submitOnItemClick)
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Enhanced filter using Intl.Collator for more robust string matching.
|
|
305
|
-
* Uses the provided `itemToStringLabel` function if available, otherwise falls back to:
|
|
306
|
-
* • When `item` is an object with a `value` property, that property is used.
|
|
307
|
-
* • When `item` is a primitive (e.g. `string`), it is used directly.
|
|
308
|
-
*/
|
|
309
|
-
function createCollatorItemFilter(collatorFilter, itemToStringLabel) {
|
|
310
|
-
return (item, query) => {
|
|
311
|
-
if (item == null) {
|
|
312
|
-
return false;
|
|
313
|
-
}
|
|
314
|
-
const itemString = stringifyAsLabel(item, itemToStringLabel);
|
|
315
|
-
return collatorFilter.contains(itemString, query);
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Enhanced filter for single selection mode using Intl.Collator that shows all items
|
|
321
|
-
* when query is empty or matches the current selection, making it easier to browse options.
|
|
322
|
-
*/
|
|
323
|
-
function createSingleSelectionCollatorFilter(collatorFilter, itemToStringLabel, selectedValue) {
|
|
324
|
-
return (item, query) => {
|
|
325
|
-
if (item == null) {
|
|
326
|
-
return false;
|
|
327
|
-
}
|
|
328
|
-
if (!query) {
|
|
329
|
-
return true;
|
|
330
|
-
}
|
|
331
|
-
const itemString = stringifyAsLabel(item, itemToStringLabel);
|
|
332
|
-
const selectedString = selectedValue != null ? stringifyAsLabel(selectedValue, itemToStringLabel) : '';
|
|
333
|
-
|
|
334
|
-
// Handle case-insensitive matching consistently
|
|
335
|
-
if (selectedString && collatorFilter.contains(selectedString, query) && selectedString.length === query.length) {
|
|
336
|
-
return true;
|
|
337
|
-
}
|
|
338
|
-
return collatorFilter.contains(itemString, query);
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const filterCache = new Map();
|
|
343
|
-
function stringifyLocale(locale) {
|
|
344
|
-
if (Array.isArray(locale)) {
|
|
345
|
-
return locale.map(value => stringifyLocale(value)).join(',');
|
|
346
|
-
}
|
|
347
|
-
if (locale == null) {
|
|
348
|
-
return '';
|
|
349
|
-
}
|
|
350
|
-
return String(locale);
|
|
351
|
-
}
|
|
352
|
-
function getFilter(options = {}) {
|
|
353
|
-
const mergedOptions = {
|
|
354
|
-
usage: 'search',
|
|
355
|
-
sensitivity: 'base',
|
|
356
|
-
ignorePunctuation: true,
|
|
357
|
-
...options
|
|
358
|
-
};
|
|
359
|
-
const cacheKey = `${stringifyLocale(options.locale)}|${JSON.stringify(mergedOptions)}`;
|
|
360
|
-
const cachedFilter = filterCache.get(cacheKey);
|
|
361
|
-
if (cachedFilter) {
|
|
362
|
-
return cachedFilter;
|
|
363
|
-
}
|
|
364
|
-
const collator = new Intl.Collator(options.locale, mergedOptions);
|
|
365
|
-
const filter = {
|
|
366
|
-
contains(item, query, itemToString) {
|
|
367
|
-
if (!query) {
|
|
368
|
-
return true;
|
|
369
|
-
}
|
|
370
|
-
const itemString = stringifyAsLabel(item, itemToString);
|
|
371
|
-
for (let i = 0; i <= itemString.length - query.length; i += 1) {
|
|
372
|
-
if (collator.compare(itemString.slice(i, i + query.length), query) === 0) {
|
|
373
|
-
return true;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
return false;
|
|
377
|
-
},
|
|
378
|
-
startsWith(item, query, itemToString) {
|
|
379
|
-
if (!query) {
|
|
380
|
-
return true;
|
|
381
|
-
}
|
|
382
|
-
const itemString = stringifyAsLabel(item, itemToString);
|
|
383
|
-
return collator.compare(itemString.slice(0, query.length), query) === 0;
|
|
384
|
-
},
|
|
385
|
-
endsWith(item, query, itemToString) {
|
|
386
|
-
if (!query) {
|
|
387
|
-
return true;
|
|
388
|
-
}
|
|
389
|
-
const itemString = stringifyAsLabel(item, itemToString);
|
|
390
|
-
const queryLength = query.length;
|
|
391
|
-
return itemString.length >= queryLength && collator.compare(itemString.slice(itemString.length - queryLength), query) === 0;
|
|
392
|
-
}
|
|
393
|
-
};
|
|
394
|
-
filterCache.set(cacheKey, filter);
|
|
395
|
-
return filter;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* Matches items against a query using `Intl.Collator` for robust string matching.
|
|
400
|
-
*/
|
|
401
|
-
const useCoreFilter = getFilter;
|
|
402
|
-
/**
|
|
403
|
-
* Matches items against a query using `Intl.Collator` for robust string matching.
|
|
404
|
-
*/
|
|
405
|
-
function useComboboxFilter(options = {}) {
|
|
41
|
+
function AutocompleteRoot(props) {
|
|
406
42
|
const {
|
|
407
|
-
|
|
43
|
+
openOnInputClick = false,
|
|
408
44
|
value,
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const contains = React__namespace.useCallback((item, query, itemToString) => {
|
|
413
|
-
if (multiple) {
|
|
414
|
-
return createCollatorItemFilter(coreFilter, itemToString)(item, query);
|
|
415
|
-
}
|
|
416
|
-
return createSingleSelectionCollatorFilter(coreFilter, itemToString, value)(item, query);
|
|
417
|
-
}, [coreFilter, value, multiple]);
|
|
418
|
-
return React__namespace.useMemo(() => ({
|
|
419
|
-
contains,
|
|
420
|
-
startsWith: coreFilter.startsWith,
|
|
421
|
-
endsWith: coreFilter.endsWith
|
|
422
|
-
}), [contains, coreFilter]);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const NO_ACTIVE_VALUE = Symbol('none');
|
|
426
|
-
const INITIAL_LAST_HIGHLIGHT = {
|
|
427
|
-
value: NO_ACTIVE_VALUE,
|
|
428
|
-
index: -1
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
function AriaCombobox(props) {
|
|
432
|
-
const {
|
|
433
|
-
id: idProp,
|
|
434
|
-
onOpenChangeComplete: onOpenChangeCompleteProp,
|
|
435
|
-
defaultSelectedValue = null,
|
|
436
|
-
selectedValue: selectedValueProp,
|
|
437
|
-
onSelectedValueChange,
|
|
438
|
-
defaultInputValue: defaultInputValueProp,
|
|
439
|
-
inputValue: inputValueProp,
|
|
440
|
-
selectionMode = 'none',
|
|
441
|
-
onItemHighlighted: onItemHighlightedProp,
|
|
442
|
-
name: nameProp,
|
|
443
|
-
disabled: disabledProp = false,
|
|
444
|
-
readOnly = false,
|
|
445
|
-
required = false,
|
|
446
|
-
inputRef: inputRefProp,
|
|
447
|
-
grid = false,
|
|
448
|
-
items,
|
|
449
|
-
filteredItems: filteredItemsProp,
|
|
450
|
-
filter: filterProp,
|
|
451
|
-
openOnInputClick = true,
|
|
452
|
-
autoHighlight = false,
|
|
453
|
-
keepHighlight = false,
|
|
454
|
-
highlightItemOnHover = true,
|
|
455
|
-
loopFocus = true,
|
|
456
|
-
itemToStringLabel,
|
|
45
|
+
defaultValue,
|
|
46
|
+
onValueChange,
|
|
47
|
+
mode = 'list',
|
|
457
48
|
itemToStringValue,
|
|
458
|
-
|
|
459
|
-
virtualized = false,
|
|
460
|
-
inline: inlineProp = false,
|
|
461
|
-
fillInputOnItemPress = true,
|
|
462
|
-
modal = false,
|
|
463
|
-
limit = -1,
|
|
464
|
-
autoComplete = 'list',
|
|
465
|
-
formAutoComplete,
|
|
466
|
-
locale,
|
|
467
|
-
submitOnItemClick = false
|
|
49
|
+
...other
|
|
468
50
|
} = props;
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
} = NumberFieldInput.useFormContext();
|
|
472
|
-
const {
|
|
473
|
-
setDirty,
|
|
474
|
-
validityData,
|
|
475
|
-
shouldValidateOnChange,
|
|
476
|
-
setFilled,
|
|
477
|
-
name: fieldName,
|
|
478
|
-
disabled: fieldDisabled,
|
|
479
|
-
setTouched,
|
|
480
|
-
setFocused,
|
|
481
|
-
validationMode,
|
|
482
|
-
validation
|
|
483
|
-
} = NumberFieldInput.useFieldRootContext();
|
|
484
|
-
const id = NumberFieldInput.useLabelableId({
|
|
485
|
-
id: idProp
|
|
486
|
-
});
|
|
487
|
-
const collatorFilter = useCoreFilter({
|
|
488
|
-
locale
|
|
489
|
-
});
|
|
490
|
-
const [queryChangedAfterOpen, setQueryChangedAfterOpen] = React__namespace.useState(false);
|
|
491
|
-
const [closeQuery, setCloseQuery] = React__namespace.useState(null);
|
|
492
|
-
const listRef = React__namespace.useRef([]);
|
|
493
|
-
const labelsRef = React__namespace.useRef([]);
|
|
494
|
-
const popupRef = React__namespace.useRef(null);
|
|
495
|
-
const inputRef = React__namespace.useRef(null);
|
|
496
|
-
const startDismissRef = React__namespace.useRef(null);
|
|
497
|
-
const endDismissRef = React__namespace.useRef(null);
|
|
498
|
-
const emptyRef = React__namespace.useRef(null);
|
|
499
|
-
const keyboardActiveRef = React__namespace.useRef(true);
|
|
500
|
-
const hadInputClearRef = React__namespace.useRef(false);
|
|
501
|
-
const chipsContainerRef = React__namespace.useRef(null);
|
|
502
|
-
const clearRef = React__namespace.useRef(null);
|
|
503
|
-
const selectionEventRef = React__namespace.useRef(null);
|
|
504
|
-
const lastHighlightRef = React__namespace.useRef(INITIAL_LAST_HIGHLIGHT);
|
|
505
|
-
const pendingQueryHighlightRef = React__namespace.useRef(null);
|
|
506
|
-
|
|
507
|
-
/**
|
|
508
|
-
* Contains the currently visible list of item values post-filtering.
|
|
509
|
-
*/
|
|
510
|
-
const valuesRef = React__namespace.useRef([]);
|
|
511
|
-
/**
|
|
512
|
-
* Contains all item values in a stable, unfiltered order.
|
|
513
|
-
* This is only used when `items` prop is not provided.
|
|
514
|
-
* It accumulates values on first mount and does not remove them on unmount due to
|
|
515
|
-
* filtering, providing a stable index for selected value tracking.
|
|
516
|
-
*/
|
|
517
|
-
const allValuesRef = React__namespace.useRef([]);
|
|
518
|
-
const disabled = fieldDisabled || disabledProp;
|
|
519
|
-
const name = fieldName ?? nameProp;
|
|
520
|
-
const multiple = selectionMode === 'multiple';
|
|
521
|
-
const single = selectionMode === 'single';
|
|
522
|
-
const hasInputValue = inputValueProp !== undefined || defaultInputValueProp !== undefined;
|
|
523
|
-
const hasItems = items !== undefined;
|
|
524
|
-
const hasFilteredItemsProp = filteredItemsProp !== undefined;
|
|
525
|
-
let autoHighlightMode;
|
|
526
|
-
if (autoHighlight === 'always') {
|
|
527
|
-
autoHighlightMode = 'always';
|
|
528
|
-
} else {
|
|
529
|
-
autoHighlightMode = autoHighlight ? 'input-change' : false;
|
|
530
|
-
}
|
|
531
|
-
const [selectedValue, setSelectedValueUnwrapped] = clamp.useControlled({
|
|
532
|
-
controlled: selectedValueProp,
|
|
533
|
-
default: multiple ? defaultSelectedValue ?? useRenderElement.EMPTY_ARRAY : defaultSelectedValue,
|
|
534
|
-
name: 'Combobox',
|
|
535
|
-
state: 'selectedValue'
|
|
536
|
-
});
|
|
537
|
-
const filter = React__namespace.useMemo(() => {
|
|
538
|
-
if (filterProp === null) {
|
|
539
|
-
return () => true;
|
|
540
|
-
}
|
|
541
|
-
if (filterProp !== undefined) {
|
|
542
|
-
return filterProp;
|
|
543
|
-
}
|
|
544
|
-
if (single && !queryChangedAfterOpen) {
|
|
545
|
-
return createSingleSelectionCollatorFilter(collatorFilter, itemToStringLabel, selectedValue);
|
|
546
|
-
}
|
|
547
|
-
return createCollatorItemFilter(collatorFilter, itemToStringLabel);
|
|
548
|
-
}, [filterProp, single, selectedValue, queryChangedAfterOpen, collatorFilter, itemToStringLabel]);
|
|
549
|
-
|
|
550
|
-
// If neither inputValue nor defaultInputValue are provided, derive it from the
|
|
551
|
-
// selected value for single mode so the input reflects the selection on mount.
|
|
552
|
-
const initialDefaultInputValue = useRenderElement.useRefWithInit(() => {
|
|
553
|
-
if (hasInputValue) {
|
|
554
|
-
return defaultInputValueProp ?? '';
|
|
555
|
-
}
|
|
556
|
-
if (single) {
|
|
557
|
-
return stringifyAsLabel(selectedValue, itemToStringLabel);
|
|
558
|
-
}
|
|
559
|
-
return '';
|
|
560
|
-
}).current;
|
|
561
|
-
const [inputValue, setInputValueUnwrapped] = clamp.useControlled({
|
|
562
|
-
controlled: inputValueProp,
|
|
563
|
-
default: initialDefaultInputValue,
|
|
564
|
-
name: 'Combobox',
|
|
565
|
-
state: 'inputValue'
|
|
566
|
-
});
|
|
567
|
-
const [open, setOpenUnwrapped] = clamp.useControlled({
|
|
568
|
-
controlled: props.open,
|
|
569
|
-
default: props.defaultOpen,
|
|
570
|
-
name: 'Combobox',
|
|
571
|
-
state: 'open'
|
|
572
|
-
});
|
|
573
|
-
const isGrouped = isGroupedItems(items);
|
|
574
|
-
const query = closeQuery ?? (inputValue === '' ? '' : String(inputValue).trim());
|
|
575
|
-
const selectedLabelString = single ? stringifyAsLabel(selectedValue, itemToStringLabel) : '';
|
|
576
|
-
const shouldBypassFiltering = single && !queryChangedAfterOpen && query !== '' && selectedLabelString !== '' && selectedLabelString.length === query.length && collatorFilter.contains(selectedLabelString, query);
|
|
577
|
-
const filterQuery = shouldBypassFiltering ? '' : query;
|
|
578
|
-
const shouldIgnoreExternalFiltering = hasItems && hasFilteredItemsProp && shouldBypassFiltering;
|
|
579
|
-
const flatItems = React__namespace.useMemo(() => {
|
|
580
|
-
if (!items) {
|
|
581
|
-
return useRenderElement.EMPTY_ARRAY;
|
|
582
|
-
}
|
|
583
|
-
if (isGrouped) {
|
|
584
|
-
return items.flatMap(group => group.items);
|
|
585
|
-
}
|
|
586
|
-
return items;
|
|
587
|
-
}, [items, isGrouped]);
|
|
588
|
-
const filteredItems = React__namespace.useMemo(() => {
|
|
589
|
-
if (filteredItemsProp && !shouldIgnoreExternalFiltering) {
|
|
590
|
-
return filteredItemsProp;
|
|
591
|
-
}
|
|
592
|
-
if (!items) {
|
|
593
|
-
return useRenderElement.EMPTY_ARRAY;
|
|
594
|
-
}
|
|
595
|
-
if (isGrouped) {
|
|
596
|
-
const groupedItems = items;
|
|
597
|
-
const resultingGroups = [];
|
|
598
|
-
let currentCount = 0;
|
|
599
|
-
for (const group of groupedItems) {
|
|
600
|
-
if (limit > -1 && currentCount >= limit) {
|
|
601
|
-
break;
|
|
602
|
-
}
|
|
603
|
-
const candidateItems = filterQuery === '' ? group.items : group.items.filter(item => filter(item, filterQuery, itemToStringLabel));
|
|
604
|
-
if (candidateItems.length === 0) {
|
|
605
|
-
continue;
|
|
606
|
-
}
|
|
607
|
-
const remainingLimit = limit > -1 ? limit - currentCount : Infinity;
|
|
608
|
-
const itemsToTake = candidateItems.slice(0, remainingLimit);
|
|
609
|
-
if (itemsToTake.length > 0) {
|
|
610
|
-
const newGroup = {
|
|
611
|
-
...group,
|
|
612
|
-
items: itemsToTake
|
|
613
|
-
};
|
|
614
|
-
resultingGroups.push(newGroup);
|
|
615
|
-
currentCount += itemsToTake.length;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
return resultingGroups;
|
|
619
|
-
}
|
|
620
|
-
if (filterQuery === '') {
|
|
621
|
-
return limit > -1 ? flatItems.slice(0, limit) :
|
|
622
|
-
// The cast here is done as `flatItems` is readonly.
|
|
623
|
-
// valuesRef.current, a mutable ref, can be set to `flatFilteredItems`, which may
|
|
624
|
-
// reference this exact readonly value, creating a mutation risk.
|
|
625
|
-
// However, <Combobox.Item> can never mutate this value as the mutating effect
|
|
626
|
-
// bails early when `items` is provided, and this is only ever returned
|
|
627
|
-
// when `items` is provided due to the early return at the top of this hook.
|
|
628
|
-
flatItems;
|
|
629
|
-
}
|
|
630
|
-
const limitedItems = [];
|
|
631
|
-
for (const item of flatItems) {
|
|
632
|
-
if (limit > -1 && limitedItems.length >= limit) {
|
|
633
|
-
break;
|
|
634
|
-
}
|
|
635
|
-
if (filter(item, filterQuery, itemToStringLabel)) {
|
|
636
|
-
limitedItems.push(item);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
return limitedItems;
|
|
640
|
-
}, [filteredItemsProp, shouldIgnoreExternalFiltering, items, isGrouped, filterQuery, limit, filter, itemToStringLabel, flatItems]);
|
|
641
|
-
const flatFilteredItems = React__namespace.useMemo(() => {
|
|
642
|
-
if (isGrouped) {
|
|
643
|
-
const groups = filteredItems;
|
|
644
|
-
return groups.flatMap(g => g.items);
|
|
645
|
-
}
|
|
646
|
-
return filteredItems;
|
|
647
|
-
}, [filteredItems, isGrouped]);
|
|
648
|
-
const store = useRenderElement.useRefWithInit(() => new ScrollAreaViewport.Store({
|
|
649
|
-
id,
|
|
650
|
-
labelId: undefined,
|
|
651
|
-
selectedValue,
|
|
652
|
-
open,
|
|
653
|
-
filter,
|
|
654
|
-
query,
|
|
655
|
-
items,
|
|
656
|
-
selectionMode,
|
|
657
|
-
listRef,
|
|
658
|
-
labelsRef,
|
|
659
|
-
popupRef,
|
|
660
|
-
emptyRef,
|
|
661
|
-
inputRef,
|
|
662
|
-
startDismissRef,
|
|
663
|
-
endDismissRef,
|
|
664
|
-
keyboardActiveRef,
|
|
665
|
-
chipsContainerRef,
|
|
666
|
-
clearRef,
|
|
667
|
-
valuesRef,
|
|
668
|
-
allValuesRef,
|
|
669
|
-
selectionEventRef,
|
|
670
|
-
name,
|
|
671
|
-
disabled,
|
|
672
|
-
readOnly,
|
|
673
|
-
required,
|
|
674
|
-
grid,
|
|
675
|
-
isGrouped,
|
|
676
|
-
virtualized,
|
|
677
|
-
openOnInputClick,
|
|
678
|
-
itemToStringLabel,
|
|
679
|
-
isItemEqualToValue,
|
|
680
|
-
modal,
|
|
681
|
-
autoHighlight: autoHighlightMode,
|
|
682
|
-
submitOnItemClick,
|
|
683
|
-
hasInputValue,
|
|
684
|
-
mounted: false,
|
|
685
|
-
forceMounted: false,
|
|
686
|
-
transitionStatus: 'idle',
|
|
687
|
-
inline: inlineProp,
|
|
688
|
-
activeIndex: null,
|
|
689
|
-
selectedIndex: null,
|
|
690
|
-
popupProps: {},
|
|
691
|
-
inputProps: {},
|
|
692
|
-
triggerProps: {},
|
|
693
|
-
positionerElement: null,
|
|
694
|
-
listElement: null,
|
|
695
|
-
triggerElement: null,
|
|
696
|
-
inputElement: null,
|
|
697
|
-
inputGroupElement: null,
|
|
698
|
-
popupSide: null,
|
|
699
|
-
openMethod: null,
|
|
700
|
-
inputInsidePopup: true,
|
|
701
|
-
onOpenChangeComplete: onOpenChangeCompleteProp || useRenderElement.NOOP,
|
|
702
|
-
// Placeholder callbacks replaced on first render
|
|
703
|
-
setOpen: useRenderElement.NOOP,
|
|
704
|
-
setInputValue: useRenderElement.NOOP,
|
|
705
|
-
setSelectedValue: useRenderElement.NOOP,
|
|
706
|
-
setIndices: useRenderElement.NOOP,
|
|
707
|
-
onItemHighlighted: useRenderElement.NOOP,
|
|
708
|
-
handleSelection: useRenderElement.NOOP,
|
|
709
|
-
getItemProps: () => useRenderElement.EMPTY_OBJECT,
|
|
710
|
-
forceMount: useRenderElement.NOOP,
|
|
711
|
-
requestSubmit: useRenderElement.NOOP
|
|
712
|
-
})).current;
|
|
713
|
-
const fieldRawValue = selectionMode === 'none' ? inputValue : selectedValue;
|
|
714
|
-
const fieldStringValue = React__namespace.useMemo(() => {
|
|
715
|
-
if (selectionMode === 'none') {
|
|
716
|
-
return fieldRawValue;
|
|
717
|
-
}
|
|
718
|
-
if (Array.isArray(selectedValue)) {
|
|
719
|
-
return selectedValue.map(value => stringifyAsValue(value, itemToStringValue));
|
|
720
|
-
}
|
|
721
|
-
return stringifyAsValue(selectedValue, itemToStringValue);
|
|
722
|
-
}, [fieldRawValue, itemToStringValue, selectionMode, selectedValue]);
|
|
723
|
-
const onItemHighlighted = clamp.useStableCallback(onItemHighlightedProp);
|
|
724
|
-
const onOpenChangeComplete = clamp.useStableCallback(onOpenChangeCompleteProp);
|
|
725
|
-
const activeIndex = ScrollAreaViewport.useStore(store, selectors.activeIndex);
|
|
726
|
-
const selectedIndex = ScrollAreaViewport.useStore(store, selectors.selectedIndex);
|
|
727
|
-
const positionerElement = ScrollAreaViewport.useStore(store, selectors.positionerElement);
|
|
728
|
-
const listElement = ScrollAreaViewport.useStore(store, selectors.listElement);
|
|
729
|
-
const triggerElement = ScrollAreaViewport.useStore(store, selectors.triggerElement);
|
|
730
|
-
const inputElement = ScrollAreaViewport.useStore(store, selectors.inputElement);
|
|
731
|
-
const inputGroupElement = ScrollAreaViewport.useStore(store, selectors.inputGroupElement);
|
|
732
|
-
const inline = ScrollAreaViewport.useStore(store, selectors.inline);
|
|
733
|
-
const inputInsidePopup = ScrollAreaViewport.useStore(store, selectors.inputInsidePopup);
|
|
734
|
-
const triggerRef = clamp.useValueAsRef(triggerElement);
|
|
735
|
-
const {
|
|
736
|
-
mounted,
|
|
737
|
-
setMounted,
|
|
738
|
-
transitionStatus
|
|
739
|
-
} = clamp.useTransitionStatus(open);
|
|
740
|
-
const {
|
|
741
|
-
openMethod,
|
|
742
|
-
triggerProps
|
|
743
|
-
} = ScrollAreaViewport.useOpenInteractionType(open);
|
|
744
|
-
NumberFieldInput.useField({
|
|
745
|
-
id,
|
|
746
|
-
name,
|
|
747
|
-
commit: validation.commit,
|
|
748
|
-
value: fieldRawValue,
|
|
749
|
-
controlRef: inputInsidePopup ? triggerRef : inputRef,
|
|
750
|
-
getValue: () => fieldStringValue
|
|
751
|
-
});
|
|
752
|
-
const forceMount = clamp.useStableCallback(() => {
|
|
753
|
-
if (items) {
|
|
754
|
-
// Ensure typeahead works on a closed list.
|
|
755
|
-
labelsRef.current = flatFilteredItems.map(item => stringifyAsLabel(item, itemToStringLabel));
|
|
756
|
-
} else {
|
|
757
|
-
store.set('forceMounted', true);
|
|
758
|
-
}
|
|
759
|
-
});
|
|
760
|
-
const initialSelectedValueRef = React__namespace.useRef(selectedValue);
|
|
761
|
-
clamp.useIsoLayoutEffect(() => {
|
|
762
|
-
// Ensure the values and labels are registered for programmatic value changes.
|
|
763
|
-
if (selectedValue !== initialSelectedValueRef.current) {
|
|
764
|
-
forceMount();
|
|
765
|
-
}
|
|
766
|
-
}, [forceMount, selectedValue]);
|
|
767
|
-
const setIndices = clamp.useStableCallback(options => {
|
|
768
|
-
store.update(options);
|
|
769
|
-
const type = options.type || 'none';
|
|
770
|
-
if (options.activeIndex === undefined) {
|
|
771
|
-
return;
|
|
772
|
-
}
|
|
773
|
-
if (options.activeIndex === null) {
|
|
774
|
-
if (lastHighlightRef.current !== INITIAL_LAST_HIGHLIGHT) {
|
|
775
|
-
lastHighlightRef.current = INITIAL_LAST_HIGHLIGHT;
|
|
776
|
-
onItemHighlighted(undefined, clamp.createGenericEventDetails(type, undefined, {
|
|
777
|
-
index: -1
|
|
778
|
-
}));
|
|
779
|
-
}
|
|
780
|
-
} else {
|
|
781
|
-
const activeValue = valuesRef.current[options.activeIndex];
|
|
782
|
-
lastHighlightRef.current = {
|
|
783
|
-
value: activeValue,
|
|
784
|
-
index: options.activeIndex
|
|
785
|
-
};
|
|
786
|
-
onItemHighlighted(activeValue, clamp.createGenericEventDetails(type, undefined, {
|
|
787
|
-
index: options.activeIndex
|
|
788
|
-
}));
|
|
789
|
-
}
|
|
790
|
-
});
|
|
791
|
-
const setInputValue = clamp.useStableCallback((next, eventDetails) => {
|
|
792
|
-
hadInputClearRef.current = eventDetails.reason === clamp.inputClear;
|
|
793
|
-
props.onInputValueChange?.(next, eventDetails);
|
|
794
|
-
if (eventDetails.isCanceled) {
|
|
795
|
-
return;
|
|
796
|
-
}
|
|
51
|
+
const enableInline = mode === 'inline' || mode === 'both';
|
|
52
|
+
const staticItems = mode === 'inline' || mode === 'none';
|
|
797
53
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
if (isTypedInput) {
|
|
807
|
-
const hasQuery = next.trim() !== '';
|
|
808
|
-
if (hasQuery) {
|
|
809
|
-
setQueryChangedAfterOpen(true);
|
|
810
|
-
}
|
|
811
|
-
// Defer index updates until after the filtered items have been derived to ensure
|
|
812
|
-
// `onItemHighlighted` receives the latest item.
|
|
813
|
-
pendingQueryHighlightRef.current = {
|
|
814
|
-
hasQuery
|
|
815
|
-
};
|
|
816
|
-
if (hasQuery && autoHighlightMode && store.state.activeIndex == null) {
|
|
817
|
-
store.set('activeIndex', 0);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
setInputValueUnwrapped(next);
|
|
822
|
-
});
|
|
823
|
-
const setOpen = clamp.useStableCallback((nextOpen, eventDetails) => {
|
|
824
|
-
if (open === nextOpen) {
|
|
825
|
-
return;
|
|
54
|
+
// Mirror the typed value for uncontrolled usage so we can compose the temporary
|
|
55
|
+
// inline input value.
|
|
56
|
+
const isControlled = value !== undefined;
|
|
57
|
+
const [internalValue, setInternalValue] = React__namespace.useState(defaultValue ?? '');
|
|
58
|
+
const [inlineInputValue, setInlineInputValue] = React__namespace.useState('');
|
|
59
|
+
React__namespace.useEffect(() => {
|
|
60
|
+
if (isControlled) {
|
|
61
|
+
setInlineInputValue('');
|
|
826
62
|
}
|
|
63
|
+
}, [value, isControlled]);
|
|
827
64
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
setCloseQuery(query);
|
|
842
|
-
}
|
|
843
|
-
// Avoid a flicker when closing the popup with an empty query.
|
|
844
|
-
if (query === '') {
|
|
845
|
-
setQueryChangedAfterOpen(false);
|
|
846
|
-
}
|
|
847
|
-
} else if (multiple) {
|
|
848
|
-
if (inline || inputInsidePopup) {
|
|
849
|
-
setIndices({
|
|
850
|
-
activeIndex: null
|
|
851
|
-
});
|
|
852
|
-
} else {
|
|
853
|
-
// Freeze the current query so filtering remains stable while exiting.
|
|
854
|
-
setCloseQuery(query);
|
|
855
|
-
}
|
|
856
|
-
// Clear the input immediately on close while retaining filtering via closeQuery for exit animations
|
|
857
|
-
// if the input is outside the popup.
|
|
858
|
-
setInputValue('', clamp.createChangeEventDetails(clamp.inputClear, eventDetails.event));
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
setOpenUnwrapped(nextOpen);
|
|
862
|
-
if (!nextOpen && inputInsidePopup && (eventDetails.reason === clamp.focusOut || eventDetails.reason === clamp.outsidePress)) {
|
|
863
|
-
setTouched(true);
|
|
864
|
-
setFocused(false);
|
|
865
|
-
if (validationMode === 'onBlur') {
|
|
866
|
-
const valueToValidate = selectionMode === 'none' ? inputValue : selectedValue;
|
|
867
|
-
validation.commit(valueToValidate);
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
});
|
|
871
|
-
const setSelectedValue = clamp.useStableCallback((nextValue, eventDetails) => {
|
|
872
|
-
// Cast to `any` due to conditional value type (single vs. multiple).
|
|
873
|
-
// The runtime implementation already ensures the correct value shape.
|
|
874
|
-
onSelectedValueChange?.(nextValue, eventDetails);
|
|
875
|
-
if (eventDetails.isCanceled) {
|
|
876
|
-
return;
|
|
877
|
-
}
|
|
878
|
-
setSelectedValueUnwrapped(nextValue);
|
|
879
|
-
const shouldFillInput = selectionMode === 'none' && popupRef.current && fillInputOnItemPress || single && !store.state.inputInsidePopup;
|
|
880
|
-
if (shouldFillInput) {
|
|
881
|
-
setInputValue(stringifyAsLabel(nextValue, itemToStringLabel), clamp.createChangeEventDetails(eventDetails.reason, eventDetails.event));
|
|
882
|
-
}
|
|
883
|
-
if (single && nextValue != null && eventDetails.reason !== clamp.inputChange && queryChangedAfterOpen && !inline) {
|
|
884
|
-
setCloseQuery(query);
|
|
65
|
+
// Compose the input value shown to the user: inline value takes precedence when present.
|
|
66
|
+
let resolvedInputValue;
|
|
67
|
+
if (enableInline && inlineInputValue !== '') {
|
|
68
|
+
resolvedInputValue = inlineInputValue;
|
|
69
|
+
} else if (isControlled) {
|
|
70
|
+
resolvedInputValue = value ?? '';
|
|
71
|
+
} else {
|
|
72
|
+
resolvedInputValue = internalValue;
|
|
73
|
+
}
|
|
74
|
+
const handleValueChange = useButton.useStableCallback((nextValue, eventDetails) => {
|
|
75
|
+
setInlineInputValue('');
|
|
76
|
+
if (!isControlled) {
|
|
77
|
+
setInternalValue(nextValue);
|
|
885
78
|
}
|
|
79
|
+
onValueChange?.(nextValue, eventDetails);
|
|
886
80
|
});
|
|
887
|
-
const
|
|
888
|
-
|
|
889
|
-
if (
|
|
890
|
-
|
|
891
|
-
return;
|
|
892
|
-
}
|
|
893
|
-
itemValue = valuesRef.current[activeIndex];
|
|
81
|
+
const collator = ComboboxChipRemove.useCoreFilter();
|
|
82
|
+
const baseFilter = React__namespace.useMemo(() => {
|
|
83
|
+
if (other.filter !== undefined) {
|
|
84
|
+
return other.filter;
|
|
894
85
|
}
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
const eventDetails = clamp.createChangeEventDetails(clamp.itemPress, overrideEvent);
|
|
899
|
-
|
|
900
|
-
// Let the link handle the click.
|
|
901
|
-
const href = targetEl?.closest('a')?.getAttribute('href');
|
|
902
|
-
if (href) {
|
|
903
|
-
if (href.startsWith('#')) {
|
|
904
|
-
setOpen(false, eventDetails);
|
|
905
|
-
}
|
|
906
|
-
return;
|
|
907
|
-
}
|
|
908
|
-
if (multiple) {
|
|
909
|
-
const currentSelectedValue = Array.isArray(selectedValue) ? selectedValue : [];
|
|
910
|
-
const isCurrentlySelected = selectedValueIncludes(currentSelectedValue, itemValue, store.state.isItemEqualToValue);
|
|
911
|
-
const nextValue = isCurrentlySelected ? removeItem(currentSelectedValue, itemValue, store.state.isItemEqualToValue) : [...currentSelectedValue, itemValue];
|
|
912
|
-
setSelectedValue(nextValue, eventDetails);
|
|
913
|
-
const wasFiltering = inputRef.current ? inputRef.current.value.trim() !== '' : false;
|
|
914
|
-
if (!wasFiltering) {
|
|
915
|
-
return;
|
|
916
|
-
}
|
|
917
|
-
if (store.state.inputInsidePopup) {
|
|
918
|
-
setInputValue('', clamp.createChangeEventDetails(clamp.inputClear, eventDetails.event));
|
|
919
|
-
} else {
|
|
920
|
-
setOpen(false, eventDetails);
|
|
921
|
-
}
|
|
922
|
-
} else {
|
|
923
|
-
setSelectedValue(itemValue, eventDetails);
|
|
924
|
-
setOpen(false, eventDetails);
|
|
925
|
-
}
|
|
926
|
-
});
|
|
927
|
-
const requestSubmit = clamp.useStableCallback(() => {
|
|
928
|
-
if (!store.state.submitOnItemClick) {
|
|
929
|
-
return;
|
|
930
|
-
}
|
|
931
|
-
const form = store.state.inputElement?.form;
|
|
932
|
-
if (form && typeof form.requestSubmit === 'function') {
|
|
933
|
-
form.requestSubmit();
|
|
934
|
-
}
|
|
935
|
-
});
|
|
936
|
-
const handleUnmount = clamp.useStableCallback(() => {
|
|
937
|
-
setMounted(false);
|
|
938
|
-
onOpenChangeComplete?.(false);
|
|
939
|
-
setQueryChangedAfterOpen(false);
|
|
940
|
-
setCloseQuery(null);
|
|
941
|
-
if (selectionMode === 'none') {
|
|
942
|
-
setIndices({
|
|
943
|
-
activeIndex: null,
|
|
944
|
-
selectedIndex: null
|
|
945
|
-
});
|
|
946
|
-
} else {
|
|
947
|
-
setIndices({
|
|
948
|
-
activeIndex: null
|
|
949
|
-
});
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
// Multiple selection mode:
|
|
953
|
-
// If the user typed a filter and didn't select in multiple mode, clear the input
|
|
954
|
-
// after close completes to avoid mid-exit flicker and start fresh on next open.
|
|
955
|
-
if (multiple && inputRef.current && inputRef.current.value !== '' && !hadInputClearRef.current) {
|
|
956
|
-
setInputValue('', clamp.createChangeEventDetails(clamp.inputClear));
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
// Single selection mode:
|
|
960
|
-
// - If input is rendered inside the popup, clear it so the next open is blank
|
|
961
|
-
// - If input is outside the popup, sync it to the selected value
|
|
962
|
-
if (single) {
|
|
963
|
-
if (store.state.inputInsidePopup) {
|
|
964
|
-
if (inputRef.current && inputRef.current.value !== '') {
|
|
965
|
-
setInputValue('', clamp.createChangeEventDetails(clamp.inputClear));
|
|
966
|
-
}
|
|
967
|
-
} else {
|
|
968
|
-
const stringVal = stringifyAsLabel(selectedValue, itemToStringLabel);
|
|
969
|
-
if (inputRef.current && inputRef.current.value !== stringVal) {
|
|
970
|
-
// If no selection was made, treat this as clearing the typed filter.
|
|
971
|
-
const reason = stringVal === '' ? clamp.inputClear : clamp.none;
|
|
972
|
-
setInputValue(stringVal, clamp.createChangeEventDetails(reason));
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
});
|
|
977
|
-
|
|
978
|
-
// Support composing the Dialog component around an inline combobox.
|
|
979
|
-
// `[role="dialog"]` is more interoperable than using a context, e.g. it can work
|
|
980
|
-
// with third-party modal libraries, though the limitation is that the closest
|
|
981
|
-
// `role=dialog` part must be the animated element.
|
|
982
|
-
const resolvedPopupRef = React__namespace.useMemo(() => {
|
|
983
|
-
if (inline && positionerElement) {
|
|
984
|
-
return {
|
|
985
|
-
current: positionerElement.closest('[role="dialog"]')
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
return popupRef;
|
|
989
|
-
}, [inline, positionerElement]);
|
|
990
|
-
clamp.useOpenChangeComplete({
|
|
991
|
-
enabled: !props.actionsRef,
|
|
992
|
-
open,
|
|
993
|
-
ref: resolvedPopupRef,
|
|
994
|
-
onComplete() {
|
|
995
|
-
if (!open) {
|
|
996
|
-
handleUnmount();
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
});
|
|
1000
|
-
React__namespace.useImperativeHandle(props.actionsRef, () => ({
|
|
1001
|
-
unmount: handleUnmount
|
|
1002
|
-
}), [handleUnmount]);
|
|
1003
|
-
clamp.useIsoLayoutEffect(function syncSelectedIndex() {
|
|
1004
|
-
if (open || selectionMode === 'none') {
|
|
1005
|
-
return;
|
|
1006
|
-
}
|
|
1007
|
-
const registry = items ? flatItems : allValuesRef.current;
|
|
1008
|
-
if (multiple) {
|
|
1009
|
-
const currentValue = Array.isArray(selectedValue) ? selectedValue : [];
|
|
1010
|
-
const lastValue = currentValue[currentValue.length - 1];
|
|
1011
|
-
const lastIndex = findItemIndex(registry, lastValue, isItemEqualToValue);
|
|
1012
|
-
setIndices({
|
|
1013
|
-
selectedIndex: lastIndex === -1 ? null : lastIndex
|
|
1014
|
-
});
|
|
1015
|
-
} else {
|
|
1016
|
-
const index = findItemIndex(registry, selectedValue, isItemEqualToValue);
|
|
1017
|
-
setIndices({
|
|
1018
|
-
selectedIndex: index === -1 ? null : index
|
|
1019
|
-
});
|
|
1020
|
-
}
|
|
1021
|
-
}, [open, selectedValue, items, selectionMode, flatItems, multiple, isItemEqualToValue, setIndices]);
|
|
1022
|
-
clamp.useIsoLayoutEffect(() => {
|
|
1023
|
-
if (items) {
|
|
1024
|
-
valuesRef.current = flatFilteredItems;
|
|
1025
|
-
listRef.current.length = flatFilteredItems.length;
|
|
1026
|
-
}
|
|
1027
|
-
}, [items, flatFilteredItems]);
|
|
1028
|
-
clamp.useIsoLayoutEffect(() => {
|
|
1029
|
-
const pendingHighlight = pendingQueryHighlightRef.current;
|
|
1030
|
-
if (pendingHighlight) {
|
|
1031
|
-
if (pendingHighlight.hasQuery) {
|
|
1032
|
-
if (autoHighlightMode) {
|
|
1033
|
-
store.set('activeIndex', 0);
|
|
1034
|
-
}
|
|
1035
|
-
} else if (autoHighlightMode === 'always') {
|
|
1036
|
-
store.set('activeIndex', 0);
|
|
1037
|
-
}
|
|
1038
|
-
pendingQueryHighlightRef.current = null;
|
|
1039
|
-
}
|
|
1040
|
-
if (!open && !inline) {
|
|
1041
|
-
return;
|
|
1042
|
-
}
|
|
1043
|
-
const shouldUseFlatFilteredItems = hasItems || hasFilteredItemsProp;
|
|
1044
|
-
const candidateItems = shouldUseFlatFilteredItems ? flatFilteredItems : valuesRef.current;
|
|
1045
|
-
const storeActiveIndex = store.state.activeIndex;
|
|
1046
|
-
if (storeActiveIndex == null) {
|
|
1047
|
-
if (autoHighlightMode === 'always' && candidateItems.length > 0) {
|
|
1048
|
-
store.set('activeIndex', 0);
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
if (lastHighlightRef.current !== INITIAL_LAST_HIGHLIGHT) {
|
|
1052
|
-
lastHighlightRef.current = INITIAL_LAST_HIGHLIGHT;
|
|
1053
|
-
store.state.onItemHighlighted(undefined, clamp.createGenericEventDetails(clamp.none, undefined, {
|
|
1054
|
-
index: -1
|
|
1055
|
-
}));
|
|
1056
|
-
}
|
|
1057
|
-
return;
|
|
1058
|
-
}
|
|
1059
|
-
if (storeActiveIndex >= candidateItems.length) {
|
|
1060
|
-
if (lastHighlightRef.current !== INITIAL_LAST_HIGHLIGHT) {
|
|
1061
|
-
lastHighlightRef.current = INITIAL_LAST_HIGHLIGHT;
|
|
1062
|
-
store.state.onItemHighlighted(undefined, clamp.createGenericEventDetails(clamp.none, undefined, {
|
|
1063
|
-
index: -1
|
|
1064
|
-
}));
|
|
1065
|
-
}
|
|
1066
|
-
store.set('activeIndex', null);
|
|
1067
|
-
return;
|
|
1068
|
-
}
|
|
1069
|
-
const itemValue = candidateItems[storeActiveIndex];
|
|
1070
|
-
const previouslyHighlightedItemValue = lastHighlightRef.current.value;
|
|
1071
|
-
const isSameItem = previouslyHighlightedItemValue !== NO_ACTIVE_VALUE && compareItemEquality(itemValue, previouslyHighlightedItemValue, store.state.isItemEqualToValue);
|
|
1072
|
-
if (lastHighlightRef.current.index !== storeActiveIndex || !isSameItem) {
|
|
1073
|
-
lastHighlightRef.current = {
|
|
1074
|
-
value: itemValue,
|
|
1075
|
-
index: storeActiveIndex
|
|
1076
|
-
};
|
|
1077
|
-
store.state.onItemHighlighted(itemValue, clamp.createGenericEventDetails(clamp.none, undefined, {
|
|
1078
|
-
index: storeActiveIndex
|
|
1079
|
-
}));
|
|
1080
|
-
}
|
|
1081
|
-
}, [activeIndex, autoHighlightMode, hasFilteredItemsProp, hasItems, flatFilteredItems, inline, open, store]);
|
|
1082
|
-
clamp.useIsoLayoutEffect(() => {
|
|
1083
|
-
if (selectionMode === 'none') {
|
|
1084
|
-
setFilled(String(inputValue) !== '');
|
|
1085
|
-
return;
|
|
1086
|
-
}
|
|
1087
|
-
setFilled(multiple ? Array.isArray(selectedValue) && selectedValue.length > 0 : selectedValue != null);
|
|
1088
|
-
}, [setFilled, selectionMode, inputValue, selectedValue, multiple]);
|
|
1089
|
-
|
|
1090
|
-
// Ensures that the active index is not set to 0 when the list is empty.
|
|
1091
|
-
// This avoids needing to press ArrowDown twice under certain conditions.
|
|
1092
|
-
React__namespace.useEffect(() => {
|
|
1093
|
-
if (hasItems && autoHighlightMode && flatFilteredItems.length === 0) {
|
|
1094
|
-
setIndices({
|
|
1095
|
-
activeIndex: null
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1098
|
-
}, [hasItems, autoHighlightMode, flatFilteredItems.length, setIndices]);
|
|
1099
|
-
clamp.useValueChanged(query, () => {
|
|
1100
|
-
if (!open || query === '' || query === String(initialDefaultInputValue)) {
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
|
-
setQueryChangedAfterOpen(true);
|
|
1104
|
-
});
|
|
1105
|
-
clamp.useValueChanged(selectedValue, () => {
|
|
1106
|
-
if (selectionMode === 'none') {
|
|
1107
|
-
return;
|
|
1108
|
-
}
|
|
1109
|
-
clearErrors(name);
|
|
1110
|
-
setDirty(selectedValue !== validityData.initialValue);
|
|
1111
|
-
if (shouldValidateOnChange()) {
|
|
1112
|
-
validation.commit(selectedValue);
|
|
1113
|
-
} else {
|
|
1114
|
-
validation.commit(selectedValue, true);
|
|
1115
|
-
}
|
|
1116
|
-
if (single && !hasInputValue && !inputInsidePopup) {
|
|
1117
|
-
const nextInputValue = stringifyAsLabel(selectedValue, itemToStringLabel);
|
|
1118
|
-
if (inputValue !== nextInputValue) {
|
|
1119
|
-
setInputValue(nextInputValue, clamp.createChangeEventDetails(clamp.none));
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
});
|
|
1123
|
-
clamp.useValueChanged(inputValue, () => {
|
|
1124
|
-
if (selectionMode !== 'none') {
|
|
1125
|
-
return;
|
|
1126
|
-
}
|
|
1127
|
-
clearErrors(name);
|
|
1128
|
-
setDirty(inputValue !== validityData.initialValue);
|
|
1129
|
-
if (shouldValidateOnChange()) {
|
|
1130
|
-
validation.commit(inputValue);
|
|
1131
|
-
} else {
|
|
1132
|
-
validation.commit(inputValue, true);
|
|
1133
|
-
}
|
|
1134
|
-
});
|
|
1135
|
-
clamp.useValueChanged(items, () => {
|
|
1136
|
-
if (!single || hasInputValue || inputInsidePopup || queryChangedAfterOpen) {
|
|
1137
|
-
return;
|
|
1138
|
-
}
|
|
1139
|
-
const nextInputValue = stringifyAsLabel(selectedValue, itemToStringLabel);
|
|
1140
|
-
if (inputValue !== nextInputValue) {
|
|
1141
|
-
setInputValue(nextInputValue, clamp.createChangeEventDetails(clamp.none));
|
|
1142
|
-
}
|
|
1143
|
-
});
|
|
1144
|
-
const floatingRootContext = MenuSubmenuTrigger.useFloatingRootContext({
|
|
1145
|
-
open: inline ? true : open,
|
|
1146
|
-
onOpenChange: setOpen,
|
|
1147
|
-
elements: {
|
|
1148
|
-
reference: inputInsidePopup ? triggerElement : inputElement,
|
|
1149
|
-
floating: positionerElement
|
|
1150
|
-
}
|
|
1151
|
-
});
|
|
1152
|
-
let ariaHasPopup;
|
|
1153
|
-
let ariaExpanded;
|
|
1154
|
-
if (!inline) {
|
|
1155
|
-
ariaHasPopup = grid ? 'grid' : 'listbox';
|
|
1156
|
-
ariaExpanded = open ? 'true' : 'false';
|
|
1157
|
-
}
|
|
1158
|
-
const role = React__namespace.useMemo(() => {
|
|
1159
|
-
const isPlainInput = inputElement?.tagName === 'INPUT';
|
|
1160
|
-
// During SSR and initial hydration, the input ref is not available yet.
|
|
1161
|
-
// Assume an input-like control so combobox ARIA attributes are present.
|
|
1162
|
-
const shouldTreatAsInput = inputElement == null || isPlainInput;
|
|
1163
|
-
const shouldApplyAria = shouldTreatAsInput || open;
|
|
1164
|
-
const reference = shouldTreatAsInput ? {
|
|
1165
|
-
autoComplete: 'off',
|
|
1166
|
-
spellCheck: 'false',
|
|
1167
|
-
autoCorrect: 'off',
|
|
1168
|
-
autoCapitalize: 'none'
|
|
1169
|
-
} : {};
|
|
1170
|
-
if (shouldApplyAria) {
|
|
1171
|
-
reference.role = 'combobox';
|
|
1172
|
-
reference['aria-expanded'] = ariaExpanded;
|
|
1173
|
-
reference['aria-haspopup'] = ariaHasPopup;
|
|
1174
|
-
reference['aria-controls'] = open ? listElement?.id : undefined;
|
|
1175
|
-
reference['aria-autocomplete'] = autoComplete;
|
|
1176
|
-
}
|
|
1177
|
-
return {
|
|
1178
|
-
reference,
|
|
1179
|
-
floating: {
|
|
1180
|
-
role: 'presentation'
|
|
1181
|
-
}
|
|
1182
|
-
};
|
|
1183
|
-
}, [inputElement, open, ariaExpanded, ariaHasPopup, listElement?.id, autoComplete]);
|
|
1184
|
-
const click = ScrollAreaViewport.useClick(floatingRootContext, {
|
|
1185
|
-
enabled: !readOnly && !disabled && openOnInputClick,
|
|
1186
|
-
event: 'mousedown-only',
|
|
1187
|
-
toggle: false,
|
|
1188
|
-
// Apply a small delay for touch to let iOS viewport centering settle.
|
|
1189
|
-
// This avoids top-bottom flip flickers if the preferred position is "top" when first tapping.
|
|
1190
|
-
touchOpenDelay: inputInsidePopup ? 0 : 50,
|
|
1191
|
-
reason: clamp.inputPress
|
|
1192
|
-
});
|
|
1193
|
-
const dismiss = ScrollAreaViewport.useDismiss(floatingRootContext, {
|
|
1194
|
-
enabled: !readOnly && !disabled && !inline,
|
|
1195
|
-
outsidePressEvent: {
|
|
1196
|
-
mouse: 'sloppy',
|
|
1197
|
-
// The visual viewport (affected by the mobile software keyboard) can be
|
|
1198
|
-
// somewhat small. The user may want to scroll the screen to see more of
|
|
1199
|
-
// the popup.
|
|
1200
|
-
touch: 'intentional'
|
|
1201
|
-
},
|
|
1202
|
-
// Without a popup, let the Escape key bubble the event up to other popups' handlers.
|
|
1203
|
-
bubbles: inline ? true : undefined,
|
|
1204
|
-
outsidePress(event) {
|
|
1205
|
-
const target = clamp.getTarget(event);
|
|
1206
|
-
return !clamp.contains(triggerElement, target) && !clamp.contains(clearRef.current, target) && !clamp.contains(chipsContainerRef.current, target) && !clamp.contains(inputGroupElement, target);
|
|
1207
|
-
}
|
|
1208
|
-
});
|
|
1209
|
-
const listNavigation = MenuSubmenuTrigger.useListNavigation(floatingRootContext, {
|
|
1210
|
-
enabled: !readOnly && !disabled,
|
|
1211
|
-
id,
|
|
1212
|
-
listRef,
|
|
1213
|
-
activeIndex,
|
|
1214
|
-
selectedIndex,
|
|
1215
|
-
virtual: true,
|
|
1216
|
-
loopFocus,
|
|
1217
|
-
allowEscape: loopFocus && !autoHighlightMode,
|
|
1218
|
-
focusItemOnOpen: queryChangedAfterOpen || selectionMode === 'none' && !autoHighlightMode ? false : 'auto',
|
|
1219
|
-
focusItemOnHover: highlightItemOnHover,
|
|
1220
|
-
resetOnPointerLeave: !keepHighlight,
|
|
1221
|
-
// `cols` > 1 enables grid navigation.
|
|
1222
|
-
// Since <Combobox.Row> infers column sizes (and is required when building a grid),
|
|
1223
|
-
// it works correctly even with a value of `2`.
|
|
1224
|
-
// Floating UI tests don't require `role="row"` wrappers, so retains the number API.
|
|
1225
|
-
cols: grid ? 2 : 1,
|
|
1226
|
-
orientation: grid ? 'horizontal' : undefined,
|
|
1227
|
-
disabledIndices: useRenderElement.EMPTY_ARRAY,
|
|
1228
|
-
onNavigate(nextActiveIndex, event) {
|
|
1229
|
-
// Retain the highlight only while actually transitioning out or closed.
|
|
1230
|
-
if (!event && !open || transitionStatus === 'ending') {
|
|
1231
|
-
return;
|
|
1232
|
-
}
|
|
1233
|
-
if (!event) {
|
|
1234
|
-
setIndices({
|
|
1235
|
-
activeIndex: nextActiveIndex
|
|
1236
|
-
});
|
|
1237
|
-
} else {
|
|
1238
|
-
setIndices({
|
|
1239
|
-
activeIndex: nextActiveIndex,
|
|
1240
|
-
type: keyboardActiveRef.current ? 'keyboard' : 'pointer'
|
|
1241
|
-
});
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
});
|
|
1245
|
-
const {
|
|
1246
|
-
getReferenceProps,
|
|
1247
|
-
getFloatingProps,
|
|
1248
|
-
getItemProps
|
|
1249
|
-
} = ScrollAreaViewport.useInteractions([role, click, dismiss, listNavigation]);
|
|
1250
|
-
ScrollAreaViewport.useOnFirstRender(() => {
|
|
1251
|
-
store.update({
|
|
1252
|
-
inline: inlineProp,
|
|
1253
|
-
popupProps: getFloatingProps(),
|
|
1254
|
-
inputProps: getReferenceProps(),
|
|
1255
|
-
triggerProps,
|
|
1256
|
-
getItemProps,
|
|
1257
|
-
setOpen,
|
|
1258
|
-
setInputValue,
|
|
1259
|
-
setSelectedValue,
|
|
1260
|
-
setIndices,
|
|
1261
|
-
onItemHighlighted,
|
|
1262
|
-
handleSelection,
|
|
1263
|
-
forceMount,
|
|
1264
|
-
requestSubmit
|
|
1265
|
-
});
|
|
1266
|
-
});
|
|
1267
|
-
clamp.useIsoLayoutEffect(() => {
|
|
1268
|
-
store.update({
|
|
1269
|
-
id,
|
|
1270
|
-
selectedValue,
|
|
1271
|
-
open,
|
|
1272
|
-
mounted,
|
|
1273
|
-
transitionStatus,
|
|
1274
|
-
items,
|
|
1275
|
-
inline: inlineProp,
|
|
1276
|
-
popupProps: getFloatingProps(),
|
|
1277
|
-
inputProps: getReferenceProps(),
|
|
1278
|
-
triggerProps,
|
|
1279
|
-
openMethod,
|
|
1280
|
-
getItemProps,
|
|
1281
|
-
selectionMode,
|
|
1282
|
-
name,
|
|
1283
|
-
disabled,
|
|
1284
|
-
readOnly,
|
|
1285
|
-
required,
|
|
1286
|
-
grid,
|
|
1287
|
-
isGrouped,
|
|
1288
|
-
virtualized,
|
|
1289
|
-
onOpenChangeComplete,
|
|
1290
|
-
openOnInputClick,
|
|
1291
|
-
itemToStringLabel,
|
|
1292
|
-
modal,
|
|
1293
|
-
autoHighlight: autoHighlightMode,
|
|
1294
|
-
isItemEqualToValue,
|
|
1295
|
-
submitOnItemClick,
|
|
1296
|
-
hasInputValue,
|
|
1297
|
-
requestSubmit
|
|
1298
|
-
});
|
|
1299
|
-
}, [store, id, selectedValue, open, mounted, transitionStatus, items, getFloatingProps, getReferenceProps, getItemProps, openMethod, triggerProps, selectionMode, name, disabled, readOnly, required, validation, grid, isGrouped, virtualized, onOpenChangeComplete, openOnInputClick, itemToStringLabel, modal, isItemEqualToValue, submitOnItemClick, hasInputValue, inlineProp, requestSubmit, autoHighlightMode]);
|
|
1300
|
-
const hiddenInputRef = useRenderElement.useMergedRefs(inputRefProp, validation.inputRef);
|
|
1301
|
-
const itemsContextValue = React__namespace.useMemo(() => ({
|
|
1302
|
-
query,
|
|
1303
|
-
hasItems,
|
|
1304
|
-
filteredItems,
|
|
1305
|
-
flatFilteredItems
|
|
1306
|
-
}), [query, hasItems, filteredItems, flatFilteredItems]);
|
|
1307
|
-
const serializedValue = React__namespace.useMemo(() => {
|
|
1308
|
-
if (Array.isArray(fieldRawValue)) {
|
|
1309
|
-
return '';
|
|
1310
|
-
}
|
|
1311
|
-
return stringifyAsValue(fieldRawValue, itemToStringValue);
|
|
1312
|
-
}, [fieldRawValue, itemToStringValue]);
|
|
1313
|
-
const hasMultipleSelection = multiple && Array.isArray(selectedValue) && selectedValue.length > 0;
|
|
1314
|
-
const hiddenInputName = multiple || selectionMode === 'none' ? undefined : name;
|
|
1315
|
-
const hiddenInputs = React__namespace.useMemo(() => {
|
|
1316
|
-
if (!multiple || !Array.isArray(selectedValue) || !name) {
|
|
1317
|
-
return null;
|
|
1318
|
-
}
|
|
1319
|
-
return selectedValue.map(value => {
|
|
1320
|
-
const currentSerializedValue = stringifyAsValue(value, itemToStringValue);
|
|
1321
|
-
return /*#__PURE__*/jsxRuntime.jsx("input", {
|
|
1322
|
-
type: "hidden",
|
|
1323
|
-
name: name,
|
|
1324
|
-
value: currentSerializedValue
|
|
1325
|
-
}, currentSerializedValue);
|
|
1326
|
-
});
|
|
1327
|
-
}, [multiple, selectedValue, name, itemToStringValue]);
|
|
1328
|
-
const children = /*#__PURE__*/jsxRuntime.jsxs(React__namespace.Fragment, {
|
|
1329
|
-
children: [props.children, /*#__PURE__*/jsxRuntime.jsx("input", {
|
|
1330
|
-
...validation.getInputValidationProps({
|
|
1331
|
-
// Move focus when the hidden input is focused.
|
|
1332
|
-
onFocus() {
|
|
1333
|
-
if (inputInsidePopup) {
|
|
1334
|
-
triggerElement?.focus();
|
|
1335
|
-
return;
|
|
1336
|
-
}
|
|
1337
|
-
(inputRef.current || triggerElement)?.focus();
|
|
1338
|
-
},
|
|
1339
|
-
// Handle browser autofill.
|
|
1340
|
-
onChange(event) {
|
|
1341
|
-
// Workaround for https://github.com/facebook/react/issues/9023
|
|
1342
|
-
if (event.nativeEvent.defaultPrevented) {
|
|
1343
|
-
return;
|
|
1344
|
-
}
|
|
1345
|
-
const nextValue = event.target.value;
|
|
1346
|
-
const details = clamp.createChangeEventDetails(clamp.none, event.nativeEvent);
|
|
1347
|
-
function handleChange() {
|
|
1348
|
-
// Browser autofill only writes a single scalar value.
|
|
1349
|
-
if (multiple) {
|
|
1350
|
-
return;
|
|
1351
|
-
}
|
|
1352
|
-
if (selectionMode === 'none') {
|
|
1353
|
-
setDirty(nextValue !== validityData.initialValue);
|
|
1354
|
-
setInputValue(nextValue, details);
|
|
1355
|
-
if (shouldValidateOnChange()) {
|
|
1356
|
-
validation.commit(nextValue);
|
|
1357
|
-
}
|
|
1358
|
-
return;
|
|
1359
|
-
}
|
|
1360
|
-
const matchingValue = valuesRef.current.find(v => {
|
|
1361
|
-
const candidate = stringifyAsValue(v, itemToStringValue);
|
|
1362
|
-
if (candidate.toLowerCase() === nextValue.toLowerCase()) {
|
|
1363
|
-
return true;
|
|
1364
|
-
}
|
|
1365
|
-
return false;
|
|
1366
|
-
});
|
|
1367
|
-
if (matchingValue != null) {
|
|
1368
|
-
setDirty(matchingValue !== validityData.initialValue);
|
|
1369
|
-
setSelectedValue?.(matchingValue, details);
|
|
1370
|
-
if (shouldValidateOnChange()) {
|
|
1371
|
-
validation.commit(matchingValue);
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
if (items) {
|
|
1376
|
-
handleChange();
|
|
1377
|
-
} else {
|
|
1378
|
-
forceMount();
|
|
1379
|
-
queueMicrotask(handleChange);
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
}),
|
|
1383
|
-
id: id && hiddenInputName == null ? `${id}-hidden-input` : undefined,
|
|
1384
|
-
name: hiddenInputName,
|
|
1385
|
-
autoComplete: formAutoComplete,
|
|
1386
|
-
disabled: disabled,
|
|
1387
|
-
required: required && !hasMultipleSelection,
|
|
1388
|
-
readOnly: readOnly,
|
|
1389
|
-
value: serializedValue,
|
|
1390
|
-
ref: hiddenInputRef,
|
|
1391
|
-
style: hiddenInputName ? clamp.visuallyHiddenInput : clamp.visuallyHidden,
|
|
1392
|
-
tabIndex: -1,
|
|
1393
|
-
"aria-hidden": true
|
|
1394
|
-
}), hiddenInputs]
|
|
1395
|
-
});
|
|
1396
|
-
return /*#__PURE__*/jsxRuntime.jsx(ComboboxRootContext.Provider, {
|
|
1397
|
-
value: store,
|
|
1398
|
-
children: /*#__PURE__*/jsxRuntime.jsx(ComboboxFloatingContext.Provider, {
|
|
1399
|
-
value: floatingRootContext,
|
|
1400
|
-
children: /*#__PURE__*/jsxRuntime.jsx(ComboboxDerivedItemsContext.Provider, {
|
|
1401
|
-
value: itemsContextValue,
|
|
1402
|
-
children: /*#__PURE__*/jsxRuntime.jsx(ComboboxInputValueContext.Provider, {
|
|
1403
|
-
value: inputValue,
|
|
1404
|
-
children: children
|
|
1405
|
-
})
|
|
1406
|
-
})
|
|
1407
|
-
})
|
|
1408
|
-
});
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
function AutocompleteRoot(props) {
|
|
1412
|
-
const {
|
|
1413
|
-
openOnInputClick = false,
|
|
1414
|
-
value,
|
|
1415
|
-
defaultValue,
|
|
1416
|
-
onValueChange,
|
|
1417
|
-
mode = 'list',
|
|
1418
|
-
itemToStringValue,
|
|
1419
|
-
...other
|
|
1420
|
-
} = props;
|
|
1421
|
-
const enableInline = mode === 'inline' || mode === 'both';
|
|
1422
|
-
const staticItems = mode === 'inline' || mode === 'none';
|
|
1423
|
-
|
|
1424
|
-
// Mirror the typed value for uncontrolled usage so we can compose the temporary
|
|
1425
|
-
// inline input value.
|
|
1426
|
-
const isControlled = value !== undefined;
|
|
1427
|
-
const [internalValue, setInternalValue] = React__namespace.useState(defaultValue ?? '');
|
|
1428
|
-
const [inlineInputValue, setInlineInputValue] = React__namespace.useState('');
|
|
1429
|
-
React__namespace.useEffect(() => {
|
|
1430
|
-
if (isControlled) {
|
|
1431
|
-
setInlineInputValue('');
|
|
1432
|
-
}
|
|
1433
|
-
}, [value, isControlled]);
|
|
1434
|
-
|
|
1435
|
-
// Compose the input value shown to the user: inline value takes precedence when present.
|
|
1436
|
-
let resolvedInputValue;
|
|
1437
|
-
if (enableInline && inlineInputValue !== '') {
|
|
1438
|
-
resolvedInputValue = inlineInputValue;
|
|
1439
|
-
} else if (isControlled) {
|
|
1440
|
-
resolvedInputValue = value ?? '';
|
|
1441
|
-
} else {
|
|
1442
|
-
resolvedInputValue = internalValue;
|
|
1443
|
-
}
|
|
1444
|
-
const handleValueChange = clamp.useStableCallback((nextValue, eventDetails) => {
|
|
1445
|
-
setInlineInputValue('');
|
|
1446
|
-
if (!isControlled) {
|
|
1447
|
-
setInternalValue(nextValue);
|
|
1448
|
-
}
|
|
1449
|
-
onValueChange?.(nextValue, eventDetails);
|
|
1450
|
-
});
|
|
1451
|
-
const collator = useCoreFilter();
|
|
1452
|
-
const baseFilter = React__namespace.useMemo(() => {
|
|
1453
|
-
if (other.filter !== undefined) {
|
|
1454
|
-
return other.filter;
|
|
1455
|
-
}
|
|
1456
|
-
return collator.contains;
|
|
1457
|
-
}, [other.filter, collator]);
|
|
1458
|
-
const resolvedQuery = String(isControlled ? value : internalValue).trim();
|
|
86
|
+
return collator.contains;
|
|
87
|
+
}, [other.filter, collator]);
|
|
88
|
+
const resolvedQuery = String(isControlled ? value : internalValue).trim();
|
|
1459
89
|
|
|
1460
90
|
// In "both", wrap filtering to use only the typed value, ignoring the inline value.
|
|
1461
91
|
const resolvedFilter = React__namespace.useMemo(() => {
|
|
1462
|
-
if (mode !== 'both') {
|
|
1463
|
-
return staticItems ? null : baseFilter;
|
|
1464
|
-
}
|
|
1465
|
-
if (baseFilter === null) {
|
|
1466
|
-
return null;
|
|
1467
|
-
}
|
|
1468
|
-
return (item, _query, toString) => {
|
|
1469
|
-
return baseFilter(item, resolvedQuery, toString);
|
|
1470
|
-
};
|
|
1471
|
-
}, [baseFilter, mode, resolvedQuery, staticItems]);
|
|
1472
|
-
const handleItemHighlighted = clamp.useStableCallback((highlightedValue, eventDetails) => {
|
|
1473
|
-
props.onItemHighlighted?.(highlightedValue, eventDetails);
|
|
1474
|
-
if (eventDetails.reason === clamp.pointer) {
|
|
1475
|
-
return;
|
|
1476
|
-
}
|
|
1477
|
-
if (enableInline) {
|
|
1478
|
-
if (highlightedValue == null) {
|
|
1479
|
-
setInlineInputValue('');
|
|
1480
|
-
} else {
|
|
1481
|
-
setInlineInputValue(stringifyAsLabel(highlightedValue, itemToStringValue));
|
|
1482
|
-
}
|
|
1483
|
-
} else {
|
|
1484
|
-
setInlineInputValue('');
|
|
1485
|
-
}
|
|
1486
|
-
});
|
|
1487
|
-
return /*#__PURE__*/jsxRuntime.jsx(AriaCombobox, {
|
|
1488
|
-
...other,
|
|
1489
|
-
itemToStringLabel: itemToStringValue,
|
|
1490
|
-
openOnInputClick: openOnInputClick,
|
|
1491
|
-
selectionMode: "none",
|
|
1492
|
-
fillInputOnItemPress: true,
|
|
1493
|
-
filter: resolvedFilter,
|
|
1494
|
-
autoComplete: mode,
|
|
1495
|
-
inputValue: resolvedInputValue,
|
|
1496
|
-
defaultInputValue: defaultValue,
|
|
1497
|
-
onInputValueChange: handleValueChange,
|
|
1498
|
-
onItemHighlighted: handleItemHighlighted
|
|
1499
|
-
});
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
function AutocompleteValue(props) {
|
|
1503
|
-
const {
|
|
1504
|
-
children
|
|
1505
|
-
} = props;
|
|
1506
|
-
const inputValue = useComboboxInputValueContext();
|
|
1507
|
-
let returnValue = null;
|
|
1508
|
-
if (typeof children === 'function') {
|
|
1509
|
-
returnValue = children(String(inputValue));
|
|
1510
|
-
} else if (children != null) {
|
|
1511
|
-
returnValue = children;
|
|
1512
|
-
} else {
|
|
1513
|
-
returnValue = inputValue;
|
|
1514
|
-
}
|
|
1515
|
-
return /*#__PURE__*/jsxRuntime.jsx(React__namespace.Fragment, {
|
|
1516
|
-
children: returnValue
|
|
1517
|
-
});
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
const triggerStateAttributesMapping = {
|
|
1521
|
-
...ScrollAreaViewport.pressableTriggerOpenStateMapping,
|
|
1522
|
-
...NumberFieldInput.fieldValidityMapping,
|
|
1523
|
-
popupSide: side => side ? {
|
|
1524
|
-
'data-popup-side': side
|
|
1525
|
-
} : null,
|
|
1526
|
-
listEmpty: empty => empty ? {
|
|
1527
|
-
'data-list-empty': ''
|
|
1528
|
-
} : null
|
|
1529
|
-
};
|
|
1530
|
-
|
|
1531
|
-
function getDefaultLabelId(id) {
|
|
1532
|
-
return id == null ? undefined : `${id}-label`;
|
|
1533
|
-
}
|
|
1534
|
-
function resolveAriaLabelledBy(fieldLabelId, localLabelId) {
|
|
1535
|
-
return fieldLabelId ?? localLabelId;
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1538
|
-
const BOUNDARY_OFFSET = 2;
|
|
1539
|
-
|
|
1540
|
-
/**
|
|
1541
|
-
* A button that opens the popup.
|
|
1542
|
-
* Renders a `<button>` element.
|
|
1543
|
-
*/
|
|
1544
|
-
const ComboboxTrigger = /*#__PURE__*/React__namespace.forwardRef(function ComboboxTrigger(componentProps, forwardedRef) {
|
|
1545
|
-
const {
|
|
1546
|
-
render,
|
|
1547
|
-
className,
|
|
1548
|
-
nativeButton = true,
|
|
1549
|
-
disabled: disabledProp = false,
|
|
1550
|
-
id: idProp,
|
|
1551
|
-
...elementProps
|
|
1552
|
-
} = componentProps;
|
|
1553
|
-
const {
|
|
1554
|
-
state: fieldState,
|
|
1555
|
-
disabled: fieldDisabled,
|
|
1556
|
-
setTouched,
|
|
1557
|
-
setFocused,
|
|
1558
|
-
validationMode,
|
|
1559
|
-
validation
|
|
1560
|
-
} = NumberFieldInput.useFieldRootContext();
|
|
1561
|
-
const {
|
|
1562
|
-
labelId: fieldLabelId
|
|
1563
|
-
} = NumberFieldInput.useLabelableContext();
|
|
1564
|
-
const store = useComboboxRootContext();
|
|
1565
|
-
const {
|
|
1566
|
-
filteredItems
|
|
1567
|
-
} = useComboboxDerivedItemsContext();
|
|
1568
|
-
const selectionMode = ScrollAreaViewport.useStore(store, selectors.selectionMode);
|
|
1569
|
-
const comboboxDisabled = ScrollAreaViewport.useStore(store, selectors.disabled);
|
|
1570
|
-
const readOnly = ScrollAreaViewport.useStore(store, selectors.readOnly);
|
|
1571
|
-
const required = ScrollAreaViewport.useStore(store, selectors.required);
|
|
1572
|
-
const mounted = ScrollAreaViewport.useStore(store, selectors.mounted);
|
|
1573
|
-
const popupSideValue = ScrollAreaViewport.useStore(store, selectors.popupSide);
|
|
1574
|
-
const positionerElement = ScrollAreaViewport.useStore(store, selectors.positionerElement);
|
|
1575
|
-
const listElement = ScrollAreaViewport.useStore(store, selectors.listElement);
|
|
1576
|
-
const triggerProps = ScrollAreaViewport.useStore(store, selectors.triggerProps);
|
|
1577
|
-
const triggerElement = ScrollAreaViewport.useStore(store, selectors.triggerElement);
|
|
1578
|
-
const inputInsidePopup = ScrollAreaViewport.useStore(store, selectors.inputInsidePopup);
|
|
1579
|
-
const rootId = ScrollAreaViewport.useStore(store, selectors.id);
|
|
1580
|
-
const comboboxLabelId = ScrollAreaViewport.useStore(store, selectors.labelId);
|
|
1581
|
-
const open = ScrollAreaViewport.useStore(store, selectors.open);
|
|
1582
|
-
const selectedValue = ScrollAreaViewport.useStore(store, selectors.selectedValue);
|
|
1583
|
-
const activeIndex = ScrollAreaViewport.useStore(store, selectors.activeIndex);
|
|
1584
|
-
const selectedIndex = ScrollAreaViewport.useStore(store, selectors.selectedIndex);
|
|
1585
|
-
const hasSelectedValue = ScrollAreaViewport.useStore(store, selectors.hasSelectedValue);
|
|
1586
|
-
const floatingRootContext = useComboboxFloatingContext();
|
|
1587
|
-
const inputValue = useComboboxInputValueContext();
|
|
1588
|
-
const focusTimeout = clamp.useTimeout();
|
|
1589
|
-
const disabled = fieldDisabled || comboboxDisabled || disabledProp;
|
|
1590
|
-
const listEmpty = filteredItems.length === 0;
|
|
1591
|
-
const popupSide = mounted && positionerElement ? popupSideValue : null;
|
|
1592
|
-
NumberFieldInput.useLabelableId({
|
|
1593
|
-
id: inputInsidePopup ? idProp : undefined
|
|
1594
|
-
});
|
|
1595
|
-
const id = inputInsidePopup ? idProp ?? rootId : idProp;
|
|
1596
|
-
const ariaLabelledBy = resolveAriaLabelledBy(fieldLabelId, comboboxLabelId);
|
|
1597
|
-
const currentPointerTypeRef = React__namespace.useRef('');
|
|
1598
|
-
function trackPointerType(event) {
|
|
1599
|
-
currentPointerTypeRef.current = event.pointerType;
|
|
1600
|
-
}
|
|
1601
|
-
const domReference = floatingRootContext.useState('domReferenceElement');
|
|
1602
|
-
|
|
1603
|
-
// Update the floating root context to use the trigger element when it differs from the current reference.
|
|
1604
|
-
// This ensures useClick and useTypeahead attach handlers to the correct element.
|
|
1605
|
-
React__namespace.useEffect(() => {
|
|
1606
|
-
if (!inputInsidePopup) {
|
|
1607
|
-
return;
|
|
1608
|
-
}
|
|
1609
|
-
if (triggerElement && triggerElement !== domReference) {
|
|
1610
|
-
floatingRootContext.set('domReferenceElement', triggerElement);
|
|
1611
|
-
}
|
|
1612
|
-
}, [triggerElement, domReference, floatingRootContext, inputInsidePopup]);
|
|
1613
|
-
const {
|
|
1614
|
-
reference: triggerTypeaheadProps
|
|
1615
|
-
} = MenuSubmenuTrigger.useTypeahead(floatingRootContext, {
|
|
1616
|
-
enabled: !open && !readOnly && !comboboxDisabled && selectionMode === 'single',
|
|
1617
|
-
listRef: store.state.labelsRef,
|
|
1618
|
-
activeIndex,
|
|
1619
|
-
selectedIndex,
|
|
1620
|
-
onMatch(index) {
|
|
1621
|
-
const nextSelectedValue = store.state.valuesRef.current[index];
|
|
1622
|
-
if (nextSelectedValue !== undefined) {
|
|
1623
|
-
store.state.setSelectedValue(nextSelectedValue, clamp.createChangeEventDetails('none'));
|
|
1624
|
-
}
|
|
1625
|
-
}
|
|
1626
|
-
});
|
|
1627
|
-
const {
|
|
1628
|
-
reference: triggerClickProps
|
|
1629
|
-
} = ScrollAreaViewport.useClick(floatingRootContext, {
|
|
1630
|
-
enabled: !readOnly && !comboboxDisabled,
|
|
1631
|
-
event: 'mousedown'
|
|
1632
|
-
});
|
|
1633
|
-
const {
|
|
1634
|
-
buttonRef,
|
|
1635
|
-
getButtonProps
|
|
1636
|
-
} = clamp.useButton({
|
|
1637
|
-
native: nativeButton,
|
|
1638
|
-
disabled
|
|
1639
|
-
});
|
|
1640
|
-
const state = {
|
|
1641
|
-
...fieldState,
|
|
1642
|
-
open,
|
|
1643
|
-
disabled,
|
|
1644
|
-
popupSide,
|
|
1645
|
-
listEmpty,
|
|
1646
|
-
placeholder: !hasSelectedValue
|
|
1647
|
-
};
|
|
1648
|
-
const setTriggerElement = clamp.useStableCallback(element => {
|
|
1649
|
-
store.set('triggerElement', element);
|
|
1650
|
-
});
|
|
1651
|
-
const element = useRenderElement.useRenderElement('button', componentProps, {
|
|
1652
|
-
ref: [forwardedRef, buttonRef, setTriggerElement],
|
|
1653
|
-
state,
|
|
1654
|
-
props: [triggerProps, triggerClickProps, triggerTypeaheadProps, {
|
|
1655
|
-
id,
|
|
1656
|
-
tabIndex: inputInsidePopup ? 0 : -1,
|
|
1657
|
-
role: inputInsidePopup ? 'combobox' : undefined,
|
|
1658
|
-
'aria-expanded': open ? 'true' : 'false',
|
|
1659
|
-
'aria-haspopup': inputInsidePopup ? 'dialog' : 'listbox',
|
|
1660
|
-
'aria-controls': open ? listElement?.id : undefined,
|
|
1661
|
-
'aria-required': inputInsidePopup ? required || undefined : undefined,
|
|
1662
|
-
'aria-labelledby': ariaLabelledBy,
|
|
1663
|
-
onPointerDown: trackPointerType,
|
|
1664
|
-
onPointerEnter: trackPointerType,
|
|
1665
|
-
onFocus() {
|
|
1666
|
-
setFocused(true);
|
|
1667
|
-
if (disabled || readOnly) {
|
|
1668
|
-
return;
|
|
1669
|
-
}
|
|
1670
|
-
focusTimeout.start(0, store.state.forceMount);
|
|
1671
|
-
},
|
|
1672
|
-
onBlur(event) {
|
|
1673
|
-
// If focus is moving into the popup, don't count it as a blur.
|
|
1674
|
-
if (clamp.contains(positionerElement, event.relatedTarget)) {
|
|
1675
|
-
return;
|
|
1676
|
-
}
|
|
1677
|
-
setTouched(true);
|
|
1678
|
-
setFocused(false);
|
|
1679
|
-
if (validationMode === 'onBlur') {
|
|
1680
|
-
const valueToValidate = selectionMode === 'none' ? inputValue : selectedValue;
|
|
1681
|
-
validation.commit(valueToValidate);
|
|
1682
|
-
}
|
|
1683
|
-
},
|
|
1684
|
-
onMouseDown(event) {
|
|
1685
|
-
if (disabled || readOnly) {
|
|
1686
|
-
return;
|
|
1687
|
-
}
|
|
1688
|
-
if (!inputInsidePopup) {
|
|
1689
|
-
floatingRootContext.set('domReferenceElement', event.currentTarget);
|
|
1690
|
-
}
|
|
1691
|
-
|
|
1692
|
-
// Ensure items are registered for initial selection highlight.
|
|
1693
|
-
store.state.forceMount();
|
|
1694
|
-
if (currentPointerTypeRef.current !== 'touch') {
|
|
1695
|
-
store.state.inputRef.current?.focus();
|
|
1696
|
-
if (!inputInsidePopup) {
|
|
1697
|
-
event.preventDefault();
|
|
1698
|
-
}
|
|
1699
|
-
}
|
|
1700
|
-
if (open) {
|
|
1701
|
-
return;
|
|
1702
|
-
}
|
|
1703
|
-
const doc = clamp.ownerDocument(event.currentTarget);
|
|
1704
|
-
function handleMouseUp(mouseEvent) {
|
|
1705
|
-
if (!triggerElement) {
|
|
1706
|
-
return;
|
|
1707
|
-
}
|
|
1708
|
-
const mouseUpTarget = clamp.getTarget(mouseEvent);
|
|
1709
|
-
const positioner = store.state.positionerElement;
|
|
1710
|
-
const list = store.state.listElement;
|
|
1711
|
-
if (clamp.contains(triggerElement, mouseUpTarget) || clamp.contains(positioner, mouseUpTarget) || clamp.contains(list, mouseUpTarget) || mouseUpTarget === triggerElement) {
|
|
1712
|
-
return;
|
|
1713
|
-
}
|
|
1714
|
-
const bounds = MenuSubmenuTrigger.getPseudoElementBounds(triggerElement);
|
|
1715
|
-
const withinHorizontal = mouseEvent.clientX >= bounds.left - BOUNDARY_OFFSET && mouseEvent.clientX <= bounds.right + BOUNDARY_OFFSET;
|
|
1716
|
-
const withinVertical = mouseEvent.clientY >= bounds.top - BOUNDARY_OFFSET && mouseEvent.clientY <= bounds.bottom + BOUNDARY_OFFSET;
|
|
1717
|
-
if (withinHorizontal && withinVertical) {
|
|
1718
|
-
return;
|
|
1719
|
-
}
|
|
1720
|
-
store.state.setOpen(false, clamp.createChangeEventDetails('cancel-open', mouseEvent));
|
|
1721
|
-
}
|
|
1722
|
-
if (inputInsidePopup) {
|
|
1723
|
-
doc.addEventListener('mouseup', handleMouseUp, {
|
|
1724
|
-
once: true
|
|
1725
|
-
});
|
|
1726
|
-
}
|
|
1727
|
-
},
|
|
1728
|
-
onKeyDown(event) {
|
|
1729
|
-
if (disabled || readOnly) {
|
|
1730
|
-
return;
|
|
1731
|
-
}
|
|
1732
|
-
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
1733
|
-
clamp.stopEvent(event);
|
|
1734
|
-
store.state.setOpen(true, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent));
|
|
1735
|
-
store.state.inputRef.current?.focus();
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
}, validation ? validation.getValidationProps(elementProps) : elementProps, getButtonProps],
|
|
1739
|
-
stateAttributesMapping: triggerStateAttributesMapping
|
|
1740
|
-
});
|
|
1741
|
-
return element;
|
|
1742
|
-
});
|
|
1743
|
-
if (process.env.NODE_ENV !== "production") ComboboxTrigger.displayName = "ComboboxTrigger";
|
|
1744
|
-
|
|
1745
|
-
const ComboboxChipsContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
1746
|
-
if (process.env.NODE_ENV !== "production") ComboboxChipsContext.displayName = "ComboboxChipsContext";
|
|
1747
|
-
function useComboboxChipsContext() {
|
|
1748
|
-
return React__namespace.useContext(ComboboxChipsContext);
|
|
1749
|
-
}
|
|
1750
|
-
|
|
1751
|
-
const ComboboxPositionerContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
1752
|
-
if (process.env.NODE_ENV !== "production") ComboboxPositionerContext.displayName = "ComboboxPositionerContext";
|
|
1753
|
-
function useComboboxPositionerContext(optional) {
|
|
1754
|
-
const context = React__namespace.useContext(ComboboxPositionerContext);
|
|
1755
|
-
if (context === undefined && !optional) {
|
|
1756
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Combobox.Popup> and <Combobox.Arrow> must be used within the <Combobox.Positioner> component' : useRenderElement.formatErrorMessage(21));
|
|
1757
|
-
}
|
|
1758
|
-
return context;
|
|
1759
|
-
}
|
|
1760
|
-
|
|
1761
|
-
/**
|
|
1762
|
-
* @internal
|
|
1763
|
-
*/
|
|
1764
|
-
const ComboboxInternalDismissButton = /*#__PURE__*/React__namespace.forwardRef(function ComboboxInternalDismissButton(_, forwardedRef) {
|
|
1765
|
-
const store = useComboboxRootContext();
|
|
1766
|
-
const {
|
|
1767
|
-
buttonRef,
|
|
1768
|
-
getButtonProps
|
|
1769
|
-
} = clamp.useButton({
|
|
1770
|
-
native: false
|
|
1771
|
-
});
|
|
1772
|
-
const mergedRef = useRenderElement.useMergedRefs(forwardedRef, buttonRef);
|
|
1773
|
-
const handleDismiss = clamp.useStableCallback(event => {
|
|
1774
|
-
store.state.setOpen(false, clamp.createChangeEventDetails(clamp.closePress, event.nativeEvent, event.currentTarget));
|
|
1775
|
-
});
|
|
1776
|
-
const dismissProps = getButtonProps({
|
|
1777
|
-
onClick: handleDismiss
|
|
1778
|
-
});
|
|
1779
|
-
return /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
1780
|
-
ref: mergedRef,
|
|
1781
|
-
...dismissProps,
|
|
1782
|
-
"aria-label": "Dismiss",
|
|
1783
|
-
tabIndex: undefined,
|
|
1784
|
-
style: clamp.visuallyHiddenInput
|
|
1785
|
-
});
|
|
1786
|
-
});
|
|
1787
|
-
if (process.env.NODE_ENV !== "production") ComboboxInternalDismissButton.displayName = "ComboboxInternalDismissButton";
|
|
1788
|
-
|
|
1789
|
-
const ComboboxInput = /*#__PURE__*/React__namespace.forwardRef(function ComboboxInput(componentProps, forwardedRef) {
|
|
1790
|
-
const {
|
|
1791
|
-
render,
|
|
1792
|
-
className,
|
|
1793
|
-
disabled: disabledProp = false,
|
|
1794
|
-
id: idProp,
|
|
1795
|
-
...elementProps
|
|
1796
|
-
} = componentProps;
|
|
1797
|
-
const {
|
|
1798
|
-
state: fieldState,
|
|
1799
|
-
disabled: fieldDisabled,
|
|
1800
|
-
setTouched,
|
|
1801
|
-
setFocused,
|
|
1802
|
-
validationMode,
|
|
1803
|
-
validation
|
|
1804
|
-
} = NumberFieldInput.useFieldRootContext();
|
|
1805
|
-
const {
|
|
1806
|
-
labelId: fieldLabelId
|
|
1807
|
-
} = NumberFieldInput.useLabelableContext();
|
|
1808
|
-
const comboboxChipsContext = useComboboxChipsContext();
|
|
1809
|
-
const positioning = useComboboxPositionerContext(true);
|
|
1810
|
-
const hasPositionerParent = Boolean(positioning);
|
|
1811
|
-
const store = useComboboxRootContext();
|
|
1812
|
-
const {
|
|
1813
|
-
filteredItems
|
|
1814
|
-
} = useComboboxDerivedItemsContext();
|
|
1815
|
-
// `inputValue` can't be placed in the store.
|
|
1816
|
-
// https://github.com/mui/base-ui/issues/2703
|
|
1817
|
-
const inputValue = useComboboxInputValueContext();
|
|
1818
|
-
const direction = ScrollAreaViewport.useDirection();
|
|
1819
|
-
const required = ScrollAreaViewport.useStore(store, selectors.required);
|
|
1820
|
-
const comboboxDisabled = ScrollAreaViewport.useStore(store, selectors.disabled);
|
|
1821
|
-
const readOnly = ScrollAreaViewport.useStore(store, selectors.readOnly);
|
|
1822
|
-
const name = ScrollAreaViewport.useStore(store, selectors.name);
|
|
1823
|
-
const selectionMode = ScrollAreaViewport.useStore(store, selectors.selectionMode);
|
|
1824
|
-
const autoHighlightMode = ScrollAreaViewport.useStore(store, selectors.autoHighlight);
|
|
1825
|
-
const inputProps = ScrollAreaViewport.useStore(store, selectors.inputProps);
|
|
1826
|
-
const triggerProps = ScrollAreaViewport.useStore(store, selectors.triggerProps);
|
|
1827
|
-
const open = ScrollAreaViewport.useStore(store, selectors.open);
|
|
1828
|
-
const mounted = ScrollAreaViewport.useStore(store, selectors.mounted);
|
|
1829
|
-
const selectedValue = ScrollAreaViewport.useStore(store, selectors.selectedValue);
|
|
1830
|
-
const popupSideValue = ScrollAreaViewport.useStore(store, selectors.popupSide);
|
|
1831
|
-
const positionerElement = ScrollAreaViewport.useStore(store, selectors.positionerElement);
|
|
1832
|
-
const rootId = ScrollAreaViewport.useStore(store, selectors.id);
|
|
1833
|
-
const inline = ScrollAreaViewport.useStore(store, selectors.inline);
|
|
1834
|
-
const modal = ScrollAreaViewport.useStore(store, selectors.modal);
|
|
1835
|
-
const autoHighlightEnabled = Boolean(autoHighlightMode);
|
|
1836
|
-
const popupSide = mounted && positionerElement ? popupSideValue : null;
|
|
1837
|
-
const disabled = fieldDisabled || comboboxDisabled || disabledProp;
|
|
1838
|
-
const listEmpty = filteredItems.length === 0;
|
|
1839
|
-
const isInsidePopup = hasPositionerParent || inline;
|
|
1840
|
-
const focusManagerModal = !isInsidePopup || modal;
|
|
1841
|
-
const id = clamp.useBaseUiId(idProp ?? (!isInsidePopup ? rootId : undefined));
|
|
1842
|
-
const ariaLabelledBy = resolveAriaLabelledBy(fieldLabelId, undefined);
|
|
1843
|
-
const fieldStateForInput = hasPositionerParent ? NumberFieldInput.DEFAULT_FIELD_STATE_ATTRIBUTES : fieldState;
|
|
1844
|
-
const [composingValue, setComposingValue] = React__namespace.useState(null);
|
|
1845
|
-
const isComposingRef = React__namespace.useRef(false);
|
|
1846
|
-
const lastActiveIndexRef = React__namespace.useRef(null);
|
|
1847
|
-
const shouldRestoreActiveIndexRef = React__namespace.useRef(false);
|
|
1848
|
-
const setInputElement = clamp.useStableCallback(element => {
|
|
1849
|
-
const nextIsInsidePopup = hasPositionerParent || store.state.inline;
|
|
1850
|
-
if (nextIsInsidePopup && !store.state.hasInputValue) {
|
|
1851
|
-
store.state.setInputValue('', clamp.createChangeEventDetails(clamp.none));
|
|
1852
|
-
}
|
|
1853
|
-
store.update({
|
|
1854
|
-
inputElement: element,
|
|
1855
|
-
inputInsidePopup: nextIsInsidePopup
|
|
1856
|
-
});
|
|
1857
|
-
});
|
|
1858
|
-
const validationProps = hasPositionerParent || !validation ? elementProps : validation.getValidationProps(elementProps);
|
|
1859
|
-
const state = {
|
|
1860
|
-
...fieldStateForInput,
|
|
1861
|
-
open,
|
|
1862
|
-
disabled,
|
|
1863
|
-
readOnly,
|
|
1864
|
-
popupSide,
|
|
1865
|
-
listEmpty
|
|
1866
|
-
};
|
|
1867
|
-
function handleKeyDown(event) {
|
|
1868
|
-
if (!comboboxChipsContext) {
|
|
1869
|
-
return undefined;
|
|
1870
|
-
}
|
|
1871
|
-
let nextIndex;
|
|
1872
|
-
const {
|
|
1873
|
-
highlightedChipIndex
|
|
1874
|
-
} = comboboxChipsContext;
|
|
1875
|
-
if (highlightedChipIndex !== undefined) {
|
|
1876
|
-
if (event.key === 'ArrowLeft') {
|
|
1877
|
-
event.preventDefault();
|
|
1878
|
-
if (highlightedChipIndex > 0) {
|
|
1879
|
-
nextIndex = highlightedChipIndex - 1;
|
|
1880
|
-
} else {
|
|
1881
|
-
nextIndex = undefined;
|
|
1882
|
-
}
|
|
1883
|
-
} else if (event.key === 'ArrowRight') {
|
|
1884
|
-
event.preventDefault();
|
|
1885
|
-
if (highlightedChipIndex < selectedValue.length - 1) {
|
|
1886
|
-
nextIndex = highlightedChipIndex + 1;
|
|
1887
|
-
} else {
|
|
1888
|
-
nextIndex = undefined;
|
|
1889
|
-
}
|
|
1890
|
-
} else if (event.key === 'Backspace' || event.key === 'Delete') {
|
|
1891
|
-
event.preventDefault();
|
|
1892
|
-
// Move highlight appropriately after removal.
|
|
1893
|
-
const computedNextIndex = highlightedChipIndex >= selectedValue.length - 1 ? selectedValue.length - 2 : highlightedChipIndex;
|
|
1894
|
-
// If the computed index is negative, treat it as no highlight.
|
|
1895
|
-
nextIndex = computedNextIndex >= 0 ? computedNextIndex : undefined;
|
|
1896
|
-
store.state.setIndices({
|
|
1897
|
-
activeIndex: null,
|
|
1898
|
-
selectedIndex: null,
|
|
1899
|
-
type: 'keyboard'
|
|
1900
|
-
});
|
|
1901
|
-
}
|
|
1902
|
-
return nextIndex;
|
|
1903
|
-
}
|
|
1904
|
-
|
|
1905
|
-
// Handle navigation when no chip is highlighted
|
|
1906
|
-
if (event.key === 'ArrowLeft' && (event.currentTarget.selectionStart ?? 0) === 0 && selectedValue.length > 0) {
|
|
1907
|
-
event.preventDefault();
|
|
1908
|
-
const lastChipIndex = Math.max(selectedValue.length - 1, 0);
|
|
1909
|
-
nextIndex = lastChipIndex;
|
|
1910
|
-
} else if (event.key === 'Backspace' && event.currentTarget.value === '' && selectedValue.length > 0) {
|
|
1911
|
-
store.state.setIndices({
|
|
1912
|
-
activeIndex: null,
|
|
1913
|
-
selectedIndex: null,
|
|
1914
|
-
type: 'keyboard'
|
|
1915
|
-
});
|
|
1916
|
-
event.preventDefault();
|
|
1917
|
-
}
|
|
1918
|
-
return nextIndex;
|
|
1919
|
-
}
|
|
1920
|
-
const element = useRenderElement.useRenderElement('input', componentProps, {
|
|
1921
|
-
state,
|
|
1922
|
-
ref: [forwardedRef, store.state.inputRef, setInputElement],
|
|
1923
|
-
props: [inputProps, triggerProps, {
|
|
1924
|
-
type: 'text',
|
|
1925
|
-
value: componentProps.value ?? composingValue ?? inputValue,
|
|
1926
|
-
'aria-readonly': readOnly || undefined,
|
|
1927
|
-
'aria-required': required || undefined,
|
|
1928
|
-
'aria-labelledby': ariaLabelledBy,
|
|
1929
|
-
disabled,
|
|
1930
|
-
readOnly,
|
|
1931
|
-
required: selectionMode === 'none' ? required : undefined,
|
|
1932
|
-
...(selectionMode === 'none' && name && {
|
|
1933
|
-
name
|
|
1934
|
-
}),
|
|
1935
|
-
id,
|
|
1936
|
-
onFocus() {
|
|
1937
|
-
setFocused(true);
|
|
1938
|
-
if (!inline || !shouldRestoreActiveIndexRef.current) {
|
|
1939
|
-
return;
|
|
1940
|
-
}
|
|
1941
|
-
shouldRestoreActiveIndexRef.current = false;
|
|
1942
|
-
const nextActiveIndex = lastActiveIndexRef.current;
|
|
1943
|
-
if (nextActiveIndex == null ||
|
|
1944
|
-
// `valuesRef` can be sparse, so guard against restoring a removed slot.
|
|
1945
|
-
!Object.hasOwn(store.state.valuesRef.current, nextActiveIndex)) {
|
|
1946
|
-
return;
|
|
1947
|
-
}
|
|
1948
|
-
store.state.setIndices({
|
|
1949
|
-
activeIndex: nextActiveIndex
|
|
1950
|
-
});
|
|
1951
|
-
},
|
|
1952
|
-
onBlur() {
|
|
1953
|
-
setTouched(true);
|
|
1954
|
-
setFocused(false);
|
|
1955
|
-
const activeIndex = store.state.activeIndex;
|
|
1956
|
-
if (inline && activeIndex !== null && autoHighlightMode !== 'always') {
|
|
1957
|
-
lastActiveIndexRef.current = activeIndex;
|
|
1958
|
-
shouldRestoreActiveIndexRef.current = true;
|
|
1959
|
-
store.state.setIndices({
|
|
1960
|
-
activeIndex: null
|
|
1961
|
-
});
|
|
1962
|
-
}
|
|
1963
|
-
if (validationMode === 'onBlur') {
|
|
1964
|
-
const valueToValidate = selectionMode === 'none' ? inputValue : selectedValue;
|
|
1965
|
-
validation.commit(valueToValidate);
|
|
1966
|
-
}
|
|
1967
|
-
},
|
|
1968
|
-
onCompositionStart(event) {
|
|
1969
|
-
if (clamp.isAndroid) {
|
|
1970
|
-
return;
|
|
1971
|
-
}
|
|
1972
|
-
isComposingRef.current = true;
|
|
1973
|
-
setComposingValue(event.currentTarget.value);
|
|
1974
|
-
},
|
|
1975
|
-
onCompositionEnd(event) {
|
|
1976
|
-
isComposingRef.current = false;
|
|
1977
|
-
const next = event.currentTarget.value;
|
|
1978
|
-
setComposingValue(null);
|
|
1979
|
-
store.state.setInputValue(next, clamp.createChangeEventDetails(clamp.inputChange, event.nativeEvent));
|
|
1980
|
-
},
|
|
1981
|
-
onChange(event) {
|
|
1982
|
-
// Autofill may not provide `inputType` (Chrome) or may report
|
|
1983
|
-
// `insertReplacementText` (Firefox).
|
|
1984
|
-
const inputType = event.nativeEvent.inputType;
|
|
1985
|
-
const autofillLikeInput = !inputType || inputType === 'insertReplacementText';
|
|
1986
|
-
const shouldOpenOnInput = isComposingRef.current || !autofillLikeInput;
|
|
1987
|
-
|
|
1988
|
-
// During IME composition, avoid propagating controlled updates to prevent
|
|
1989
|
-
// filtering the options prematurely so `Empty` won't show incorrectly.
|
|
1990
|
-
// We can't rely on this check for Android due to how it handles composition
|
|
1991
|
-
// events with some keyboards (e.g. Samsung keyboard with predictive text on
|
|
1992
|
-
// treats all text as always-composing).
|
|
1993
|
-
// https://github.com/mui/base-ui/issues/2942
|
|
1994
|
-
if (isComposingRef.current) {
|
|
1995
|
-
const nextVal = event.currentTarget.value;
|
|
1996
|
-
setComposingValue(nextVal);
|
|
1997
|
-
if (nextVal === '' && !store.state.openOnInputClick && !store.state.inputInsidePopup) {
|
|
1998
|
-
store.state.setOpen(false, clamp.createChangeEventDetails(clamp.inputClear, event.nativeEvent));
|
|
1999
|
-
}
|
|
2000
|
-
const trimmed = nextVal.trim();
|
|
2001
|
-
const shouldMaintainHighlight = autoHighlightEnabled && trimmed !== '';
|
|
2002
|
-
if (!readOnly && !disabled && trimmed) {
|
|
2003
|
-
if (shouldOpenOnInput) {
|
|
2004
|
-
store.state.setOpen(true, clamp.createChangeEventDetails(clamp.inputChange, event.nativeEvent));
|
|
2005
|
-
if (!autoHighlightEnabled) {
|
|
2006
|
-
store.state.setIndices({
|
|
2007
|
-
activeIndex: null,
|
|
2008
|
-
selectedIndex: null,
|
|
2009
|
-
type: store.state.keyboardActiveRef.current ? 'keyboard' : 'pointer'
|
|
2010
|
-
});
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
}
|
|
2014
|
-
if (open && store.state.activeIndex !== null && !shouldMaintainHighlight) {
|
|
2015
|
-
store.state.setIndices({
|
|
2016
|
-
activeIndex: null,
|
|
2017
|
-
selectedIndex: null,
|
|
2018
|
-
type: store.state.keyboardActiveRef.current ? 'keyboard' : 'pointer'
|
|
2019
|
-
});
|
|
2020
|
-
}
|
|
2021
|
-
return;
|
|
2022
|
-
}
|
|
2023
|
-
store.state.setInputValue(event.currentTarget.value, clamp.createChangeEventDetails(clamp.inputChange, event.nativeEvent));
|
|
2024
|
-
const empty = event.currentTarget.value === '';
|
|
2025
|
-
const clearDetails = clamp.createChangeEventDetails(clamp.inputClear, event.nativeEvent);
|
|
2026
|
-
if (empty && !store.state.inputInsidePopup) {
|
|
2027
|
-
if (selectionMode === 'single') {
|
|
2028
|
-
store.state.setSelectedValue(null, clearDetails);
|
|
2029
|
-
}
|
|
2030
|
-
if (!store.state.openOnInputClick) {
|
|
2031
|
-
store.state.setOpen(false, clearDetails);
|
|
2032
|
-
}
|
|
2033
|
-
}
|
|
2034
|
-
const trimmed = event.currentTarget.value.trim();
|
|
2035
|
-
if (!readOnly && !disabled && trimmed) {
|
|
2036
|
-
if (shouldOpenOnInput) {
|
|
2037
|
-
store.state.setOpen(true, clamp.createChangeEventDetails(clamp.inputChange, event.nativeEvent));
|
|
2038
|
-
// When autoHighlight is enabled, keep the highlight (will be set to 0 in root).
|
|
2039
|
-
if (!autoHighlightEnabled) {
|
|
2040
|
-
store.state.setIndices({
|
|
2041
|
-
activeIndex: null,
|
|
2042
|
-
selectedIndex: null,
|
|
2043
|
-
type: store.state.keyboardActiveRef.current ? 'keyboard' : 'pointer'
|
|
2044
|
-
});
|
|
2045
|
-
}
|
|
2046
|
-
}
|
|
2047
|
-
}
|
|
2048
|
-
|
|
2049
|
-
// When the user types, ensure the list resets its highlight so that
|
|
2050
|
-
// virtual focus returns to the input (aria-activedescendant is
|
|
2051
|
-
// cleared).
|
|
2052
|
-
if (open && store.state.activeIndex !== null && !autoHighlightEnabled) {
|
|
2053
|
-
store.state.setIndices({
|
|
2054
|
-
activeIndex: null,
|
|
2055
|
-
selectedIndex: null,
|
|
2056
|
-
type: store.state.keyboardActiveRef.current ? 'keyboard' : 'pointer'
|
|
2057
|
-
});
|
|
2058
|
-
}
|
|
2059
|
-
},
|
|
2060
|
-
onKeyDown(event) {
|
|
2061
|
-
if (disabled || readOnly) {
|
|
2062
|
-
return;
|
|
2063
|
-
}
|
|
2064
|
-
if (event.ctrlKey || event.shiftKey || event.altKey || event.metaKey) {
|
|
2065
|
-
return;
|
|
2066
|
-
}
|
|
2067
|
-
store.state.keyboardActiveRef.current = true;
|
|
2068
|
-
const input = event.currentTarget;
|
|
2069
|
-
const scrollAmount = input.scrollWidth - input.clientWidth;
|
|
2070
|
-
const isRTL = direction === 'rtl';
|
|
2071
|
-
if (event.key === 'Home') {
|
|
2072
|
-
clamp.stopEvent(event);
|
|
2073
|
-
const cursor = clamp.isFirefox && isRTL ? input.value.length : 0;
|
|
2074
|
-
input.setSelectionRange(cursor, cursor);
|
|
2075
|
-
input.scrollLeft = 0;
|
|
2076
|
-
return;
|
|
2077
|
-
}
|
|
2078
|
-
if (event.key === 'End') {
|
|
2079
|
-
clamp.stopEvent(event);
|
|
2080
|
-
const cursor = clamp.isFirefox && isRTL ? 0 : input.value.length;
|
|
2081
|
-
input.setSelectionRange(cursor, cursor);
|
|
2082
|
-
input.scrollLeft = isRTL ? -scrollAmount : scrollAmount;
|
|
2083
|
-
return;
|
|
2084
|
-
}
|
|
2085
|
-
if (!mounted && event.key === 'Escape') {
|
|
2086
|
-
const isClear = selectionMode === 'multiple' && Array.isArray(selectedValue) ? selectedValue.length === 0 : selectedValue === null;
|
|
2087
|
-
const details = clamp.createChangeEventDetails(clamp.escapeKey, event.nativeEvent);
|
|
2088
|
-
const value = selectionMode === 'multiple' ? [] : null;
|
|
2089
|
-
store.state.setInputValue('', details);
|
|
2090
|
-
store.state.setSelectedValue(value, details);
|
|
2091
|
-
if (!isClear && !store.state.inline && !details.isPropagationAllowed) {
|
|
2092
|
-
event.stopPropagation();
|
|
2093
|
-
}
|
|
2094
|
-
return;
|
|
2095
|
-
}
|
|
2096
|
-
|
|
2097
|
-
// Handle deletion when no chip is highlighted and the input is empty.
|
|
2098
|
-
if (comboboxChipsContext && event.key === 'Backspace' && input.value === '' && comboboxChipsContext.highlightedChipIndex === undefined && Array.isArray(selectedValue) && selectedValue.length > 0) {
|
|
2099
|
-
const newValue = selectedValue.slice(0, -1);
|
|
2100
|
-
// If the removed item was also the active (highlighted) item, clear highlight
|
|
2101
|
-
store.state.setIndices({
|
|
2102
|
-
activeIndex: null,
|
|
2103
|
-
selectedIndex: null,
|
|
2104
|
-
type: store.state.keyboardActiveRef.current ? 'keyboard' : 'pointer'
|
|
2105
|
-
});
|
|
2106
|
-
store.state.setSelectedValue(newValue, clamp.createChangeEventDetails(clamp.none, event.nativeEvent));
|
|
2107
|
-
return;
|
|
2108
|
-
}
|
|
2109
|
-
const hadHighlightedChip = comboboxChipsContext?.highlightedChipIndex !== undefined;
|
|
2110
|
-
const nextIndex = handleKeyDown(event);
|
|
2111
|
-
comboboxChipsContext?.setHighlightedChipIndex(nextIndex);
|
|
2112
|
-
if (nextIndex !== undefined) {
|
|
2113
|
-
comboboxChipsContext?.chipsRef.current[nextIndex]?.focus();
|
|
2114
|
-
} else if (hadHighlightedChip) {
|
|
2115
|
-
store.state.inputRef.current?.focus();
|
|
2116
|
-
}
|
|
2117
|
-
|
|
2118
|
-
// event.isComposing
|
|
2119
|
-
if (event.which === 229) {
|
|
2120
|
-
return;
|
|
2121
|
-
}
|
|
2122
|
-
if (event.key === 'Enter' && open) {
|
|
2123
|
-
const activeIndex = store.state.activeIndex;
|
|
2124
|
-
const nativeEvent = event.nativeEvent;
|
|
2125
|
-
if (activeIndex === null) {
|
|
2126
|
-
if (inline) {
|
|
2127
|
-
return;
|
|
2128
|
-
}
|
|
2129
|
-
|
|
2130
|
-
// Allow form submission when no item is highlighted.
|
|
2131
|
-
store.state.setOpen(false, clamp.createChangeEventDetails(clamp.none, nativeEvent));
|
|
2132
|
-
return;
|
|
2133
|
-
}
|
|
2134
|
-
clamp.stopEvent(event);
|
|
2135
|
-
const listItem = store.state.listRef.current[activeIndex];
|
|
2136
|
-
if (listItem) {
|
|
2137
|
-
store.state.selectionEventRef.current = nativeEvent;
|
|
2138
|
-
listItem.click();
|
|
2139
|
-
store.state.selectionEventRef.current = null;
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
},
|
|
2143
|
-
onPointerMove() {
|
|
2144
|
-
store.state.keyboardActiveRef.current = false;
|
|
2145
|
-
},
|
|
2146
|
-
onPointerDown() {
|
|
2147
|
-
store.state.keyboardActiveRef.current = false;
|
|
2148
|
-
}
|
|
2149
|
-
}, validationProps],
|
|
2150
|
-
stateAttributesMapping: triggerStateAttributesMapping
|
|
2151
|
-
});
|
|
2152
|
-
return /*#__PURE__*/jsxRuntime.jsxs(React__namespace.Fragment, {
|
|
2153
|
-
children: [open && focusManagerModal && /*#__PURE__*/jsxRuntime.jsx(ComboboxInternalDismissButton, {
|
|
2154
|
-
ref: store.state.startDismissRef
|
|
2155
|
-
}), element]
|
|
2156
|
-
});
|
|
2157
|
-
});
|
|
2158
|
-
if (process.env.NODE_ENV !== "production") ComboboxInput.displayName = "ComboboxInput";
|
|
2159
|
-
|
|
2160
|
-
/**
|
|
2161
|
-
* A wrapper for the input and its associated controls.
|
|
2162
|
-
* Renders a `<div>` element.
|
|
2163
|
-
*/
|
|
2164
|
-
const ComboboxInputGroup = /*#__PURE__*/React__namespace.forwardRef(function ComboboxInputGroup(componentProps, forwardedRef) {
|
|
2165
|
-
const {
|
|
2166
|
-
render,
|
|
2167
|
-
className,
|
|
2168
|
-
...elementProps
|
|
2169
|
-
} = componentProps;
|
|
2170
|
-
const {
|
|
2171
|
-
state: fieldState,
|
|
2172
|
-
disabled: fieldDisabled
|
|
2173
|
-
} = NumberFieldInput.useFieldRootContext();
|
|
2174
|
-
const store = useComboboxRootContext();
|
|
2175
|
-
const {
|
|
2176
|
-
filteredItems
|
|
2177
|
-
} = useComboboxDerivedItemsContext();
|
|
2178
|
-
const open = ScrollAreaViewport.useStore(store, selectors.open);
|
|
2179
|
-
const mounted = ScrollAreaViewport.useStore(store, selectors.mounted);
|
|
2180
|
-
const popupSideValue = ScrollAreaViewport.useStore(store, selectors.popupSide);
|
|
2181
|
-
const positionerElement = ScrollAreaViewport.useStore(store, selectors.positionerElement);
|
|
2182
|
-
const comboboxDisabled = ScrollAreaViewport.useStore(store, selectors.disabled);
|
|
2183
|
-
const readOnly = ScrollAreaViewport.useStore(store, selectors.readOnly);
|
|
2184
|
-
const hasSelectedValue = ScrollAreaViewport.useStore(store, selectors.hasSelectedValue);
|
|
2185
|
-
const selectionMode = ScrollAreaViewport.useStore(store, selectors.selectionMode);
|
|
2186
|
-
const popupSide = mounted && positionerElement ? popupSideValue : null;
|
|
2187
|
-
const disabled = fieldDisabled || comboboxDisabled;
|
|
2188
|
-
const listEmpty = filteredItems.length === 0;
|
|
2189
|
-
const placeholder = selectionMode === 'none' ? false : !hasSelectedValue;
|
|
2190
|
-
const state = {
|
|
2191
|
-
...fieldState,
|
|
2192
|
-
open,
|
|
2193
|
-
disabled,
|
|
2194
|
-
readOnly,
|
|
2195
|
-
popupSide,
|
|
2196
|
-
listEmpty,
|
|
2197
|
-
placeholder
|
|
2198
|
-
};
|
|
2199
|
-
const setInputGroupElement = clamp.useStableCallback(element => {
|
|
2200
|
-
store.set('inputGroupElement', element);
|
|
2201
|
-
});
|
|
2202
|
-
return useRenderElement.useRenderElement('div', componentProps, {
|
|
2203
|
-
ref: [forwardedRef, setInputGroupElement],
|
|
2204
|
-
props: [{
|
|
2205
|
-
role: 'group'
|
|
2206
|
-
}, elementProps],
|
|
2207
|
-
state,
|
|
2208
|
-
stateAttributesMapping: triggerStateAttributesMapping
|
|
2209
|
-
});
|
|
2210
|
-
});
|
|
2211
|
-
if (process.env.NODE_ENV !== "production") ComboboxInputGroup.displayName = "ComboboxInputGroup";
|
|
2212
|
-
|
|
2213
|
-
/**
|
|
2214
|
-
* An icon that indicates that the trigger button opens the popup.
|
|
2215
|
-
* Renders a `<span>` element.
|
|
2216
|
-
*/
|
|
2217
|
-
const ComboboxIcon = /*#__PURE__*/React__namespace.forwardRef(function ComboboxIcon(componentProps, forwardedRef) {
|
|
2218
|
-
const {
|
|
2219
|
-
className,
|
|
2220
|
-
render,
|
|
2221
|
-
...elementProps
|
|
2222
|
-
} = componentProps;
|
|
2223
|
-
const element = useRenderElement.useRenderElement('span', componentProps, {
|
|
2224
|
-
ref: forwardedRef,
|
|
2225
|
-
props: [{
|
|
2226
|
-
'aria-hidden': true,
|
|
2227
|
-
children: '▼'
|
|
2228
|
-
}, elementProps]
|
|
2229
|
-
});
|
|
2230
|
-
return element;
|
|
2231
|
-
});
|
|
2232
|
-
if (process.env.NODE_ENV !== "production") ComboboxIcon.displayName = "ComboboxIcon";
|
|
2233
|
-
|
|
2234
|
-
const stateAttributesMapping$8 = {
|
|
2235
|
-
...clamp.transitionStatusMapping,
|
|
2236
|
-
...ScrollAreaViewport.triggerOpenStateMapping
|
|
2237
|
-
};
|
|
2238
|
-
|
|
2239
|
-
/**
|
|
2240
|
-
* Clears the value when clicked.
|
|
2241
|
-
* Renders a `<button>` element.
|
|
2242
|
-
*/
|
|
2243
|
-
const ComboboxClear = /*#__PURE__*/React__namespace.forwardRef(function ComboboxClear(componentProps, forwardedRef) {
|
|
2244
|
-
const {
|
|
2245
|
-
render,
|
|
2246
|
-
className,
|
|
2247
|
-
disabled: disabledProp = false,
|
|
2248
|
-
nativeButton = true,
|
|
2249
|
-
keepMounted = false,
|
|
2250
|
-
...elementProps
|
|
2251
|
-
} = componentProps;
|
|
2252
|
-
const {
|
|
2253
|
-
disabled: fieldDisabled
|
|
2254
|
-
} = NumberFieldInput.useFieldRootContext();
|
|
2255
|
-
const store = useComboboxRootContext();
|
|
2256
|
-
const selectionMode = ScrollAreaViewport.useStore(store, selectors.selectionMode);
|
|
2257
|
-
const comboboxDisabled = ScrollAreaViewport.useStore(store, selectors.disabled);
|
|
2258
|
-
const readOnly = ScrollAreaViewport.useStore(store, selectors.readOnly);
|
|
2259
|
-
const open = ScrollAreaViewport.useStore(store, selectors.open);
|
|
2260
|
-
const selectedValue = ScrollAreaViewport.useStore(store, selectors.selectedValue);
|
|
2261
|
-
const hasSelectionChips = ScrollAreaViewport.useStore(store, selectors.hasSelectionChips);
|
|
2262
|
-
const inputValue = useComboboxInputValueContext();
|
|
2263
|
-
let visible = false;
|
|
2264
|
-
if (selectionMode === 'none') {
|
|
2265
|
-
visible = inputValue !== '';
|
|
2266
|
-
} else if (selectionMode === 'single') {
|
|
2267
|
-
visible = selectedValue != null;
|
|
2268
|
-
} else {
|
|
2269
|
-
visible = hasSelectionChips;
|
|
2270
|
-
}
|
|
2271
|
-
const disabled = fieldDisabled || comboboxDisabled || disabledProp;
|
|
2272
|
-
const {
|
|
2273
|
-
buttonRef,
|
|
2274
|
-
getButtonProps
|
|
2275
|
-
} = clamp.useButton({
|
|
2276
|
-
native: nativeButton,
|
|
2277
|
-
disabled
|
|
2278
|
-
});
|
|
2279
|
-
const {
|
|
2280
|
-
mounted,
|
|
2281
|
-
transitionStatus,
|
|
2282
|
-
setMounted
|
|
2283
|
-
} = clamp.useTransitionStatus(visible);
|
|
2284
|
-
const state = {
|
|
2285
|
-
disabled,
|
|
2286
|
-
open,
|
|
2287
|
-
transitionStatus
|
|
2288
|
-
};
|
|
2289
|
-
clamp.useOpenChangeComplete({
|
|
2290
|
-
open: visible,
|
|
2291
|
-
ref: store.state.clearRef,
|
|
2292
|
-
onComplete() {
|
|
2293
|
-
if (!visible) {
|
|
2294
|
-
setMounted(false);
|
|
2295
|
-
}
|
|
2296
|
-
}
|
|
2297
|
-
});
|
|
2298
|
-
const element = useRenderElement.useRenderElement('button', componentProps, {
|
|
2299
|
-
state,
|
|
2300
|
-
ref: [forwardedRef, buttonRef, store.state.clearRef],
|
|
2301
|
-
props: [{
|
|
2302
|
-
tabIndex: -1,
|
|
2303
|
-
children: 'x',
|
|
2304
|
-
// Avoid stealing focus from the input.
|
|
2305
|
-
onMouseDown(event) {
|
|
2306
|
-
event.preventDefault();
|
|
2307
|
-
},
|
|
2308
|
-
onClick(event) {
|
|
2309
|
-
if (disabled || readOnly) {
|
|
2310
|
-
return;
|
|
2311
|
-
}
|
|
2312
|
-
const keyboardActiveRef = store.state.keyboardActiveRef;
|
|
2313
|
-
store.state.setInputValue('', clamp.createChangeEventDetails(clamp.clearPress, event.nativeEvent));
|
|
2314
|
-
if (selectionMode !== 'none') {
|
|
2315
|
-
store.state.setSelectedValue(Array.isArray(selectedValue) ? [] : null, clamp.createChangeEventDetails(clamp.clearPress, event.nativeEvent));
|
|
2316
|
-
store.state.setIndices({
|
|
2317
|
-
activeIndex: null,
|
|
2318
|
-
selectedIndex: null,
|
|
2319
|
-
type: keyboardActiveRef.current ? 'keyboard' : 'pointer'
|
|
2320
|
-
});
|
|
2321
|
-
} else {
|
|
2322
|
-
store.state.setIndices({
|
|
2323
|
-
activeIndex: null,
|
|
2324
|
-
type: keyboardActiveRef.current ? 'keyboard' : 'pointer'
|
|
2325
|
-
});
|
|
2326
|
-
}
|
|
2327
|
-
store.state.inputRef.current?.focus();
|
|
2328
|
-
}
|
|
2329
|
-
}, elementProps, getButtonProps],
|
|
2330
|
-
stateAttributesMapping: stateAttributesMapping$8
|
|
2331
|
-
});
|
|
2332
|
-
const shouldRender = keepMounted || mounted;
|
|
2333
|
-
if (!shouldRender) {
|
|
2334
|
-
return null;
|
|
2335
|
-
}
|
|
2336
|
-
return element;
|
|
2337
|
-
});
|
|
2338
|
-
if (process.env.NODE_ENV !== "production") ComboboxClear.displayName = "ComboboxClear";
|
|
2339
|
-
|
|
2340
|
-
const GroupCollectionContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
2341
|
-
if (process.env.NODE_ENV !== "production") GroupCollectionContext.displayName = "GroupCollectionContext";
|
|
2342
|
-
function useGroupCollectionContext() {
|
|
2343
|
-
return React__namespace.useContext(GroupCollectionContext);
|
|
2344
|
-
}
|
|
2345
|
-
function GroupCollectionProvider(props) {
|
|
2346
|
-
const {
|
|
2347
|
-
children,
|
|
2348
|
-
items
|
|
2349
|
-
} = props;
|
|
2350
|
-
const contextValue = React__namespace.useMemo(() => ({
|
|
2351
|
-
items
|
|
2352
|
-
}), [items]);
|
|
2353
|
-
return /*#__PURE__*/jsxRuntime.jsx(GroupCollectionContext.Provider, {
|
|
2354
|
-
value: contextValue,
|
|
2355
|
-
children: children
|
|
2356
|
-
});
|
|
2357
|
-
}
|
|
2358
|
-
|
|
2359
|
-
function ComboboxCollection(props) {
|
|
2360
|
-
const {
|
|
2361
|
-
children
|
|
2362
|
-
} = props;
|
|
2363
|
-
const {
|
|
2364
|
-
filteredItems
|
|
2365
|
-
} = useComboboxDerivedItemsContext();
|
|
2366
|
-
const groupContext = useGroupCollectionContext();
|
|
2367
|
-
const itemsToRender = groupContext ? groupContext.items : filteredItems;
|
|
2368
|
-
if (!itemsToRender) {
|
|
2369
|
-
return null;
|
|
2370
|
-
}
|
|
2371
|
-
return /*#__PURE__*/jsxRuntime.jsx(React__namespace.Fragment, {
|
|
2372
|
-
children: itemsToRender.map(children)
|
|
2373
|
-
});
|
|
2374
|
-
}
|
|
2375
|
-
|
|
2376
|
-
const ComboboxList = /*#__PURE__*/React__namespace.forwardRef(function ComboboxList(componentProps, forwardedRef) {
|
|
2377
|
-
var _ComboboxCollection;
|
|
2378
|
-
const {
|
|
2379
|
-
render,
|
|
2380
|
-
className,
|
|
2381
|
-
children,
|
|
2382
|
-
...elementProps
|
|
2383
|
-
} = componentProps;
|
|
2384
|
-
const store = useComboboxRootContext();
|
|
2385
|
-
const floatingRootContext = useComboboxFloatingContext();
|
|
2386
|
-
const hasPositionerContext = Boolean(useComboboxPositionerContext(true));
|
|
2387
|
-
const {
|
|
2388
|
-
filteredItems
|
|
2389
|
-
} = useComboboxDerivedItemsContext();
|
|
2390
|
-
const items = ScrollAreaViewport.useStore(store, selectors.items);
|
|
2391
|
-
const labelsRef = ScrollAreaViewport.useStore(store, selectors.labelsRef);
|
|
2392
|
-
const listRef = ScrollAreaViewport.useStore(store, selectors.listRef);
|
|
2393
|
-
const selectionMode = ScrollAreaViewport.useStore(store, selectors.selectionMode);
|
|
2394
|
-
const grid = ScrollAreaViewport.useStore(store, selectors.grid);
|
|
2395
|
-
const popupProps = ScrollAreaViewport.useStore(store, selectors.popupProps);
|
|
2396
|
-
const disabled = ScrollAreaViewport.useStore(store, selectors.disabled);
|
|
2397
|
-
const readOnly = ScrollAreaViewport.useStore(store, selectors.readOnly);
|
|
2398
|
-
const virtualized = ScrollAreaViewport.useStore(store, selectors.virtualized);
|
|
2399
|
-
const multiple = selectionMode === 'multiple';
|
|
2400
|
-
const empty = filteredItems.length === 0;
|
|
2401
|
-
const setPositionerElement = clamp.useStableCallback(element => {
|
|
2402
|
-
store.set('positionerElement', element);
|
|
2403
|
-
});
|
|
2404
|
-
const setListElement = clamp.useStableCallback(element => {
|
|
2405
|
-
store.set('listElement', element);
|
|
2406
|
-
});
|
|
2407
|
-
|
|
2408
|
-
// Support "closed template" API: if children is a function, implicitly wrap it
|
|
2409
|
-
// with a Combobox.Collection that reads items from context/root.
|
|
2410
|
-
// Ensures this component's `popupProps` subscription does not cause <Combobox.Item>
|
|
2411
|
-
// to re-render on every active index change.
|
|
2412
|
-
const resolvedChildren = React__namespace.useMemo(() => {
|
|
2413
|
-
if (typeof children === 'function') {
|
|
2414
|
-
return _ComboboxCollection || (_ComboboxCollection = /*#__PURE__*/jsxRuntime.jsx(ComboboxCollection, {
|
|
2415
|
-
children: children
|
|
2416
|
-
}));
|
|
2417
|
-
}
|
|
2418
|
-
return children;
|
|
2419
|
-
}, [children]);
|
|
2420
|
-
const state = {
|
|
2421
|
-
empty
|
|
2422
|
-
};
|
|
2423
|
-
const floatingId = floatingRootContext.useState('floatingId');
|
|
2424
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2425
|
-
state,
|
|
2426
|
-
ref: [forwardedRef, setListElement, hasPositionerContext ? null : setPositionerElement],
|
|
2427
|
-
props: [popupProps, {
|
|
2428
|
-
children: resolvedChildren,
|
|
2429
|
-
tabIndex: -1,
|
|
2430
|
-
id: floatingId,
|
|
2431
|
-
role: grid ? 'grid' : 'listbox',
|
|
2432
|
-
'aria-multiselectable': multiple ? 'true' : undefined,
|
|
2433
|
-
onKeyDown(event) {
|
|
2434
|
-
if (disabled || readOnly) {
|
|
2435
|
-
return;
|
|
2436
|
-
}
|
|
2437
|
-
if (event.key === 'Enter') {
|
|
2438
|
-
const activeIndex = store.state.activeIndex;
|
|
2439
|
-
if (activeIndex == null) {
|
|
2440
|
-
// Allow form submission when no item is highlighted.
|
|
2441
|
-
return;
|
|
2442
|
-
}
|
|
2443
|
-
clamp.stopEvent(event);
|
|
2444
|
-
const nativeEvent = event.nativeEvent;
|
|
2445
|
-
const listItem = store.state.listRef.current[activeIndex];
|
|
2446
|
-
if (listItem) {
|
|
2447
|
-
store.state.selectionEventRef.current = nativeEvent;
|
|
2448
|
-
listItem.click();
|
|
2449
|
-
store.state.selectionEventRef.current = null;
|
|
2450
|
-
}
|
|
2451
|
-
}
|
|
2452
|
-
},
|
|
2453
|
-
onKeyDownCapture() {
|
|
2454
|
-
store.state.keyboardActiveRef.current = true;
|
|
2455
|
-
},
|
|
2456
|
-
onPointerMoveCapture() {
|
|
2457
|
-
store.state.keyboardActiveRef.current = false;
|
|
2458
|
-
}
|
|
2459
|
-
}, elementProps]
|
|
2460
|
-
});
|
|
2461
|
-
if (virtualized) {
|
|
2462
|
-
return element;
|
|
2463
|
-
}
|
|
2464
|
-
return /*#__PURE__*/jsxRuntime.jsx(MenuSubmenuTrigger.CompositeList, {
|
|
2465
|
-
elementsRef: listRef,
|
|
2466
|
-
labelsRef: items ? undefined : labelsRef,
|
|
2467
|
-
children: element
|
|
2468
|
-
});
|
|
2469
|
-
});
|
|
2470
|
-
if (process.env.NODE_ENV !== "production") ComboboxList.displayName = "ComboboxList";
|
|
2471
|
-
|
|
2472
|
-
/**
|
|
2473
|
-
* Displays a status message whose content changes are announced politely to screen readers.
|
|
2474
|
-
* Useful for conveying the status of an asynchronously loaded list.
|
|
2475
|
-
* Renders a `<div>` element.
|
|
2476
|
-
*/
|
|
2477
|
-
const ComboboxStatus = /*#__PURE__*/React__namespace.forwardRef(function ComboboxStatus(componentProps, forwardedRef) {
|
|
2478
|
-
const {
|
|
2479
|
-
render,
|
|
2480
|
-
className,
|
|
2481
|
-
...elementProps
|
|
2482
|
-
} = componentProps;
|
|
2483
|
-
return useRenderElement.useRenderElement('div', componentProps, {
|
|
2484
|
-
ref: forwardedRef,
|
|
2485
|
-
props: [{
|
|
2486
|
-
role: 'status',
|
|
2487
|
-
'aria-live': 'polite',
|
|
2488
|
-
'aria-atomic': true
|
|
2489
|
-
}, elementProps]
|
|
2490
|
-
});
|
|
2491
|
-
});
|
|
2492
|
-
if (process.env.NODE_ENV !== "production") ComboboxStatus.displayName = "ComboboxStatus";
|
|
2493
|
-
|
|
2494
|
-
const ComboboxPortalContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2495
|
-
if (process.env.NODE_ENV !== "production") ComboboxPortalContext.displayName = "ComboboxPortalContext";
|
|
2496
|
-
function useComboboxPortalContext() {
|
|
2497
|
-
const context = React__namespace.useContext(ComboboxPortalContext);
|
|
2498
|
-
if (context === undefined) {
|
|
2499
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Combobox.Portal> is missing.' : useRenderElement.formatErrorMessage(20));
|
|
2500
|
-
}
|
|
2501
|
-
return context;
|
|
2502
|
-
}
|
|
2503
|
-
|
|
2504
|
-
const ComboboxPortal = /*#__PURE__*/React__namespace.forwardRef(function ComboboxPortal(props, forwardedRef) {
|
|
2505
|
-
const {
|
|
2506
|
-
keepMounted = false,
|
|
2507
|
-
...portalProps
|
|
2508
|
-
} = props;
|
|
2509
|
-
const store = useComboboxRootContext();
|
|
2510
|
-
const mounted = ScrollAreaViewport.useStore(store, selectors.mounted);
|
|
2511
|
-
const forceMounted = ScrollAreaViewport.useStore(store, selectors.forceMounted);
|
|
2512
|
-
const shouldRender = mounted || keepMounted || forceMounted;
|
|
2513
|
-
if (!shouldRender) {
|
|
2514
|
-
return null;
|
|
2515
|
-
}
|
|
2516
|
-
return /*#__PURE__*/jsxRuntime.jsx(ComboboxPortalContext.Provider, {
|
|
2517
|
-
value: keepMounted,
|
|
2518
|
-
children: /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingPortal, {
|
|
2519
|
-
ref: forwardedRef,
|
|
2520
|
-
...portalProps
|
|
2521
|
-
})
|
|
2522
|
-
});
|
|
2523
|
-
});
|
|
2524
|
-
if (process.env.NODE_ENV !== "production") ComboboxPortal.displayName = "ComboboxPortal";
|
|
2525
|
-
|
|
2526
|
-
const stateAttributesMapping$7 = {
|
|
2527
|
-
...ScrollAreaViewport.popupStateMapping,
|
|
2528
|
-
...clamp.transitionStatusMapping
|
|
2529
|
-
};
|
|
2530
|
-
|
|
2531
|
-
/**
|
|
2532
|
-
* An overlay displayed beneath the popup.
|
|
2533
|
-
* Renders a `<div>` element.
|
|
2534
|
-
*/
|
|
2535
|
-
const ComboboxBackdrop = /*#__PURE__*/React__namespace.forwardRef(function ComboboxBackdrop(componentProps, forwardedRef) {
|
|
2536
|
-
const {
|
|
2537
|
-
className,
|
|
2538
|
-
render,
|
|
2539
|
-
...elementProps
|
|
2540
|
-
} = componentProps;
|
|
2541
|
-
const store = useComboboxRootContext();
|
|
2542
|
-
const open = ScrollAreaViewport.useStore(store, selectors.open);
|
|
2543
|
-
const mounted = ScrollAreaViewport.useStore(store, selectors.mounted);
|
|
2544
|
-
const transitionStatus = ScrollAreaViewport.useStore(store, selectors.transitionStatus);
|
|
2545
|
-
const state = {
|
|
2546
|
-
open,
|
|
2547
|
-
transitionStatus
|
|
2548
|
-
};
|
|
2549
|
-
return useRenderElement.useRenderElement('div', componentProps, {
|
|
2550
|
-
state,
|
|
2551
|
-
ref: forwardedRef,
|
|
2552
|
-
stateAttributesMapping: stateAttributesMapping$7,
|
|
2553
|
-
props: [{
|
|
2554
|
-
role: 'presentation',
|
|
2555
|
-
hidden: !mounted,
|
|
2556
|
-
style: {
|
|
2557
|
-
userSelect: 'none',
|
|
2558
|
-
WebkitUserSelect: 'none'
|
|
2559
|
-
}
|
|
2560
|
-
}, elementProps]
|
|
2561
|
-
});
|
|
2562
|
-
});
|
|
2563
|
-
if (process.env.NODE_ENV !== "production") ComboboxBackdrop.displayName = "ComboboxBackdrop";
|
|
2564
|
-
|
|
2565
|
-
const ComboboxPositioner = /*#__PURE__*/React__namespace.forwardRef(function ComboboxPositioner(componentProps, forwardedRef) {
|
|
2566
|
-
const {
|
|
2567
|
-
render,
|
|
2568
|
-
className,
|
|
2569
|
-
anchor,
|
|
2570
|
-
positionMethod = 'absolute',
|
|
2571
|
-
side = 'bottom',
|
|
2572
|
-
align = 'center',
|
|
2573
|
-
sideOffset = 0,
|
|
2574
|
-
alignOffset = 0,
|
|
2575
|
-
collisionBoundary = 'clipping-ancestors',
|
|
2576
|
-
collisionPadding = 5,
|
|
2577
|
-
arrowPadding = 5,
|
|
2578
|
-
sticky = false,
|
|
2579
|
-
disableAnchorTracking = false,
|
|
2580
|
-
collisionAvoidance = ScrollAreaViewport.DROPDOWN_COLLISION_AVOIDANCE,
|
|
2581
|
-
...elementProps
|
|
2582
|
-
} = componentProps;
|
|
2583
|
-
const store = useComboboxRootContext();
|
|
2584
|
-
const {
|
|
2585
|
-
filteredItems
|
|
2586
|
-
} = useComboboxDerivedItemsContext();
|
|
2587
|
-
const floatingRootContext = useComboboxFloatingContext();
|
|
2588
|
-
const keepMounted = useComboboxPortalContext();
|
|
2589
|
-
const modal = ScrollAreaViewport.useStore(store, selectors.modal);
|
|
2590
|
-
const open = ScrollAreaViewport.useStore(store, selectors.open);
|
|
2591
|
-
const mounted = ScrollAreaViewport.useStore(store, selectors.mounted);
|
|
2592
|
-
const openMethod = ScrollAreaViewport.useStore(store, selectors.openMethod);
|
|
2593
|
-
const triggerElement = ScrollAreaViewport.useStore(store, selectors.triggerElement);
|
|
2594
|
-
const inputElement = ScrollAreaViewport.useStore(store, selectors.inputElement);
|
|
2595
|
-
const inputGroupElement = ScrollAreaViewport.useStore(store, selectors.inputGroupElement);
|
|
2596
|
-
const inputInsidePopup = ScrollAreaViewport.useStore(store, selectors.inputInsidePopup);
|
|
2597
|
-
const transitionStatus = ScrollAreaViewport.useStore(store, selectors.transitionStatus);
|
|
2598
|
-
const empty = filteredItems.length === 0;
|
|
2599
|
-
const resolvedAnchor = anchor ?? (inputInsidePopup ? triggerElement : inputGroupElement ?? inputElement);
|
|
2600
|
-
const positioning = MenuSubmenuTrigger.useAnchorPositioning({
|
|
2601
|
-
anchor: resolvedAnchor,
|
|
2602
|
-
floatingRootContext,
|
|
2603
|
-
positionMethod,
|
|
2604
|
-
mounted,
|
|
2605
|
-
side,
|
|
2606
|
-
sideOffset,
|
|
2607
|
-
align,
|
|
2608
|
-
alignOffset,
|
|
2609
|
-
arrowPadding,
|
|
2610
|
-
collisionBoundary,
|
|
2611
|
-
collisionPadding,
|
|
2612
|
-
sticky,
|
|
2613
|
-
disableAnchorTracking,
|
|
2614
|
-
keepMounted,
|
|
2615
|
-
collisionAvoidance,
|
|
2616
|
-
lazyFlip: true
|
|
2617
|
-
});
|
|
2618
|
-
ScrollAreaViewport.useScrollLock(open && modal && openMethod !== 'touch', triggerElement);
|
|
2619
|
-
const defaultProps = React__namespace.useMemo(() => {
|
|
2620
|
-
const style = {
|
|
2621
|
-
...positioning.positionerStyles
|
|
2622
|
-
};
|
|
2623
|
-
if (!open) {
|
|
2624
|
-
style.pointerEvents = 'none';
|
|
2625
|
-
}
|
|
2626
|
-
return {
|
|
2627
|
-
role: 'presentation',
|
|
2628
|
-
hidden: !mounted,
|
|
2629
|
-
style
|
|
2630
|
-
};
|
|
2631
|
-
}, [open, mounted, positioning.positionerStyles]);
|
|
2632
|
-
const state = {
|
|
2633
|
-
open,
|
|
2634
|
-
side: positioning.side,
|
|
2635
|
-
align: positioning.align,
|
|
2636
|
-
anchorHidden: positioning.anchorHidden,
|
|
2637
|
-
empty
|
|
2638
|
-
};
|
|
2639
|
-
clamp.useIsoLayoutEffect(() => {
|
|
2640
|
-
store.set('popupSide', positioning.side);
|
|
2641
|
-
}, [store, positioning.side]);
|
|
2642
|
-
const contextValue = React__namespace.useMemo(() => ({
|
|
2643
|
-
side: positioning.side,
|
|
2644
|
-
align: positioning.align,
|
|
2645
|
-
arrowRef: positioning.arrowRef,
|
|
2646
|
-
arrowUncentered: positioning.arrowUncentered,
|
|
2647
|
-
arrowStyles: positioning.arrowStyles,
|
|
2648
|
-
anchorHidden: positioning.anchorHidden,
|
|
2649
|
-
isPositioned: positioning.isPositioned
|
|
2650
|
-
}), [positioning.side, positioning.align, positioning.arrowRef, positioning.arrowUncentered, positioning.arrowStyles, positioning.anchorHidden, positioning.isPositioned]);
|
|
2651
|
-
const setPositionerElement = clamp.useStableCallback(element => {
|
|
2652
|
-
store.set('positionerElement', element);
|
|
2653
|
-
});
|
|
2654
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2655
|
-
state,
|
|
2656
|
-
ref: [forwardedRef, setPositionerElement],
|
|
2657
|
-
props: [defaultProps, MenuSubmenuTrigger.getDisabledMountTransitionStyles(transitionStatus), elementProps],
|
|
2658
|
-
stateAttributesMapping: ScrollAreaViewport.popupStateMapping
|
|
2659
|
-
});
|
|
2660
|
-
return /*#__PURE__*/jsxRuntime.jsxs(ComboboxPositionerContext.Provider, {
|
|
2661
|
-
value: contextValue,
|
|
2662
|
-
children: [mounted && modal && /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.InternalBackdrop, {
|
|
2663
|
-
inert: ScrollAreaViewport.inertValue(!open),
|
|
2664
|
-
cutout: inputGroupElement ?? inputElement ?? triggerElement
|
|
2665
|
-
}), element]
|
|
2666
|
-
});
|
|
2667
|
-
});
|
|
2668
|
-
if (process.env.NODE_ENV !== "production") ComboboxPositioner.displayName = "ComboboxPositioner";
|
|
2669
|
-
|
|
2670
|
-
const stateAttributesMapping$6 = {
|
|
2671
|
-
...ScrollAreaViewport.popupStateMapping,
|
|
2672
|
-
...clamp.transitionStatusMapping
|
|
2673
|
-
};
|
|
2674
|
-
|
|
2675
|
-
/**
|
|
2676
|
-
* A container for the list.
|
|
2677
|
-
* Renders a `<div>` element.
|
|
2678
|
-
*/
|
|
2679
|
-
const ComboboxPopup = /*#__PURE__*/React__namespace.forwardRef(function ComboboxPopup(componentProps, forwardedRef) {
|
|
2680
|
-
const {
|
|
2681
|
-
render,
|
|
2682
|
-
className,
|
|
2683
|
-
initialFocus,
|
|
2684
|
-
finalFocus,
|
|
2685
|
-
...elementProps
|
|
2686
|
-
} = componentProps;
|
|
2687
|
-
const store = useComboboxRootContext();
|
|
2688
|
-
const positioning = useComboboxPositionerContext();
|
|
2689
|
-
const floatingRootContext = useComboboxFloatingContext();
|
|
2690
|
-
const {
|
|
2691
|
-
filteredItems
|
|
2692
|
-
} = useComboboxDerivedItemsContext();
|
|
2693
|
-
const mounted = ScrollAreaViewport.useStore(store, selectors.mounted);
|
|
2694
|
-
const open = ScrollAreaViewport.useStore(store, selectors.open);
|
|
2695
|
-
const openMethod = ScrollAreaViewport.useStore(store, selectors.openMethod);
|
|
2696
|
-
const transitionStatus = ScrollAreaViewport.useStore(store, selectors.transitionStatus);
|
|
2697
|
-
const inputInsidePopup = ScrollAreaViewport.useStore(store, selectors.inputInsidePopup);
|
|
2698
|
-
const inputElement = ScrollAreaViewport.useStore(store, selectors.inputElement);
|
|
2699
|
-
const modal = ScrollAreaViewport.useStore(store, selectors.modal);
|
|
2700
|
-
const empty = filteredItems.length === 0;
|
|
2701
|
-
clamp.useOpenChangeComplete({
|
|
2702
|
-
open,
|
|
2703
|
-
ref: store.state.popupRef,
|
|
2704
|
-
onComplete() {
|
|
2705
|
-
if (open) {
|
|
2706
|
-
store.state.onOpenChangeComplete(true);
|
|
2707
|
-
}
|
|
2708
|
-
}
|
|
2709
|
-
});
|
|
2710
|
-
const state = {
|
|
2711
|
-
open,
|
|
2712
|
-
side: positioning.side,
|
|
2713
|
-
align: positioning.align,
|
|
2714
|
-
anchorHidden: positioning.anchorHidden,
|
|
2715
|
-
transitionStatus,
|
|
2716
|
-
empty
|
|
2717
|
-
};
|
|
2718
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2719
|
-
state,
|
|
2720
|
-
ref: [forwardedRef, store.state.popupRef],
|
|
2721
|
-
props: [{
|
|
2722
|
-
role: inputInsidePopup ? 'dialog' : 'presentation',
|
|
2723
|
-
tabIndex: -1,
|
|
2724
|
-
onFocus(event) {
|
|
2725
|
-
const target = clamp.getTarget(event.nativeEvent);
|
|
2726
|
-
if (openMethod !== 'touch' && (clamp.contains(store.state.listElement, target) || target === event.currentTarget)) {
|
|
2727
|
-
store.state.inputRef.current?.focus();
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
}, MenuSubmenuTrigger.getDisabledMountTransitionStyles(transitionStatus), elementProps],
|
|
2731
|
-
stateAttributesMapping: stateAttributesMapping$6
|
|
2732
|
-
});
|
|
2733
|
-
|
|
2734
|
-
// Default initial focus logic:
|
|
2735
|
-
// If opened by touch, focus the popup element to prevent the virtual keyboard from opening
|
|
2736
|
-
// (this is required for Android specifically as iOS handles this automatically).
|
|
2737
|
-
const computedDefaultInitialFocus = inputInsidePopup ? interactionType => interactionType === 'touch' ? store.state.popupRef.current : inputElement : false;
|
|
2738
|
-
const resolvedInitialFocus = initialFocus === undefined ? computedDefaultInitialFocus : initialFocus;
|
|
2739
|
-
let resolvedFinalFocus;
|
|
2740
|
-
if (finalFocus != null) {
|
|
2741
|
-
resolvedFinalFocus = finalFocus;
|
|
2742
|
-
} else {
|
|
2743
|
-
resolvedFinalFocus = inputInsidePopup ? undefined : false;
|
|
2744
|
-
}
|
|
2745
|
-
const focusManagerModal = !inputInsidePopup || modal;
|
|
2746
|
-
return /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.FloatingFocusManager, {
|
|
2747
|
-
context: floatingRootContext,
|
|
2748
|
-
disabled: !mounted,
|
|
2749
|
-
modal: focusManagerModal,
|
|
2750
|
-
openInteractionType: openMethod,
|
|
2751
|
-
initialFocus: resolvedInitialFocus,
|
|
2752
|
-
returnFocus: resolvedFinalFocus,
|
|
2753
|
-
getInsideElements: () => [store.state.startDismissRef.current, store.state.endDismissRef.current],
|
|
2754
|
-
children: /*#__PURE__*/jsxRuntime.jsxs(React__namespace.Fragment, {
|
|
2755
|
-
children: [element, focusManagerModal && /*#__PURE__*/jsxRuntime.jsx(ComboboxInternalDismissButton, {
|
|
2756
|
-
ref: store.state.endDismissRef
|
|
2757
|
-
})]
|
|
2758
|
-
})
|
|
2759
|
-
});
|
|
2760
|
-
});
|
|
2761
|
-
if (process.env.NODE_ENV !== "production") ComboboxPopup.displayName = "ComboboxPopup";
|
|
2762
|
-
|
|
2763
|
-
/**
|
|
2764
|
-
* Displays an element positioned against the anchor.
|
|
2765
|
-
* Renders a `<div>` element.
|
|
2766
|
-
*/
|
|
2767
|
-
const ComboboxArrow = /*#__PURE__*/React__namespace.forwardRef(function ComboboxArrow(componentProps, forwardedRef) {
|
|
2768
|
-
const {
|
|
2769
|
-
className,
|
|
2770
|
-
render,
|
|
2771
|
-
...elementProps
|
|
2772
|
-
} = componentProps;
|
|
2773
|
-
const store = useComboboxRootContext();
|
|
2774
|
-
const {
|
|
2775
|
-
arrowRef,
|
|
2776
|
-
side,
|
|
2777
|
-
align,
|
|
2778
|
-
arrowUncentered,
|
|
2779
|
-
arrowStyles
|
|
2780
|
-
} = useComboboxPositionerContext();
|
|
2781
|
-
const open = ScrollAreaViewport.useStore(store, selectors.open);
|
|
2782
|
-
const state = {
|
|
2783
|
-
open,
|
|
2784
|
-
side,
|
|
2785
|
-
align,
|
|
2786
|
-
uncentered: arrowUncentered
|
|
2787
|
-
};
|
|
2788
|
-
return useRenderElement.useRenderElement('div', componentProps, {
|
|
2789
|
-
ref: [arrowRef, forwardedRef],
|
|
2790
|
-
stateAttributesMapping: ScrollAreaViewport.popupStateMapping,
|
|
2791
|
-
state,
|
|
2792
|
-
props: {
|
|
2793
|
-
style: arrowStyles,
|
|
2794
|
-
'aria-hidden': true,
|
|
2795
|
-
...elementProps
|
|
2796
|
-
}
|
|
2797
|
-
});
|
|
2798
|
-
});
|
|
2799
|
-
if (process.env.NODE_ENV !== "production") ComboboxArrow.displayName = "ComboboxArrow";
|
|
2800
|
-
|
|
2801
|
-
const ComboboxGroupContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2802
|
-
if (process.env.NODE_ENV !== "production") ComboboxGroupContext.displayName = "ComboboxGroupContext";
|
|
2803
|
-
function useComboboxGroupContext() {
|
|
2804
|
-
const context = React__namespace.useContext(ComboboxGroupContext);
|
|
2805
|
-
if (context === undefined) {
|
|
2806
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ComboboxGroupContext is missing. ComboboxGroup parts must be placed within <Combobox.Group>.' : useRenderElement.formatErrorMessage(18));
|
|
2807
|
-
}
|
|
2808
|
-
return context;
|
|
2809
|
-
}
|
|
2810
|
-
|
|
2811
|
-
const ComboboxGroup = /*#__PURE__*/React__namespace.forwardRef(function ComboboxGroup(componentProps, forwardedRef) {
|
|
2812
|
-
const {
|
|
2813
|
-
render,
|
|
2814
|
-
className,
|
|
2815
|
-
items,
|
|
2816
|
-
...elementProps
|
|
2817
|
-
} = componentProps;
|
|
2818
|
-
const [labelId, setLabelId] = React__namespace.useState();
|
|
2819
|
-
const contextValue = React__namespace.useMemo(() => ({
|
|
2820
|
-
labelId,
|
|
2821
|
-
setLabelId,
|
|
2822
|
-
items
|
|
2823
|
-
}), [labelId, setLabelId, items]);
|
|
2824
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2825
|
-
ref: forwardedRef,
|
|
2826
|
-
props: [{
|
|
2827
|
-
role: 'group',
|
|
2828
|
-
'aria-labelledby': labelId
|
|
2829
|
-
}, elementProps]
|
|
2830
|
-
});
|
|
2831
|
-
const wrappedElement = /*#__PURE__*/jsxRuntime.jsx(ComboboxGroupContext.Provider, {
|
|
2832
|
-
value: contextValue,
|
|
2833
|
-
children: element
|
|
2834
|
-
});
|
|
2835
|
-
if (items) {
|
|
2836
|
-
return /*#__PURE__*/jsxRuntime.jsx(GroupCollectionProvider, {
|
|
2837
|
-
items: items,
|
|
2838
|
-
children: wrappedElement
|
|
2839
|
-
});
|
|
2840
|
-
}
|
|
2841
|
-
return wrappedElement;
|
|
2842
|
-
});
|
|
2843
|
-
if (process.env.NODE_ENV !== "production") ComboboxGroup.displayName = "ComboboxGroup";
|
|
2844
|
-
|
|
2845
|
-
/**
|
|
2846
|
-
* An accessible label that is automatically associated with its parent group.
|
|
2847
|
-
* Renders a `<div>` element.
|
|
2848
|
-
*/
|
|
2849
|
-
const ComboboxGroupLabel = /*#__PURE__*/React__namespace.forwardRef(function ComboboxGroupLabel(componentProps, forwardedRef) {
|
|
2850
|
-
const {
|
|
2851
|
-
render,
|
|
2852
|
-
className,
|
|
2853
|
-
id: idProp,
|
|
2854
|
-
...elementProps
|
|
2855
|
-
} = componentProps;
|
|
2856
|
-
const {
|
|
2857
|
-
setLabelId
|
|
2858
|
-
} = useComboboxGroupContext();
|
|
2859
|
-
const id = clamp.useBaseUiId(idProp);
|
|
2860
|
-
clamp.useIsoLayoutEffect(() => {
|
|
2861
|
-
setLabelId(id);
|
|
2862
|
-
return () => {
|
|
2863
|
-
setLabelId(undefined);
|
|
2864
|
-
};
|
|
2865
|
-
}, [id, setLabelId]);
|
|
2866
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
2867
|
-
ref: forwardedRef,
|
|
2868
|
-
props: [{
|
|
2869
|
-
id
|
|
2870
|
-
}, elementProps]
|
|
2871
|
-
});
|
|
2872
|
-
return element;
|
|
2873
|
-
});
|
|
2874
|
-
if (process.env.NODE_ENV !== "production") ComboboxGroupLabel.displayName = "ComboboxGroupLabel";
|
|
2875
|
-
|
|
2876
|
-
const ComboboxItemContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
2877
|
-
if (process.env.NODE_ENV !== "production") ComboboxItemContext.displayName = "ComboboxItemContext";
|
|
2878
|
-
function useComboboxItemContext() {
|
|
2879
|
-
const context = React__namespace.useContext(ComboboxItemContext);
|
|
2880
|
-
if (!context) {
|
|
2881
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: ComboboxItemContext is missing. ComboboxItem parts must be placed within <Combobox.Item>.' : useRenderElement.formatErrorMessage(19));
|
|
2882
|
-
}
|
|
2883
|
-
return context;
|
|
2884
|
-
}
|
|
2885
|
-
|
|
2886
|
-
const ComboboxRowContext = /*#__PURE__*/React__namespace.createContext(false);
|
|
2887
|
-
if (process.env.NODE_ENV !== "production") ComboboxRowContext.displayName = "ComboboxRowContext";
|
|
2888
|
-
function useComboboxRowContext() {
|
|
2889
|
-
return React__namespace.useContext(ComboboxRowContext);
|
|
2890
|
-
}
|
|
2891
|
-
|
|
2892
|
-
const ComboboxItem = /*#__PURE__*/React__namespace.memo(/*#__PURE__*/React__namespace.forwardRef(function ComboboxItem(componentProps, forwardedRef) {
|
|
2893
|
-
const {
|
|
2894
|
-
render,
|
|
2895
|
-
className,
|
|
2896
|
-
value: itemValue = null,
|
|
2897
|
-
index: indexProp,
|
|
2898
|
-
disabled = false,
|
|
2899
|
-
nativeButton = false,
|
|
2900
|
-
...elementProps
|
|
2901
|
-
} = componentProps;
|
|
2902
|
-
const didPointerDownRef = React__namespace.useRef(false);
|
|
2903
|
-
const textRef = React__namespace.useRef(null);
|
|
2904
|
-
const listItem = MenuSubmenuTrigger.useCompositeListItem({
|
|
2905
|
-
index: indexProp,
|
|
2906
|
-
textRef,
|
|
2907
|
-
indexGuessBehavior: MenuSubmenuTrigger.IndexGuessBehavior.GuessFromOrder
|
|
2908
|
-
});
|
|
2909
|
-
const store = useComboboxRootContext();
|
|
2910
|
-
const isRow = useComboboxRowContext();
|
|
2911
|
-
const {
|
|
2912
|
-
flatFilteredItems,
|
|
2913
|
-
hasItems
|
|
2914
|
-
} = useComboboxDerivedItemsContext();
|
|
2915
|
-
const open = ScrollAreaViewport.useStore(store, selectors.open);
|
|
2916
|
-
const selectionMode = ScrollAreaViewport.useStore(store, selectors.selectionMode);
|
|
2917
|
-
const readOnly = ScrollAreaViewport.useStore(store, selectors.readOnly);
|
|
2918
|
-
const virtualized = ScrollAreaViewport.useStore(store, selectors.virtualized);
|
|
2919
|
-
const isItemEqualToValue = ScrollAreaViewport.useStore(store, selectors.isItemEqualToValue);
|
|
2920
|
-
const selectable = selectionMode !== 'none';
|
|
2921
|
-
const index = indexProp ?? (virtualized ? findItemIndex(flatFilteredItems, itemValue, isItemEqualToValue) : listItem.index);
|
|
2922
|
-
const hasRegistered = listItem.index !== -1;
|
|
2923
|
-
const rootId = ScrollAreaViewport.useStore(store, selectors.id);
|
|
2924
|
-
const highlighted = ScrollAreaViewport.useStore(store, selectors.isActive, index);
|
|
2925
|
-
const matchesSelectedValue = ScrollAreaViewport.useStore(store, selectors.isSelected, itemValue);
|
|
2926
|
-
const getItemProps = ScrollAreaViewport.useStore(store, selectors.getItemProps);
|
|
2927
|
-
const itemRef = React__namespace.useRef(null);
|
|
2928
|
-
const id = rootId != null && hasRegistered ? `${rootId}-${index}` : undefined;
|
|
2929
|
-
const selected = matchesSelectedValue && selectable;
|
|
2930
|
-
clamp.useIsoLayoutEffect(() => {
|
|
2931
|
-
const shouldRun = hasRegistered && (virtualized || indexProp != null);
|
|
2932
|
-
if (!shouldRun) {
|
|
2933
|
-
return undefined;
|
|
2934
|
-
}
|
|
2935
|
-
const list = store.state.listRef.current;
|
|
2936
|
-
list[index] = itemRef.current;
|
|
2937
|
-
return () => {
|
|
2938
|
-
delete list[index];
|
|
2939
|
-
};
|
|
2940
|
-
}, [hasRegistered, virtualized, index, indexProp, store]);
|
|
2941
|
-
clamp.useIsoLayoutEffect(() => {
|
|
2942
|
-
if (!hasRegistered || hasItems) {
|
|
2943
|
-
return undefined;
|
|
2944
|
-
}
|
|
2945
|
-
const visibleMap = store.state.valuesRef.current;
|
|
2946
|
-
visibleMap[index] = itemValue;
|
|
2947
|
-
|
|
2948
|
-
// Stable registry that doesn't depend on filtering. Assume that no
|
|
2949
|
-
// filtering had occurred at this point; otherwise, an `items` prop is
|
|
2950
|
-
// required.
|
|
2951
|
-
if (selectionMode !== 'none') {
|
|
2952
|
-
store.state.allValuesRef.current.push(itemValue);
|
|
2953
|
-
}
|
|
2954
|
-
return () => {
|
|
2955
|
-
delete visibleMap[index];
|
|
2956
|
-
};
|
|
2957
|
-
}, [hasRegistered, hasItems, index, itemValue, store, selectionMode]);
|
|
2958
|
-
clamp.useIsoLayoutEffect(() => {
|
|
2959
|
-
if (!open) {
|
|
2960
|
-
didPointerDownRef.current = false;
|
|
2961
|
-
return;
|
|
2962
|
-
}
|
|
2963
|
-
if (!hasRegistered || hasItems) {
|
|
2964
|
-
return;
|
|
2965
|
-
}
|
|
2966
|
-
const selectedValue = store.state.selectedValue;
|
|
2967
|
-
const lastSelectedValue = Array.isArray(selectedValue) ? selectedValue[selectedValue.length - 1] : selectedValue;
|
|
2968
|
-
if (compareItemEquality(itemValue, lastSelectedValue, isItemEqualToValue)) {
|
|
2969
|
-
store.set('selectedIndex', index);
|
|
2970
|
-
}
|
|
2971
|
-
}, [hasRegistered, hasItems, open, store, index, itemValue, isItemEqualToValue]);
|
|
2972
|
-
const state = {
|
|
2973
|
-
disabled,
|
|
2974
|
-
selected,
|
|
2975
|
-
highlighted
|
|
2976
|
-
};
|
|
2977
|
-
const rootProps = getItemProps({
|
|
2978
|
-
active: highlighted,
|
|
2979
|
-
selected
|
|
2980
|
-
});
|
|
2981
|
-
rootProps.id = undefined;
|
|
2982
|
-
rootProps.onFocus = undefined;
|
|
2983
|
-
const {
|
|
2984
|
-
getButtonProps,
|
|
2985
|
-
buttonRef
|
|
2986
|
-
} = clamp.useButton({
|
|
2987
|
-
disabled,
|
|
2988
|
-
focusableWhenDisabled: true,
|
|
2989
|
-
native: nativeButton,
|
|
2990
|
-
composite: true
|
|
2991
|
-
});
|
|
2992
|
-
function commitSelection(nativeEvent) {
|
|
2993
|
-
function selectItem() {
|
|
2994
|
-
store.state.handleSelection(nativeEvent, itemValue);
|
|
92
|
+
if (mode !== 'both') {
|
|
93
|
+
return staticItems ? null : baseFilter;
|
|
2995
94
|
}
|
|
2996
|
-
if (
|
|
2997
|
-
|
|
2998
|
-
store.state.requestSubmit();
|
|
2999
|
-
} else {
|
|
3000
|
-
selectItem();
|
|
95
|
+
if (baseFilter === null) {
|
|
96
|
+
return null;
|
|
3001
97
|
}
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
if (disabled || readOnly) {
|
|
3017
|
-
return;
|
|
3018
|
-
}
|
|
3019
|
-
commitSelection(event.nativeEvent);
|
|
3020
|
-
},
|
|
3021
|
-
onMouseUp(event) {
|
|
3022
|
-
const pointerStartedOnItem = didPointerDownRef.current;
|
|
3023
|
-
didPointerDownRef.current = false;
|
|
3024
|
-
if (disabled || readOnly || event.button !== 0 || pointerStartedOnItem || !highlighted) {
|
|
3025
|
-
return;
|
|
98
|
+
return (item, _query, toString) => {
|
|
99
|
+
return baseFilter(item, resolvedQuery, toString);
|
|
100
|
+
};
|
|
101
|
+
}, [baseFilter, mode, resolvedQuery, staticItems]);
|
|
102
|
+
const handleItemHighlighted = useButton.useStableCallback((highlightedValue, eventDetails) => {
|
|
103
|
+
props.onItemHighlighted?.(highlightedValue, eventDetails);
|
|
104
|
+
if (eventDetails.reason === useButton.pointer) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (enableInline) {
|
|
108
|
+
if (highlightedValue == null) {
|
|
109
|
+
setInlineInputValue('');
|
|
110
|
+
} else {
|
|
111
|
+
setInlineInputValue(ComboboxChipRemove.stringifyAsLabel(highlightedValue, itemToStringValue));
|
|
3026
112
|
}
|
|
3027
|
-
|
|
113
|
+
} else {
|
|
114
|
+
setInlineInputValue('');
|
|
3028
115
|
}
|
|
3029
|
-
};
|
|
3030
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
3031
|
-
ref: [buttonRef, forwardedRef, listItem.ref, itemRef],
|
|
3032
|
-
state,
|
|
3033
|
-
props: [rootProps, defaultProps, elementProps, getButtonProps]
|
|
3034
|
-
});
|
|
3035
|
-
const contextValue = React__namespace.useMemo(() => ({
|
|
3036
|
-
selected,
|
|
3037
|
-
textRef
|
|
3038
|
-
}), [selected, textRef]);
|
|
3039
|
-
return /*#__PURE__*/jsxRuntime.jsx(ComboboxItemContext.Provider, {
|
|
3040
|
-
value: contextValue,
|
|
3041
|
-
children: element
|
|
3042
|
-
});
|
|
3043
|
-
}));
|
|
3044
|
-
if (process.env.NODE_ENV !== "production") ComboboxItem.displayName = "ComboboxItem";
|
|
3045
|
-
|
|
3046
|
-
const ComboboxRow = /*#__PURE__*/React__namespace.forwardRef(function ComboboxRow(componentProps, forwardedRef) {
|
|
3047
|
-
const {
|
|
3048
|
-
render,
|
|
3049
|
-
className,
|
|
3050
|
-
...elementProps
|
|
3051
|
-
} = componentProps;
|
|
3052
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
3053
|
-
ref: forwardedRef,
|
|
3054
|
-
props: [{
|
|
3055
|
-
role: 'row'
|
|
3056
|
-
}, elementProps]
|
|
3057
116
|
});
|
|
3058
|
-
return /*#__PURE__*/jsxRuntime.jsx(
|
|
3059
|
-
|
|
3060
|
-
|
|
117
|
+
return /*#__PURE__*/jsxRuntime.jsx(ComboboxChipRemove.AriaCombobox, {
|
|
118
|
+
...other,
|
|
119
|
+
itemToStringLabel: itemToStringValue,
|
|
120
|
+
openOnInputClick: openOnInputClick,
|
|
121
|
+
selectionMode: "none",
|
|
122
|
+
fillInputOnItemPress: true,
|
|
123
|
+
filter: resolvedFilter,
|
|
124
|
+
autoComplete: mode,
|
|
125
|
+
inputValue: resolvedInputValue,
|
|
126
|
+
defaultInputValue: defaultValue,
|
|
127
|
+
onInputValueChange: handleValueChange,
|
|
128
|
+
onItemHighlighted: handleItemHighlighted
|
|
3061
129
|
});
|
|
3062
|
-
}
|
|
3063
|
-
if (process.env.NODE_ENV !== "production") ComboboxRow.displayName = "ComboboxRow";
|
|
130
|
+
}
|
|
3064
131
|
|
|
3065
|
-
|
|
3066
|
-
* Renders its children only when the list is empty.
|
|
3067
|
-
* Requires the `items` prop on the root component.
|
|
3068
|
-
* Announces changes politely to screen readers.
|
|
3069
|
-
* Renders a `<div>` element.
|
|
3070
|
-
*/
|
|
3071
|
-
const ComboboxEmpty = /*#__PURE__*/React__namespace.forwardRef(function ComboboxEmpty(componentProps, forwardedRef) {
|
|
3072
|
-
const {
|
|
3073
|
-
render,
|
|
3074
|
-
className,
|
|
3075
|
-
children: childrenProp,
|
|
3076
|
-
...elementProps
|
|
3077
|
-
} = componentProps;
|
|
132
|
+
function AutocompleteValue(props) {
|
|
3078
133
|
const {
|
|
3079
|
-
|
|
3080
|
-
} =
|
|
3081
|
-
const
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
134
|
+
children
|
|
135
|
+
} = props;
|
|
136
|
+
const inputValue = ComboboxChipRemove.useComboboxInputValueContext();
|
|
137
|
+
let returnValue = null;
|
|
138
|
+
if (typeof children === 'function') {
|
|
139
|
+
returnValue = children(String(inputValue));
|
|
140
|
+
} else if (children != null) {
|
|
141
|
+
returnValue = children;
|
|
142
|
+
} else {
|
|
143
|
+
returnValue = inputValue;
|
|
144
|
+
}
|
|
145
|
+
return /*#__PURE__*/jsxRuntime.jsx(React__namespace.Fragment, {
|
|
146
|
+
children: returnValue
|
|
3091
147
|
});
|
|
3092
|
-
});
|
|
3093
|
-
if (process.env.NODE_ENV !== "production") ComboboxEmpty.displayName = "ComboboxEmpty";
|
|
3094
|
-
|
|
3095
|
-
/**
|
|
3096
|
-
* Returns the internally filtered items.
|
|
3097
|
-
*/
|
|
3098
|
-
function useFilteredItems() {
|
|
3099
|
-
const items = useComboboxDerivedItemsContext();
|
|
3100
|
-
return items.filteredItems;
|
|
3101
148
|
}
|
|
3102
149
|
|
|
3103
150
|
var index_parts$5 = /*#__PURE__*/Object.freeze({
|
|
3104
151
|
__proto__: null,
|
|
3105
|
-
Arrow: ComboboxArrow,
|
|
3106
|
-
Backdrop: ComboboxBackdrop,
|
|
3107
|
-
Clear: ComboboxClear,
|
|
3108
|
-
Collection: ComboboxCollection,
|
|
3109
|
-
Empty: ComboboxEmpty,
|
|
3110
|
-
Group: ComboboxGroup,
|
|
3111
|
-
GroupLabel: ComboboxGroupLabel,
|
|
3112
|
-
Icon: ComboboxIcon,
|
|
3113
|
-
Input: ComboboxInput,
|
|
3114
|
-
InputGroup: ComboboxInputGroup,
|
|
3115
|
-
Item: ComboboxItem,
|
|
3116
|
-
List: ComboboxList,
|
|
3117
|
-
Popup: ComboboxPopup,
|
|
3118
|
-
Portal: ComboboxPortal,
|
|
3119
|
-
Positioner: ComboboxPositioner,
|
|
152
|
+
Arrow: ComboboxChipRemove.ComboboxArrow,
|
|
153
|
+
Backdrop: ComboboxChipRemove.ComboboxBackdrop,
|
|
154
|
+
Clear: ComboboxChipRemove.ComboboxClear,
|
|
155
|
+
Collection: ComboboxChipRemove.ComboboxCollection,
|
|
156
|
+
Empty: ComboboxChipRemove.ComboboxEmpty,
|
|
157
|
+
Group: ComboboxChipRemove.ComboboxGroup,
|
|
158
|
+
GroupLabel: ComboboxChipRemove.ComboboxGroupLabel,
|
|
159
|
+
Icon: ComboboxChipRemove.ComboboxIcon,
|
|
160
|
+
Input: ComboboxChipRemove.ComboboxInput,
|
|
161
|
+
InputGroup: ComboboxChipRemove.ComboboxInputGroup,
|
|
162
|
+
Item: ComboboxChipRemove.ComboboxItem,
|
|
163
|
+
List: ComboboxChipRemove.ComboboxList,
|
|
164
|
+
Popup: ComboboxChipRemove.ComboboxPopup,
|
|
165
|
+
Portal: ComboboxChipRemove.ComboboxPortal,
|
|
166
|
+
Positioner: ComboboxChipRemove.ComboboxPositioner,
|
|
3120
167
|
Root: AutocompleteRoot,
|
|
3121
|
-
Row: ComboboxRow,
|
|
168
|
+
Row: ComboboxChipRemove.ComboboxRow,
|
|
3122
169
|
Separator: Separator.Separator,
|
|
3123
|
-
Status: ComboboxStatus,
|
|
3124
|
-
Trigger: ComboboxTrigger,
|
|
170
|
+
Status: ComboboxChipRemove.ComboboxStatus,
|
|
171
|
+
Trigger: ComboboxChipRemove.ComboboxTrigger,
|
|
3125
172
|
Value: AutocompleteValue,
|
|
3126
|
-
useFilter: useCoreFilter,
|
|
3127
|
-
useFilteredItems: useFilteredItems
|
|
173
|
+
useFilter: ComboboxChipRemove.useCoreFilter,
|
|
174
|
+
useFilteredItems: ComboboxChipRemove.useFilteredItems
|
|
3128
175
|
});
|
|
3129
176
|
|
|
3130
177
|
/**
|
|
@@ -3143,7 +190,7 @@ const DialogDescription = /*#__PURE__*/React__namespace.forwardRef(function Dial
|
|
|
3143
190
|
const {
|
|
3144
191
|
store
|
|
3145
192
|
} = ScrollAreaViewport.useDialogRootContext();
|
|
3146
|
-
const id =
|
|
193
|
+
const id = useButton.useBaseUiId(idProp);
|
|
3147
194
|
store.useSyncedValueWithCleanup('descriptionElementId', id);
|
|
3148
195
|
return useRenderElement.useRenderElement('p', componentProps, {
|
|
3149
196
|
ref: forwardedRef,
|
|
@@ -3192,7 +239,7 @@ const DrawerIndent = /*#__PURE__*/React__namespace.forwardRef(function DrawerInd
|
|
|
3192
239
|
const active = providerContext?.active ?? false;
|
|
3193
240
|
const visualStateStore = providerContext?.visualStateStore;
|
|
3194
241
|
const indentRef = React__namespace.useRef(null);
|
|
3195
|
-
|
|
242
|
+
useButton.useIsoLayoutEffect(() => {
|
|
3196
243
|
const element = indentRef.current;
|
|
3197
244
|
if (!element || !visualStateStore) {
|
|
3198
245
|
return undefined;
|
|
@@ -3282,7 +329,7 @@ function DrawerProvider(props) {
|
|
|
3282
329
|
} = props;
|
|
3283
330
|
const [openById, setOpenById] = React__namespace.useState(() => new Map());
|
|
3284
331
|
const [visualStateStore] = React__namespace.useState(createVisualStateStore);
|
|
3285
|
-
const setDrawerOpen =
|
|
332
|
+
const setDrawerOpen = useButton.useStableCallback((drawerId, open) => {
|
|
3286
333
|
setOpenById(prev => {
|
|
3287
334
|
const prevOpen = prev.get(drawerId);
|
|
3288
335
|
if (prevOpen === open) {
|
|
@@ -3293,7 +340,7 @@ function DrawerProvider(props) {
|
|
|
3293
340
|
return next;
|
|
3294
341
|
});
|
|
3295
342
|
});
|
|
3296
|
-
const removeDrawer =
|
|
343
|
+
const removeDrawer = useButton.useStableCallback(drawerId => {
|
|
3297
344
|
setOpenById(prev => {
|
|
3298
345
|
if (!prev.has(drawerId)) {
|
|
3299
346
|
return prev;
|
|
@@ -3363,19 +410,19 @@ let DialogViewportDataAttributes = function (DialogViewportDataAttributes) {
|
|
|
3363
410
|
/**
|
|
3364
411
|
* Present when the dialog is open.
|
|
3365
412
|
*/
|
|
3366
|
-
DialogViewportDataAttributes[DialogViewportDataAttributes["open"] =
|
|
413
|
+
DialogViewportDataAttributes[DialogViewportDataAttributes["open"] = InternalBackdrop.CommonPopupDataAttributes.open] = "open";
|
|
3367
414
|
/**
|
|
3368
415
|
* Present when the dialog is closed.
|
|
3369
416
|
*/
|
|
3370
|
-
DialogViewportDataAttributes[DialogViewportDataAttributes["closed"] =
|
|
417
|
+
DialogViewportDataAttributes[DialogViewportDataAttributes["closed"] = InternalBackdrop.CommonPopupDataAttributes.closed] = "closed";
|
|
3371
418
|
/**
|
|
3372
419
|
* Present when the dialog is animating in.
|
|
3373
420
|
*/
|
|
3374
|
-
DialogViewportDataAttributes[DialogViewportDataAttributes["startingStyle"] =
|
|
421
|
+
DialogViewportDataAttributes[DialogViewportDataAttributes["startingStyle"] = InternalBackdrop.CommonPopupDataAttributes.startingStyle] = "startingStyle";
|
|
3375
422
|
/**
|
|
3376
423
|
* Present when the dialog is animating out.
|
|
3377
424
|
*/
|
|
3378
|
-
DialogViewportDataAttributes[DialogViewportDataAttributes["endingStyle"] =
|
|
425
|
+
DialogViewportDataAttributes[DialogViewportDataAttributes["endingStyle"] = InternalBackdrop.CommonPopupDataAttributes.endingStyle] = "endingStyle";
|
|
3379
426
|
/**
|
|
3380
427
|
* Present when the dialog is nested within another dialog.
|
|
3381
428
|
*/
|
|
@@ -3388,8 +435,8 @@ let DialogViewportDataAttributes = function (DialogViewportDataAttributes) {
|
|
|
3388
435
|
}({});
|
|
3389
436
|
|
|
3390
437
|
const stateAttributesMapping$3 = {
|
|
3391
|
-
...
|
|
3392
|
-
...
|
|
438
|
+
...InternalBackdrop.popupStateMapping,
|
|
439
|
+
...useButton.transitionStatusMapping,
|
|
3393
440
|
nested(value) {
|
|
3394
441
|
return value ? {
|
|
3395
442
|
[DialogViewportDataAttributes.nested]: ''
|
|
@@ -3477,7 +524,7 @@ class DialogHandle {
|
|
|
3477
524
|
console.warn(`Base UI: DialogHandle.open: No trigger found with id "${triggerId}". The dialog will open, but the trigger will not be associated with the dialog.`);
|
|
3478
525
|
}
|
|
3479
526
|
}
|
|
3480
|
-
this.store.setOpen(true,
|
|
527
|
+
this.store.setOpen(true, useButton.createChangeEventDetails(useButton.imperativeAction, undefined, triggerElement));
|
|
3481
528
|
}
|
|
3482
529
|
|
|
3483
530
|
/**
|
|
@@ -3488,14 +535,14 @@ class DialogHandle {
|
|
|
3488
535
|
*/
|
|
3489
536
|
openWithPayload(payload) {
|
|
3490
537
|
this.store.set('payload', payload);
|
|
3491
|
-
this.store.setOpen(true,
|
|
538
|
+
this.store.setOpen(true, useButton.createChangeEventDetails(useButton.imperativeAction, undefined, undefined));
|
|
3492
539
|
}
|
|
3493
540
|
|
|
3494
541
|
/**
|
|
3495
542
|
* Closes the dialog.
|
|
3496
543
|
*/
|
|
3497
544
|
close() {
|
|
3498
|
-
this.store.setOpen(false,
|
|
545
|
+
this.store.setOpen(false, useButton.createChangeEventDetails(useButton.imperativeAction, undefined, undefined));
|
|
3499
546
|
}
|
|
3500
547
|
|
|
3501
548
|
/**
|
|
@@ -3707,7 +754,7 @@ function useSwipeDismiss(options) {
|
|
|
3707
754
|
});
|
|
3708
755
|
const lastProgressDetailsRef = React__namespace.useRef(null);
|
|
3709
756
|
const isSwipingRef = React__namespace.useRef(false);
|
|
3710
|
-
const setSwiping =
|
|
757
|
+
const setSwiping = useButton.useStableCallback(nextSwiping => {
|
|
3711
758
|
if (isSwipingRef.current === nextSwiping) {
|
|
3712
759
|
return;
|
|
3713
760
|
}
|
|
@@ -3733,7 +780,7 @@ function useSwipeDismiss(options) {
|
|
|
3733
780
|
});
|
|
3734
781
|
swipeThresholdRef.current = Math.max(0, value);
|
|
3735
782
|
}
|
|
3736
|
-
const updateSwipeProgress =
|
|
783
|
+
const updateSwipeProgress = useButton.useStableCallback((progress, details) => {
|
|
3737
784
|
const nextProgress = Number.isFinite(progress) ? clamp.clamp(progress, 0, 1) : 0;
|
|
3738
785
|
const progressChanged = nextProgress !== swipeProgressRef.current;
|
|
3739
786
|
let detailsChanged = false;
|
|
@@ -3850,9 +897,9 @@ function useSwipeDismiss(options) {
|
|
|
3850
897
|
return event.pointerType === 'touch';
|
|
3851
898
|
}
|
|
3852
899
|
function getTargetAtPoint(position, nativeEvent) {
|
|
3853
|
-
const doc =
|
|
900
|
+
const doc = useButton.ownerDocument(elementRef.current);
|
|
3854
901
|
const elementAtPoint = getElementAtPoint(doc, position.x, position.y);
|
|
3855
|
-
const target = elementAtPoint ??
|
|
902
|
+
const target = elementAtPoint ?? useButton.getTarget(nativeEvent);
|
|
3856
903
|
return target;
|
|
3857
904
|
}
|
|
3858
905
|
function findGestureScrollableTouchTarget(target, root) {
|
|
@@ -3868,7 +915,7 @@ function useSwipeDismiss(options) {
|
|
|
3868
915
|
swipeFromScrollableRef.current = false;
|
|
3869
916
|
const touchLike = isTouchLikeEvent(event);
|
|
3870
917
|
const target = getTargetAtPoint(position, event.nativeEvent);
|
|
3871
|
-
const doc =
|
|
918
|
+
const doc = useButton.ownerDocument(elementRef.current);
|
|
3872
919
|
const body = doc.body;
|
|
3873
920
|
const scrollableTarget = touchLike && body ? findGestureScrollableTouchTarget(target, body) : null;
|
|
3874
921
|
const ignoreScrollableTarget = startOptions?.ignoreScrollableTarget ?? false;
|
|
@@ -4010,7 +1057,7 @@ function useSwipeDismiss(options) {
|
|
|
4010
1057
|
}
|
|
4011
1058
|
return null;
|
|
4012
1059
|
}
|
|
4013
|
-
const handleStart =
|
|
1060
|
+
const handleStart = useButton.useStableCallback(event => {
|
|
4014
1061
|
if (!enabled) {
|
|
4015
1062
|
return;
|
|
4016
1063
|
}
|
|
@@ -4043,7 +1090,7 @@ function useSwipeDismiss(options) {
|
|
|
4043
1090
|
if (!enabled || !isSwipingRef.current) {
|
|
4044
1091
|
return;
|
|
4045
1092
|
}
|
|
4046
|
-
const target =
|
|
1093
|
+
const target = useButton.getTarget(event.nativeEvent);
|
|
4047
1094
|
if (isTouchLikeEvent(event) && !swipeFromScrollableRef.current) {
|
|
4048
1095
|
const boundaryElement = event.currentTarget;
|
|
4049
1096
|
if (findGestureScrollableTouchTarget(target, boundaryElement)) {
|
|
@@ -4206,7 +1253,7 @@ function useSwipeDismiss(options) {
|
|
|
4206
1253
|
direction: swipeDirectionDetails
|
|
4207
1254
|
});
|
|
4208
1255
|
}
|
|
4209
|
-
const handleMove =
|
|
1256
|
+
const handleMove = useButton.useStableCallback(event => {
|
|
4210
1257
|
const currentPos = getPrimaryPointerPosition(event);
|
|
4211
1258
|
if (!currentPos) {
|
|
4212
1259
|
return;
|
|
@@ -4241,10 +1288,10 @@ function useSwipeDismiss(options) {
|
|
|
4241
1288
|
const element = elementRef.current;
|
|
4242
1289
|
if (pendingStartPos && element) {
|
|
4243
1290
|
const target = getTargetAtPoint(currentPos, event.nativeEvent);
|
|
4244
|
-
const doc =
|
|
1291
|
+
const doc = useButton.ownerDocument(element);
|
|
4245
1292
|
const body = doc.body;
|
|
4246
1293
|
const scrollTarget = body ? findGestureScrollableTouchTarget(target, body) : null;
|
|
4247
|
-
if (scrollTarget && (
|
|
1294
|
+
if (scrollTarget && (useButton.contains(element, scrollTarget) || useButton.contains(scrollTarget, element))) {
|
|
4248
1295
|
const deltaX = currentPos.x - pendingStartPos.x;
|
|
4249
1296
|
const deltaY = currentPos.y - pendingStartPos.y;
|
|
4250
1297
|
const canSwipeFromEdge = canSwipeFromScrollEdgeOnPendingMove(scrollTarget, deltaX, deltaY);
|
|
@@ -4291,7 +1338,7 @@ function useSwipeDismiss(options) {
|
|
|
4291
1338
|
lastMovePosRef.current = currentPos;
|
|
4292
1339
|
handleMoveCore(event, currentPos, movement);
|
|
4293
1340
|
});
|
|
4294
|
-
const handleEnd =
|
|
1341
|
+
const handleEnd = useButton.useStableCallback(event => {
|
|
4295
1342
|
if (!enabled) {
|
|
4296
1343
|
return;
|
|
4297
1344
|
}
|
|
@@ -4488,11 +1535,11 @@ let DrawerSwipeAreaDataAttributes = function (DrawerSwipeAreaDataAttributes) {
|
|
|
4488
1535
|
/**
|
|
4489
1536
|
* Present when the drawer is open.
|
|
4490
1537
|
*/
|
|
4491
|
-
DrawerSwipeAreaDataAttributes[DrawerSwipeAreaDataAttributes["open"] =
|
|
1538
|
+
DrawerSwipeAreaDataAttributes[DrawerSwipeAreaDataAttributes["open"] = InternalBackdrop.CommonPopupDataAttributes.open] = "open";
|
|
4492
1539
|
/**
|
|
4493
1540
|
* Present when the drawer is closed.
|
|
4494
1541
|
*/
|
|
4495
|
-
DrawerSwipeAreaDataAttributes[DrawerSwipeAreaDataAttributes["closed"] =
|
|
1542
|
+
DrawerSwipeAreaDataAttributes[DrawerSwipeAreaDataAttributes["closed"] = InternalBackdrop.CommonPopupDataAttributes.closed] = "closed";
|
|
4496
1543
|
/**
|
|
4497
1544
|
* Present when the swipe area is disabled.
|
|
4498
1545
|
*/
|
|
@@ -4574,7 +1621,7 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
4574
1621
|
} = ScrollAreaViewport.useDrawerRootContext();
|
|
4575
1622
|
const providerContext = ScrollAreaViewport.useDrawerProviderContext();
|
|
4576
1623
|
const [swipeActive, setSwipeActive] = React__namespace.useState(false);
|
|
4577
|
-
const releaseDismissTimeout =
|
|
1624
|
+
const releaseDismissTimeout = useButton.useTimeout();
|
|
4578
1625
|
const swipeAreaRef = React__namespace.useRef(null);
|
|
4579
1626
|
const swipeStartEventRef = React__namespace.useRef(null);
|
|
4580
1627
|
const openedBySwipeRef = React__namespace.useRef(false);
|
|
@@ -4585,13 +1632,13 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
4585
1632
|
const closedOffsetRef = React__namespace.useRef(null);
|
|
4586
1633
|
const appliedSwipeStylesRef = React__namespace.useRef(false);
|
|
4587
1634
|
const popupTransitionRef = React__namespace.useRef(null);
|
|
4588
|
-
const swipeAreaId =
|
|
1635
|
+
const swipeAreaId = useButton.useBaseUiId(componentProps.id);
|
|
4589
1636
|
const registerTrigger = ScrollAreaViewport.useTriggerRegistration(swipeAreaId, store);
|
|
4590
1637
|
const open = store.useState('open');
|
|
4591
1638
|
const resolvedSwipeDirection = swipeDirectionProp ?? oppositeSwipeDirection[swipeDirection];
|
|
4592
1639
|
const dismissDirection = oppositeSwipeDirection[resolvedSwipeDirection];
|
|
4593
1640
|
const enabled = !disabled && (!open || swipeActive);
|
|
4594
|
-
const resetDragDelta =
|
|
1641
|
+
const resetDragDelta = useButton.useStableCallback(() => {
|
|
4595
1642
|
dragDeltaRef.current.x = 0;
|
|
4596
1643
|
dragDeltaRef.current.y = 0;
|
|
4597
1644
|
});
|
|
@@ -4698,7 +1745,7 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
4698
1745
|
});
|
|
4699
1746
|
appliedSwipeStylesRef.current = true;
|
|
4700
1747
|
}
|
|
4701
|
-
const clearSwipeStyles =
|
|
1748
|
+
const clearSwipeStyles = useButton.useStableCallback(() => {
|
|
4702
1749
|
const popupElement = store.context.popupRef.current;
|
|
4703
1750
|
if (popupElement && appliedSwipeStylesRef.current) {
|
|
4704
1751
|
popupElement.style.removeProperty(ScrollAreaViewport.DrawerPopupCssVars.swipeMovementX);
|
|
@@ -4726,13 +1773,13 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
4726
1773
|
return;
|
|
4727
1774
|
}
|
|
4728
1775
|
openedBySwipeRef.current = true;
|
|
4729
|
-
store.setOpen(true,
|
|
1776
|
+
store.setOpen(true, useButton.createChangeEventDetails(useButton.swipe, event, swipeAreaRef.current ?? undefined));
|
|
4730
1777
|
}
|
|
4731
1778
|
function closeDrawer(event) {
|
|
4732
1779
|
if (!store.select('open')) {
|
|
4733
1780
|
return;
|
|
4734
1781
|
}
|
|
4735
|
-
store.setOpen(false,
|
|
1782
|
+
store.setOpen(false, useButton.createChangeEventDetails(useButton.swipe, event, swipeAreaRef.current ?? undefined));
|
|
4736
1783
|
}
|
|
4737
1784
|
const swipe = useSwipeDismiss({
|
|
4738
1785
|
enabled,
|
|
@@ -4931,7 +1978,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
4931
1978
|
const [swipeRelease, setSwipeRelease] = React__namespace.useState(null);
|
|
4932
1979
|
const pendingSwipeCloseSnapPointRef = React__namespace.useRef(undefined);
|
|
4933
1980
|
const resetSwipeRef = React__namespace.useRef(null);
|
|
4934
|
-
const controlledDismissFrame =
|
|
1981
|
+
const controlledDismissFrame = useButton.useAnimationFrame();
|
|
4935
1982
|
const nestedSwipeActiveRef = React__namespace.useRef(false);
|
|
4936
1983
|
const lastPointerTypeRef = React__namespace.useRef('');
|
|
4937
1984
|
const ignoreNextTouchStartFromPenRef = React__namespace.useRef(false);
|
|
@@ -4979,15 +2026,15 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
4979
2026
|
}
|
|
4980
2027
|
return [swipeDirection];
|
|
4981
2028
|
}, [snapPoints, swipeDirection]);
|
|
4982
|
-
const setSwipeDismissed =
|
|
2029
|
+
const setSwipeDismissed = useButton.useStableCallback(dismissed => {
|
|
4983
2030
|
setSwipeDismissedElements(store.context.popupRef.current, store.context.backdropRef.current, dismissed);
|
|
4984
2031
|
});
|
|
4985
|
-
const clearSwipeRelease =
|
|
2032
|
+
const clearSwipeRelease = useButton.useStableCallback(() => {
|
|
4986
2033
|
setSwipeDismissed(false);
|
|
4987
|
-
store.context.popupRef.current?.removeAttribute(
|
|
2034
|
+
store.context.popupRef.current?.removeAttribute(useButton.TransitionStatusDataAttributes.endingStyle);
|
|
4988
2035
|
setSwipeRelease(null);
|
|
4989
2036
|
});
|
|
4990
|
-
const applySwipeProgress =
|
|
2037
|
+
const applySwipeProgress = useButton.useStableCallback(({
|
|
4991
2038
|
resolvedProgress,
|
|
4992
2039
|
shouldTrackProgress,
|
|
4993
2040
|
notifyParent
|
|
@@ -5101,14 +2148,14 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
5101
2148
|
if (!popupElement) {
|
|
5102
2149
|
return;
|
|
5103
2150
|
}
|
|
5104
|
-
const doc =
|
|
2151
|
+
const doc = useButton.ownerDocument(popupElement);
|
|
5105
2152
|
const selection = doc.getSelection?.();
|
|
5106
2153
|
if (!selection || selection.isCollapsed) {
|
|
5107
2154
|
return;
|
|
5108
2155
|
}
|
|
5109
2156
|
const anchorElement = floatingUi_utils_dom.isElement(selection.anchorNode) ? selection.anchorNode : selection.anchorNode?.parentElement;
|
|
5110
2157
|
const focusElement = floatingUi_utils_dom.isElement(selection.focusNode) ? selection.focusNode : selection.focusNode?.parentElement;
|
|
5111
|
-
if (!
|
|
2158
|
+
if (!useButton.contains(popupElement, anchorElement) && !useButton.contains(popupElement, focusElement)) {
|
|
5112
2159
|
return;
|
|
5113
2160
|
}
|
|
5114
2161
|
selection.removeAllRanges();
|
|
@@ -5133,7 +2180,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
5133
2180
|
}
|
|
5134
2181
|
const doc = popupElement.ownerDocument;
|
|
5135
2182
|
const elementAtPoint = getElementAtPoint(doc, position.x, position.y);
|
|
5136
|
-
if (!elementAtPoint || !
|
|
2183
|
+
if (!elementAtPoint || !useButton.contains(popupElement, elementAtPoint)) {
|
|
5137
2184
|
return false;
|
|
5138
2185
|
}
|
|
5139
2186
|
const nativeEvent = details.nativeEvent;
|
|
@@ -5202,7 +2249,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
5202
2249
|
notifyParentSwipingChange?.(false);
|
|
5203
2250
|
setSwipeDismissed(true);
|
|
5204
2251
|
popupElement.style.removeProperty('transition');
|
|
5205
|
-
popupElement.setAttribute(
|
|
2252
|
+
popupElement.setAttribute(useButton.TransitionStatusDataAttributes.endingStyle, '');
|
|
5206
2253
|
ReactDOM__namespace.flushSync(() => {
|
|
5207
2254
|
setSwipeRelease(resolveSwipeRelease({
|
|
5208
2255
|
direction: resolvedDirection,
|
|
@@ -5273,7 +2320,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
5273
2320
|
const dragTargetOffset = clamp.clamp(currentOffset + dragDelta, 0, popupHeight);
|
|
5274
2321
|
const velocityOffset = Number.isFinite(resolvedDirectionalVelocity) && Math.abs(resolvedDirectionalVelocity) >= SNAP_VELOCITY_THRESHOLD ? clamp.clamp(resolvedDirectionalVelocity, -MAX_SNAP_VELOCITY, MAX_SNAP_VELOCITY) * SNAP_VELOCITY_MULTIPLIER : 0;
|
|
5275
2322
|
const targetOffset = snapToSequentialPoints ? dragTargetOffset : clamp.clamp(dragTargetOffset + velocityOffset, 0, popupHeight);
|
|
5276
|
-
const snapPointEventDetails =
|
|
2323
|
+
const snapPointEventDetails = useButton.createChangeEventDetails(useButton.swipe, event);
|
|
5277
2324
|
const closeFromSnapPoints = () => {
|
|
5278
2325
|
pendingSwipeCloseSnapPointRef.current = activeSnapPoint;
|
|
5279
2326
|
setActiveSnapPoint?.(null, snapPointEventDetails);
|
|
@@ -5361,12 +2408,12 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
5361
2408
|
backdropElement.style.setProperty(ScrollAreaViewport.DrawerBackdropCssVars.swipeProgress, '0');
|
|
5362
2409
|
backdropElement.style.removeProperty(ScrollAreaViewport.DrawerPopupCssVars.height);
|
|
5363
2410
|
}
|
|
5364
|
-
const dismissEventDetails =
|
|
2411
|
+
const dismissEventDetails = useButton.createChangeEventDetails(useButton.swipe, event);
|
|
5365
2412
|
store.setOpen(false, dismissEventDetails);
|
|
5366
2413
|
if (dismissEventDetails.isCanceled) {
|
|
5367
2414
|
const pendingSnapPoint = pendingSwipeCloseSnapPointRef.current;
|
|
5368
2415
|
if (pendingSnapPoint !== undefined) {
|
|
5369
|
-
setActiveSnapPoint?.(pendingSnapPoint,
|
|
2416
|
+
setActiveSnapPoint?.(pendingSnapPoint, useButton.createChangeEventDetails(useButton.swipe, event));
|
|
5370
2417
|
}
|
|
5371
2418
|
pendingSwipeCloseSnapPointRef.current = undefined;
|
|
5372
2419
|
resetSwipeRef.current?.();
|
|
@@ -5388,7 +2435,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
5388
2435
|
// Parent rejected: revert animation and restore snap point.
|
|
5389
2436
|
const pendingSnapPoint = pendingSwipeCloseSnapPointRef.current;
|
|
5390
2437
|
if (pendingSnapPoint !== undefined) {
|
|
5391
|
-
setActiveSnapPoint?.(pendingSnapPoint,
|
|
2438
|
+
setActiveSnapPoint?.(pendingSnapPoint, useButton.createChangeEventDetails(useButton.swipe, savedEvent));
|
|
5392
2439
|
}
|
|
5393
2440
|
pendingSwipeCloseSnapPointRef.current = undefined;
|
|
5394
2441
|
clearSwipeRelease();
|
|
@@ -5414,7 +2461,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
5414
2461
|
return undefined;
|
|
5415
2462
|
}
|
|
5416
2463
|
const resolvedRootElement = rootElement;
|
|
5417
|
-
const doc =
|
|
2464
|
+
const doc = useButton.ownerDocument(resolvedRootElement);
|
|
5418
2465
|
const win = floatingUi_utils_dom.getWindow(doc);
|
|
5419
2466
|
function handleNativeTouchMove(event) {
|
|
5420
2467
|
if (ignoreTouchSwipeRef.current) {
|
|
@@ -5557,7 +2604,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
5557
2604
|
if (!open || !mounted || nestedDrawerOpen) {
|
|
5558
2605
|
return;
|
|
5559
2606
|
}
|
|
5560
|
-
const doc =
|
|
2607
|
+
const doc = useButton.ownerDocument(event.currentTarget);
|
|
5561
2608
|
const elementAtPoint = getElementAtPoint(doc, event.clientX, event.clientY);
|
|
5562
2609
|
if (isSwipeIgnoredTarget(elementAtPoint) || isDrawerContentTarget(elementAtPoint)) {
|
|
5563
2610
|
return;
|
|
@@ -5613,7 +2660,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
5613
2660
|
touchScrollStateRef.current = null;
|
|
5614
2661
|
return;
|
|
5615
2662
|
}
|
|
5616
|
-
const doc =
|
|
2663
|
+
const doc = useButton.ownerDocument(event.currentTarget);
|
|
5617
2664
|
const elementAtPoint = getElementAtPoint(doc, touch.clientX, touch.clientY);
|
|
5618
2665
|
ignoreTouchSwipeRef.current = isSwipeIgnoredTarget(elementAtPoint);
|
|
5619
2666
|
if (ignoreTouchSwipeRef.current) {
|
|
@@ -5624,7 +2671,7 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
5624
2671
|
const target = floatingUi_utils_dom.isElement(event.target) ? event.target : null;
|
|
5625
2672
|
let scrollTarget = null;
|
|
5626
2673
|
let hasCrossAxisScrollableContent = false;
|
|
5627
|
-
if (rootElement && target &&
|
|
2674
|
+
if (rootElement && target && useButton.contains(rootElement, target)) {
|
|
5628
2675
|
scrollTarget = findScrollableTouchTarget(target, rootElement, scrollAxis);
|
|
5629
2676
|
hasCrossAxisScrollableContent = findScrollableTouchTarget(target, rootElement, crossScrollAxis) != null;
|
|
5630
2677
|
}
|
|
@@ -5700,7 +2747,7 @@ function setBackdropSwipingAttribute(backdropElement, swiping) {
|
|
|
5700
2747
|
backdropElement.removeAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swiping);
|
|
5701
2748
|
}
|
|
5702
2749
|
function isSwipeIgnoredTarget(target) {
|
|
5703
|
-
return Boolean(target?.closest(
|
|
2750
|
+
return Boolean(target?.closest(InternalBackdrop.BASE_UI_SWIPE_IGNORE_SELECTOR));
|
|
5704
2751
|
}
|
|
5705
2752
|
function isDrawerContentTarget(target) {
|
|
5706
2753
|
return Boolean(target?.closest(DRAWER_CONTENT_SELECTOR));
|
|
@@ -5721,11 +2768,11 @@ function isTextSelectionControl(target) {
|
|
|
5721
2768
|
function hasExpandedSelectionWithinTarget(selection, target) {
|
|
5722
2769
|
const anchorElement = floatingUi_utils_dom.isElement(selection.anchorNode) ? selection.anchorNode : selection.anchorNode?.parentElement;
|
|
5723
2770
|
const focusElement = floatingUi_utils_dom.isElement(selection.focusNode) ? selection.focusNode : selection.focusNode?.parentElement;
|
|
5724
|
-
return selection.containsNode(target, true) ||
|
|
2771
|
+
return selection.containsNode(target, true) || useButton.contains(target, anchorElement) || useButton.contains(target, focusElement);
|
|
5725
2772
|
}
|
|
5726
2773
|
function shouldIgnoreSwipeForTextSelection(doc, rootElement) {
|
|
5727
2774
|
const activeElement = doc.activeElement;
|
|
5728
|
-
const activeElementWithinRoot = Boolean(activeElement &&
|
|
2775
|
+
const activeElementWithinRoot = Boolean(activeElement && useButton.contains(rootElement, activeElement));
|
|
5729
2776
|
if (activeElementWithinRoot && isTextSelectionControl(activeElement)) {
|
|
5730
2777
|
const {
|
|
5731
2778
|
selectionStart,
|
|
@@ -5885,7 +2932,7 @@ const MenuArrow = /*#__PURE__*/React__namespace.forwardRef(function MenuArrow(co
|
|
|
5885
2932
|
};
|
|
5886
2933
|
return useRenderElement.useRenderElement('div', componentProps, {
|
|
5887
2934
|
ref: [arrowRef, forwardedRef],
|
|
5888
|
-
stateAttributesMapping:
|
|
2935
|
+
stateAttributesMapping: InternalBackdrop.popupStateMapping,
|
|
5889
2936
|
state,
|
|
5890
2937
|
props: {
|
|
5891
2938
|
style: arrowStyles,
|
|
@@ -5897,8 +2944,8 @@ const MenuArrow = /*#__PURE__*/React__namespace.forwardRef(function MenuArrow(co
|
|
|
5897
2944
|
if (process.env.NODE_ENV !== "production") MenuArrow.displayName = "MenuArrow";
|
|
5898
2945
|
|
|
5899
2946
|
const stateAttributesMapping$1 = {
|
|
5900
|
-
...
|
|
5901
|
-
...
|
|
2947
|
+
...InternalBackdrop.popupStateMapping,
|
|
2948
|
+
...useButton.transitionStatusMapping
|
|
5902
2949
|
};
|
|
5903
2950
|
|
|
5904
2951
|
/**
|
|
@@ -5933,7 +2980,7 @@ const MenuBackdrop = /*#__PURE__*/React__namespace.forwardRef(function MenuBackd
|
|
|
5933
2980
|
role: 'presentation',
|
|
5934
2981
|
hidden: !mounted,
|
|
5935
2982
|
style: {
|
|
5936
|
-
pointerEvents: lastOpenChangeReason ===
|
|
2983
|
+
pointerEvents: lastOpenChangeReason === useButton.triggerHover ? 'none' : undefined,
|
|
5937
2984
|
userSelect: 'none',
|
|
5938
2985
|
WebkitUserSelect: 'none'
|
|
5939
2986
|
}
|
|
@@ -5972,17 +3019,17 @@ const MenuCheckboxItem = /*#__PURE__*/React__namespace.forwardRef(function MenuC
|
|
|
5972
3019
|
onCheckedChange,
|
|
5973
3020
|
...elementProps
|
|
5974
3021
|
} = componentProps;
|
|
5975
|
-
const listItem =
|
|
3022
|
+
const listItem = useCompositeListItem.useCompositeListItem({
|
|
5976
3023
|
label
|
|
5977
3024
|
});
|
|
5978
3025
|
const menuPositionerContext = MenuSubmenuTrigger.useMenuPositionerContext(true);
|
|
5979
|
-
const id =
|
|
3026
|
+
const id = useButton.useBaseUiId(idProp);
|
|
5980
3027
|
const {
|
|
5981
3028
|
store
|
|
5982
3029
|
} = MenuSubmenuTrigger.useMenuRootContext();
|
|
5983
3030
|
const highlighted = store.useState('isActive', listItem.index);
|
|
5984
3031
|
const itemProps = store.useState('itemProps');
|
|
5985
|
-
const [checked, setChecked] =
|
|
3032
|
+
const [checked, setChecked] = useButton.useControlled({
|
|
5986
3033
|
controlled: checkedProp,
|
|
5987
3034
|
default: defaultChecked ?? false,
|
|
5988
3035
|
name: 'MenuCheckboxItem',
|
|
@@ -6006,9 +3053,9 @@ const MenuCheckboxItem = /*#__PURE__*/React__namespace.forwardRef(function MenuC
|
|
|
6006
3053
|
highlighted,
|
|
6007
3054
|
checked
|
|
6008
3055
|
}), [disabled, highlighted, checked]);
|
|
6009
|
-
const handleClick =
|
|
3056
|
+
const handleClick = useButton.useStableCallback(event => {
|
|
6010
3057
|
const details = {
|
|
6011
|
-
...
|
|
3058
|
+
...useButton.createChangeEventDetails(useButton.itemPress, event.nativeEvent),
|
|
6012
3059
|
preventUnmountOnClose: () => {}
|
|
6013
3060
|
};
|
|
6014
3061
|
onCheckedChange?.(!checked, details);
|
|
@@ -6052,8 +3099,8 @@ const MenuCheckboxItemIndicator = /*#__PURE__*/React__namespace.forwardRef(funct
|
|
|
6052
3099
|
const {
|
|
6053
3100
|
transitionStatus,
|
|
6054
3101
|
setMounted
|
|
6055
|
-
} =
|
|
6056
|
-
|
|
3102
|
+
} = useButton.useTransitionStatus(item.checked);
|
|
3103
|
+
useButton.useOpenChangeComplete({
|
|
6057
3104
|
open: item.checked,
|
|
6058
3105
|
ref: indicatorRef,
|
|
6059
3106
|
onComplete() {
|
|
@@ -6138,14 +3185,14 @@ function usePopupAutoResize(parameters) {
|
|
|
6138
3185
|
side,
|
|
6139
3186
|
direction
|
|
6140
3187
|
} = parameters;
|
|
6141
|
-
const runOnceAnimationsFinish =
|
|
6142
|
-
const animationFrame =
|
|
3188
|
+
const runOnceAnimationsFinish = useButton.useAnimationsFinished(popupElement, true, false);
|
|
3189
|
+
const animationFrame = useButton.useAnimationFrame();
|
|
6143
3190
|
const committedDimensionsRef = React__namespace.useRef(null);
|
|
6144
3191
|
const liveDimensionsRef = React__namespace.useRef(null);
|
|
6145
3192
|
const isInitialRenderRef = React__namespace.useRef(true);
|
|
6146
3193
|
const restoreAnchoringStylesRef = React__namespace.useRef(useRenderElement.NOOP);
|
|
6147
|
-
const onMeasureLayout =
|
|
6148
|
-
const onMeasureLayoutComplete =
|
|
3194
|
+
const onMeasureLayout = useButton.useStableCallback(onMeasureLayoutParam);
|
|
3195
|
+
const onMeasureLayoutComplete = useButton.useStableCallback(onMeasureLayoutCompleteParam);
|
|
6149
3196
|
const anchoringStyles = React__namespace.useMemo(() => {
|
|
6150
3197
|
// Ensure popup size transitions correctly when anchored to `bottom` (side=top) or `right` (side=left).
|
|
6151
3198
|
let isOriginSide = side === 'top';
|
|
@@ -6163,7 +3210,7 @@ function usePopupAutoResize(parameters) {
|
|
|
6163
3210
|
[isPhysicalLeft ? 'right' : 'left']: '0'
|
|
6164
3211
|
} : useRenderElement.EMPTY_OBJECT;
|
|
6165
3212
|
}, [side, direction]);
|
|
6166
|
-
|
|
3213
|
+
useButton.useIsoLayoutEffect(() => {
|
|
6167
3214
|
// Reset the state when the popup is closed.
|
|
6168
3215
|
if (!mounted || !enabled() || typeof ResizeObserver !== 'function') {
|
|
6169
3216
|
restoreAnchoringStylesRef.current = useRenderElement.NOOP;
|
|
@@ -6304,7 +3351,7 @@ function usePopupViewport(parameters) {
|
|
|
6304
3351
|
cssVars,
|
|
6305
3352
|
children
|
|
6306
3353
|
} = parameters;
|
|
6307
|
-
const direction =
|
|
3354
|
+
const direction = InternalBackdrop.useDirection();
|
|
6308
3355
|
const activeTrigger = store.useState('activeTriggerElement');
|
|
6309
3356
|
const activeTriggerId = store.useState('activeTriggerId');
|
|
6310
3357
|
const open = store.useState('open');
|
|
@@ -6321,22 +3368,22 @@ function usePopupViewport(parameters) {
|
|
|
6321
3368
|
const [newTriggerOffset, setNewTriggerOffset] = React__namespace.useState(null);
|
|
6322
3369
|
const currentContainerRef = React__namespace.useRef(null);
|
|
6323
3370
|
const previousContainerRef = React__namespace.useRef(null);
|
|
6324
|
-
const onAnimationsFinished =
|
|
6325
|
-
const cleanupFrame =
|
|
3371
|
+
const onAnimationsFinished = useButton.useAnimationsFinished(currentContainerRef, true, false);
|
|
3372
|
+
const cleanupFrame = useButton.useAnimationFrame();
|
|
6326
3373
|
const [previousContentDimensions, setPreviousContentDimensions] = React__namespace.useState(null);
|
|
6327
3374
|
const [showStartingStyleAttribute, setShowStartingStyleAttribute] = React__namespace.useState(false);
|
|
6328
|
-
|
|
3375
|
+
useButton.useIsoLayoutEffect(() => {
|
|
6329
3376
|
store.set('hasViewport', true);
|
|
6330
3377
|
return () => {
|
|
6331
3378
|
store.set('hasViewport', false);
|
|
6332
3379
|
};
|
|
6333
3380
|
}, [store]);
|
|
6334
|
-
const handleMeasureLayout =
|
|
3381
|
+
const handleMeasureLayout = useButton.useStableCallback(() => {
|
|
6335
3382
|
currentContainerRef.current?.style.setProperty('animation', 'none');
|
|
6336
3383
|
currentContainerRef.current?.style.setProperty('transition', 'none');
|
|
6337
3384
|
previousContainerRef.current?.style.setProperty('display', 'none');
|
|
6338
3385
|
});
|
|
6339
|
-
const handleMeasureLayoutComplete =
|
|
3386
|
+
const handleMeasureLayoutComplete = useButton.useStableCallback(previousDimensions => {
|
|
6340
3387
|
currentContainerRef.current?.style.removeProperty('animation');
|
|
6341
3388
|
currentContainerRef.current?.style.removeProperty('transition');
|
|
6342
3389
|
previousContainerRef.current?.style.removeProperty('display');
|
|
@@ -6345,7 +3392,7 @@ function usePopupViewport(parameters) {
|
|
|
6345
3392
|
}
|
|
6346
3393
|
});
|
|
6347
3394
|
const lastHandledTriggerRef = React__namespace.useRef(null);
|
|
6348
|
-
|
|
3395
|
+
useButton.useIsoLayoutEffect(() => {
|
|
6349
3396
|
// When a trigger changes, set the captured children HTML to state,
|
|
6350
3397
|
// so we can render both new and old content.
|
|
6351
3398
|
if (activeTrigger && previousActiveTrigger && activeTrigger !== previousActiveTrigger && lastHandledTriggerRef.current !== activeTrigger && capturedNodeRef.current) {
|
|
@@ -6372,7 +3419,7 @@ function usePopupViewport(parameters) {
|
|
|
6372
3419
|
|
|
6373
3420
|
// Capture a clone of the current content DOM subtree when not transitioning.
|
|
6374
3421
|
// We can't store previous React nodes as they may be stateful; instead we capture DOM clones for visual continuity.
|
|
6375
|
-
|
|
3422
|
+
useButton.useIsoLayoutEffect(() => {
|
|
6376
3423
|
// When a transition is in progress, we store the next content in capturedNodeRef.
|
|
6377
3424
|
// This handles the case where the trigger changes multiple times before the transition finishes.
|
|
6378
3425
|
// We want to always capture the latest content for the previous snapshot.
|
|
@@ -6401,7 +3448,7 @@ function usePopupViewport(parameters) {
|
|
|
6401
3448
|
childrenToRender = /*#__PURE__*/jsxRuntime.jsxs(React__namespace.Fragment, {
|
|
6402
3449
|
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
6403
3450
|
"data-previous": true,
|
|
6404
|
-
inert:
|
|
3451
|
+
inert: InternalBackdrop.inertValue(true),
|
|
6405
3452
|
ref: previousContainerRef,
|
|
6406
3453
|
style: {
|
|
6407
3454
|
...(previousContentDimensions ? {
|
|
@@ -6421,7 +3468,7 @@ function usePopupViewport(parameters) {
|
|
|
6421
3468
|
}
|
|
6422
3469
|
|
|
6423
3470
|
// When previousContentNode is present, imperatively populate the previous container with the cloned children.
|
|
6424
|
-
|
|
3471
|
+
useButton.useIsoLayoutEffect(() => {
|
|
6425
3472
|
const container = previousContainerRef.current;
|
|
6426
3473
|
if (!container || !previousContentNode) {
|
|
6427
3474
|
return;
|
|
@@ -6508,7 +3555,7 @@ function usePopupContentKey(activeTriggerId, payload) {
|
|
|
6508
3555
|
const previousActiveTriggerIdRef = React__namespace.useRef(activeTriggerId);
|
|
6509
3556
|
const previousPayloadRef = React__namespace.useRef(payload);
|
|
6510
3557
|
const pendingPayloadUpdateRef = React__namespace.useRef(false);
|
|
6511
|
-
|
|
3558
|
+
useButton.useIsoLayoutEffect(() => {
|
|
6512
3559
|
// Compare against the last committed values to decide whether we need a new DOM subtree.
|
|
6513
3560
|
const previousActiveTriggerId = previousActiveTriggerIdRef.current;
|
|
6514
3561
|
const previousPayload = previousPayloadRef.current;
|
|
@@ -6621,14 +3668,14 @@ class MenuHandle {
|
|
|
6621
3668
|
if (triggerId && !triggerElement) {
|
|
6622
3669
|
throw new Error(process.env.NODE_ENV !== "production" ? `Base UI: MenuHandle.open: No trigger found with id "${triggerId}".` : useRenderElement.formatErrorMessage(83, triggerId));
|
|
6623
3670
|
}
|
|
6624
|
-
this.store.setOpen(true,
|
|
3671
|
+
this.store.setOpen(true, useButton.createChangeEventDetails('imperative-action', undefined, triggerElement));
|
|
6625
3672
|
}
|
|
6626
3673
|
|
|
6627
3674
|
/**
|
|
6628
3675
|
* Closes the menu.
|
|
6629
3676
|
*/
|
|
6630
3677
|
close() {
|
|
6631
|
-
this.store.setOpen(false,
|
|
3678
|
+
this.store.setOpen(false, useButton.createChangeEventDetails('imperative-action', undefined, undefined));
|
|
6632
3679
|
}
|
|
6633
3680
|
|
|
6634
3681
|
/**
|
|
@@ -6742,7 +3789,7 @@ const ScrollAreaScrollbar = /*#__PURE__*/React__namespace.forwardRef(function Sc
|
|
|
6742
3789
|
overflowYEnd: overflowEdges.yEnd,
|
|
6743
3790
|
cornerHidden: hiddenState.corner
|
|
6744
3791
|
};
|
|
6745
|
-
const direction =
|
|
3792
|
+
const direction = InternalBackdrop.useDirection();
|
|
6746
3793
|
const hideTrackUntilMeasured = !hasMeasuredScrollbar && !keepMounted;
|
|
6747
3794
|
React__namespace.useEffect(() => {
|
|
6748
3795
|
const viewportEl = viewportRef.current;
|
|
@@ -6900,7 +3947,7 @@ const ScrollAreaContent = /*#__PURE__*/React__namespace.forwardRef(function Scro
|
|
|
6900
3947
|
const {
|
|
6901
3948
|
viewportState
|
|
6902
3949
|
} = ScrollAreaViewport.useScrollAreaRootContext();
|
|
6903
|
-
|
|
3950
|
+
useButton.useIsoLayoutEffect(() => {
|
|
6904
3951
|
if (typeof ResizeObserver === 'undefined') {
|
|
6905
3952
|
return undefined;
|
|
6906
3953
|
}
|
|
@@ -7040,434 +4087,36 @@ var index_parts$2 = /*#__PURE__*/Object.freeze({
|
|
|
7040
4087
|
Viewport: ScrollAreaViewport.ScrollAreaViewport
|
|
7041
4088
|
});
|
|
7042
4089
|
|
|
7043
|
-
function ComboboxRoot(props) {
|
|
7044
|
-
const {
|
|
7045
|
-
multiple = false,
|
|
7046
|
-
defaultValue,
|
|
7047
|
-
value,
|
|
7048
|
-
onValueChange,
|
|
7049
|
-
autoComplete,
|
|
7050
|
-
...other
|
|
7051
|
-
} = props;
|
|
7052
|
-
return /*#__PURE__*/jsxRuntime.jsx(AriaCombobox, {
|
|
7053
|
-
...other,
|
|
7054
|
-
selectionMode: multiple ? 'multiple' : 'single',
|
|
7055
|
-
selectedValue: value,
|
|
7056
|
-
defaultSelectedValue: defaultValue,
|
|
7057
|
-
onSelectedValueChange: onValueChange,
|
|
7058
|
-
formAutoComplete: autoComplete
|
|
7059
|
-
});
|
|
7060
|
-
}
|
|
7061
|
-
|
|
7062
|
-
/**
|
|
7063
|
-
* An accessible label that is automatically associated with the combobox trigger.
|
|
7064
|
-
* Renders a `<div>` element.
|
|
7065
|
-
*
|
|
7066
|
-
* Documentation: [Base UI Combobox](https://base-ui.com/react/components/combobox)
|
|
7067
|
-
*/
|
|
7068
|
-
const ComboboxLabel = /*#__PURE__*/React__namespace.forwardRef(function ComboboxLabel(componentProps, forwardedRef) {
|
|
7069
|
-
const {
|
|
7070
|
-
render,
|
|
7071
|
-
className,
|
|
7072
|
-
...elementProps
|
|
7073
|
-
} = componentProps;
|
|
7074
|
-
// Keep label id derived from the root and ignore runtime `id` overrides from untyped consumers.
|
|
7075
|
-
const elementPropsWithoutId = elementProps;
|
|
7076
|
-
delete elementPropsWithoutId.id;
|
|
7077
|
-
const fieldRootContext = NumberFieldInput.useFieldRootContext();
|
|
7078
|
-
const store = useComboboxRootContext();
|
|
7079
|
-
const inputInsidePopup = ScrollAreaViewport.useStore(store, selectors.inputInsidePopup);
|
|
7080
|
-
const triggerElement = ScrollAreaViewport.useStore(store, selectors.triggerElement);
|
|
7081
|
-
const inputElement = ScrollAreaViewport.useStore(store, selectors.inputElement);
|
|
7082
|
-
const rootId = ScrollAreaViewport.useStore(store, selectors.id);
|
|
7083
|
-
const defaultLabelId = getDefaultLabelId(rootId);
|
|
7084
|
-
const localControlId = triggerElement?.id ?? (inputInsidePopup ? rootId : undefined);
|
|
7085
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
7086
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
7087
|
-
React__namespace.useEffect(() => {
|
|
7088
|
-
if (!inputElement || inputInsidePopup) {
|
|
7089
|
-
return;
|
|
7090
|
-
}
|
|
7091
|
-
const ownerStackMessage = clamp.SafeReact.captureOwnerStack?.() || '';
|
|
7092
|
-
const message = '<Combobox.Label> labels <Combobox.Trigger> only. ' + 'When <Combobox.Input> is the form control, use a native <label> or <Field.Label> instead.';
|
|
7093
|
-
clamp.error(`${message}${ownerStackMessage}`);
|
|
7094
|
-
}, [inputElement, inputInsidePopup]);
|
|
7095
|
-
}
|
|
7096
|
-
const labelProps = NumberFieldInput.useLabel({
|
|
7097
|
-
id: defaultLabelId,
|
|
7098
|
-
fallbackControlId: localControlId,
|
|
7099
|
-
setLabelId(nextLabelId) {
|
|
7100
|
-
store.set('labelId', nextLabelId);
|
|
7101
|
-
}
|
|
7102
|
-
});
|
|
7103
|
-
return useRenderElement.useRenderElement('div', componentProps, {
|
|
7104
|
-
ref: forwardedRef,
|
|
7105
|
-
state: fieldRootContext.state,
|
|
7106
|
-
props: [labelProps, elementProps],
|
|
7107
|
-
stateAttributesMapping: NumberFieldInput.fieldValidityMapping
|
|
7108
|
-
});
|
|
7109
|
-
});
|
|
7110
|
-
if (process.env.NODE_ENV !== "production") ComboboxLabel.displayName = "ComboboxLabel";
|
|
7111
|
-
|
|
7112
|
-
function ComboboxValue(props) {
|
|
7113
|
-
const {
|
|
7114
|
-
children: childrenProp,
|
|
7115
|
-
placeholder
|
|
7116
|
-
} = props;
|
|
7117
|
-
const store = useComboboxRootContext();
|
|
7118
|
-
const itemToStringLabel = ScrollAreaViewport.useStore(store, selectors.itemToStringLabel);
|
|
7119
|
-
const selectedValue = ScrollAreaViewport.useStore(store, selectors.selectedValue);
|
|
7120
|
-
const items = ScrollAreaViewport.useStore(store, selectors.items);
|
|
7121
|
-
const multiple = ScrollAreaViewport.useStore(store, selectors.selectionMode) === 'multiple';
|
|
7122
|
-
const hasSelectedValue = ScrollAreaViewport.useStore(store, selectors.hasSelectedValue);
|
|
7123
|
-
const shouldCheckNullItemLabel = !hasSelectedValue && placeholder != null && childrenProp == null;
|
|
7124
|
-
const hasNullLabel = ScrollAreaViewport.useStore(store, selectors.hasNullItemLabel, shouldCheckNullItemLabel);
|
|
7125
|
-
let children = null;
|
|
7126
|
-
if (typeof childrenProp === 'function') {
|
|
7127
|
-
children = childrenProp(selectedValue);
|
|
7128
|
-
} else if (childrenProp != null) {
|
|
7129
|
-
children = childrenProp;
|
|
7130
|
-
} else if (!hasSelectedValue && placeholder != null && !hasNullLabel) {
|
|
7131
|
-
children = placeholder;
|
|
7132
|
-
} else if (multiple && Array.isArray(selectedValue)) {
|
|
7133
|
-
children = resolveMultipleLabels(selectedValue, items, itemToStringLabel);
|
|
7134
|
-
} else {
|
|
7135
|
-
children = resolveSelectedLabel(selectedValue, items, itemToStringLabel);
|
|
7136
|
-
}
|
|
7137
|
-
return /*#__PURE__*/jsxRuntime.jsx(React__namespace.Fragment, {
|
|
7138
|
-
children: children
|
|
7139
|
-
});
|
|
7140
|
-
}
|
|
7141
|
-
|
|
7142
|
-
const ComboboxItemIndicator = /*#__PURE__*/React__namespace.forwardRef(function ComboboxItemIndicator(componentProps, forwardedRef) {
|
|
7143
|
-
const keepMounted = componentProps.keepMounted ?? false;
|
|
7144
|
-
const {
|
|
7145
|
-
selected
|
|
7146
|
-
} = useComboboxItemContext();
|
|
7147
|
-
const shouldRender = keepMounted || selected;
|
|
7148
|
-
if (!shouldRender) {
|
|
7149
|
-
return null;
|
|
7150
|
-
}
|
|
7151
|
-
|
|
7152
|
-
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
7153
|
-
return /*#__PURE__*/jsxRuntime.jsx(Inner, {
|
|
7154
|
-
...componentProps,
|
|
7155
|
-
ref: forwardedRef
|
|
7156
|
-
});
|
|
7157
|
-
});
|
|
7158
|
-
|
|
7159
|
-
/** The core implementation of the indicator is split here to avoid paying the hooks
|
|
7160
|
-
* costs unless the element needs to be mounted. */
|
|
7161
|
-
if (process.env.NODE_ENV !== "production") ComboboxItemIndicator.displayName = "ComboboxItemIndicator";
|
|
7162
|
-
const Inner = /*#__PURE__*/React__namespace.memo(/*#__PURE__*/React__namespace.forwardRef((componentProps, forwardedRef) => {
|
|
7163
|
-
const {
|
|
7164
|
-
render,
|
|
7165
|
-
className,
|
|
7166
|
-
keepMounted,
|
|
7167
|
-
...elementProps
|
|
7168
|
-
} = componentProps;
|
|
7169
|
-
const {
|
|
7170
|
-
selected
|
|
7171
|
-
} = useComboboxItemContext();
|
|
7172
|
-
const indicatorRef = React__namespace.useRef(null);
|
|
7173
|
-
const {
|
|
7174
|
-
transitionStatus,
|
|
7175
|
-
setMounted
|
|
7176
|
-
} = clamp.useTransitionStatus(selected);
|
|
7177
|
-
const state = {
|
|
7178
|
-
selected,
|
|
7179
|
-
transitionStatus
|
|
7180
|
-
};
|
|
7181
|
-
const element = useRenderElement.useRenderElement('span', componentProps, {
|
|
7182
|
-
ref: [forwardedRef, indicatorRef],
|
|
7183
|
-
state,
|
|
7184
|
-
props: [{
|
|
7185
|
-
'aria-hidden': true,
|
|
7186
|
-
children: '✔️'
|
|
7187
|
-
}, elementProps],
|
|
7188
|
-
stateAttributesMapping: clamp.transitionStatusMapping
|
|
7189
|
-
});
|
|
7190
|
-
clamp.useOpenChangeComplete({
|
|
7191
|
-
open: selected,
|
|
7192
|
-
ref: indicatorRef,
|
|
7193
|
-
onComplete() {
|
|
7194
|
-
if (!selected) {
|
|
7195
|
-
setMounted(false);
|
|
7196
|
-
}
|
|
7197
|
-
}
|
|
7198
|
-
});
|
|
7199
|
-
return element;
|
|
7200
|
-
}));
|
|
7201
|
-
if (process.env.NODE_ENV !== "production") Inner.displayName = "Inner";
|
|
7202
|
-
|
|
7203
|
-
const ComboboxChips = /*#__PURE__*/React__namespace.forwardRef(function ComboboxChips(componentProps, forwardedRef) {
|
|
7204
|
-
const {
|
|
7205
|
-
render,
|
|
7206
|
-
className,
|
|
7207
|
-
...elementProps
|
|
7208
|
-
} = componentProps;
|
|
7209
|
-
const store = useComboboxRootContext();
|
|
7210
|
-
const open = ScrollAreaViewport.useStore(store, selectors.open);
|
|
7211
|
-
const hasSelectionChips = ScrollAreaViewport.useStore(store, selectors.hasSelectionChips);
|
|
7212
|
-
const [highlightedChipIndex, setHighlightedChipIndex] = React__namespace.useState(undefined);
|
|
7213
|
-
if (open && highlightedChipIndex !== undefined) {
|
|
7214
|
-
setHighlightedChipIndex(undefined);
|
|
7215
|
-
}
|
|
7216
|
-
const chipsRef = React__namespace.useRef([]);
|
|
7217
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
7218
|
-
ref: [forwardedRef, store.state.chipsContainerRef],
|
|
7219
|
-
// NVDA enters browse mode instead of staying in focus mode when navigating with
|
|
7220
|
-
// arrow keys inside a container unless it has a toolbar role.
|
|
7221
|
-
props: [hasSelectionChips ? {
|
|
7222
|
-
role: 'toolbar'
|
|
7223
|
-
} : useRenderElement.EMPTY_OBJECT, elementProps]
|
|
7224
|
-
});
|
|
7225
|
-
const contextValue = React__namespace.useMemo(() => ({
|
|
7226
|
-
highlightedChipIndex,
|
|
7227
|
-
setHighlightedChipIndex,
|
|
7228
|
-
chipsRef
|
|
7229
|
-
}), [highlightedChipIndex, setHighlightedChipIndex, chipsRef]);
|
|
7230
|
-
return /*#__PURE__*/jsxRuntime.jsx(ComboboxChipsContext.Provider, {
|
|
7231
|
-
value: contextValue,
|
|
7232
|
-
children: /*#__PURE__*/jsxRuntime.jsx(MenuSubmenuTrigger.CompositeList, {
|
|
7233
|
-
elementsRef: chipsRef,
|
|
7234
|
-
children: element
|
|
7235
|
-
})
|
|
7236
|
-
});
|
|
7237
|
-
});
|
|
7238
|
-
if (process.env.NODE_ENV !== "production") ComboboxChips.displayName = "ComboboxChips";
|
|
7239
|
-
|
|
7240
|
-
const ComboboxChipContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
7241
|
-
if (process.env.NODE_ENV !== "production") ComboboxChipContext.displayName = "ComboboxChipContext";
|
|
7242
|
-
function useComboboxChipContext() {
|
|
7243
|
-
const context = React__namespace.useContext(ComboboxChipContext);
|
|
7244
|
-
if (!context) {
|
|
7245
|
-
throw new Error(process.env.NODE_ENV !== "production" ? 'useComboboxChipContext must be used within a ComboboxChip' : useRenderElement.formatErrorMessage(17));
|
|
7246
|
-
}
|
|
7247
|
-
return context;
|
|
7248
|
-
}
|
|
7249
|
-
|
|
7250
|
-
const ComboboxChip = /*#__PURE__*/React__namespace.forwardRef(function ComboboxChip(componentProps, forwardedRef) {
|
|
7251
|
-
const {
|
|
7252
|
-
render,
|
|
7253
|
-
className,
|
|
7254
|
-
...elementProps
|
|
7255
|
-
} = componentProps;
|
|
7256
|
-
const store = useComboboxRootContext();
|
|
7257
|
-
const {
|
|
7258
|
-
setHighlightedChipIndex,
|
|
7259
|
-
chipsRef
|
|
7260
|
-
} = useComboboxChipsContext();
|
|
7261
|
-
const disabled = ScrollAreaViewport.useStore(store, selectors.disabled);
|
|
7262
|
-
const readOnly = ScrollAreaViewport.useStore(store, selectors.readOnly);
|
|
7263
|
-
const selectedValue = ScrollAreaViewport.useStore(store, selectors.selectedValue);
|
|
7264
|
-
const {
|
|
7265
|
-
ref,
|
|
7266
|
-
index
|
|
7267
|
-
} = MenuSubmenuTrigger.useCompositeListItem();
|
|
7268
|
-
function handleKeyDown(event) {
|
|
7269
|
-
let nextIndex = index;
|
|
7270
|
-
if (event.key === 'ArrowLeft') {
|
|
7271
|
-
event.preventDefault();
|
|
7272
|
-
if (index > 0) {
|
|
7273
|
-
nextIndex = index - 1;
|
|
7274
|
-
} else {
|
|
7275
|
-
nextIndex = undefined;
|
|
7276
|
-
}
|
|
7277
|
-
} else if (event.key === 'ArrowRight') {
|
|
7278
|
-
event.preventDefault();
|
|
7279
|
-
if (index < selectedValue.length - 1) {
|
|
7280
|
-
nextIndex = index + 1;
|
|
7281
|
-
} else {
|
|
7282
|
-
nextIndex = undefined;
|
|
7283
|
-
}
|
|
7284
|
-
} else if (event.key === 'Backspace' || event.key === 'Delete') {
|
|
7285
|
-
const computedNextIndex = index >= selectedValue.length - 1 ? selectedValue.length - 2 : index;
|
|
7286
|
-
nextIndex = computedNextIndex >= 0 ? computedNextIndex : undefined;
|
|
7287
|
-
clamp.stopEvent(event);
|
|
7288
|
-
store.state.setIndices({
|
|
7289
|
-
activeIndex: null,
|
|
7290
|
-
selectedIndex: null,
|
|
7291
|
-
type: 'keyboard'
|
|
7292
|
-
});
|
|
7293
|
-
store.state.setSelectedValue(selectedValue.filter((_, i) => i !== index), clamp.createChangeEventDetails(clamp.none, event.nativeEvent));
|
|
7294
|
-
} else if (event.key === 'Enter' || event.key === ' ') {
|
|
7295
|
-
clamp.stopEvent(event);
|
|
7296
|
-
nextIndex = undefined;
|
|
7297
|
-
} else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
7298
|
-
clamp.stopEvent(event);
|
|
7299
|
-
store.state.setOpen(true, clamp.createChangeEventDetails(clamp.listNavigation, event.nativeEvent));
|
|
7300
|
-
nextIndex = undefined;
|
|
7301
|
-
} else if (
|
|
7302
|
-
// Check for printable characters (letters, numbers, symbols)
|
|
7303
|
-
event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
7304
|
-
nextIndex = undefined;
|
|
7305
|
-
}
|
|
7306
|
-
return nextIndex;
|
|
7307
|
-
}
|
|
7308
|
-
const state = {
|
|
7309
|
-
disabled
|
|
7310
|
-
};
|
|
7311
|
-
const element = useRenderElement.useRenderElement('div', componentProps, {
|
|
7312
|
-
ref: [forwardedRef, ref],
|
|
7313
|
-
state,
|
|
7314
|
-
props: [{
|
|
7315
|
-
tabIndex: -1,
|
|
7316
|
-
'aria-disabled': disabled || undefined,
|
|
7317
|
-
'aria-readonly': readOnly || undefined,
|
|
7318
|
-
onKeyDown(event) {
|
|
7319
|
-
if (disabled || readOnly) {
|
|
7320
|
-
return;
|
|
7321
|
-
}
|
|
7322
|
-
const nextIndex = handleKeyDown(event);
|
|
7323
|
-
ReactDOM__namespace.flushSync(() => {
|
|
7324
|
-
setHighlightedChipIndex(nextIndex);
|
|
7325
|
-
});
|
|
7326
|
-
if (nextIndex === undefined) {
|
|
7327
|
-
store.state.inputRef.current?.focus();
|
|
7328
|
-
} else {
|
|
7329
|
-
chipsRef.current[nextIndex]?.focus();
|
|
7330
|
-
}
|
|
7331
|
-
},
|
|
7332
|
-
onMouseDown(event) {
|
|
7333
|
-
if (readOnly) {
|
|
7334
|
-
return;
|
|
7335
|
-
}
|
|
7336
|
-
event.preventDefault();
|
|
7337
|
-
if (disabled) {
|
|
7338
|
-
return;
|
|
7339
|
-
}
|
|
7340
|
-
store.state.inputRef.current?.focus();
|
|
7341
|
-
}
|
|
7342
|
-
}, elementProps]
|
|
7343
|
-
});
|
|
7344
|
-
const contextValue = React__namespace.useMemo(() => ({
|
|
7345
|
-
index
|
|
7346
|
-
}), [index]);
|
|
7347
|
-
return /*#__PURE__*/jsxRuntime.jsx(ComboboxChipContext.Provider, {
|
|
7348
|
-
value: contextValue,
|
|
7349
|
-
children: element
|
|
7350
|
-
});
|
|
7351
|
-
});
|
|
7352
|
-
if (process.env.NODE_ENV !== "production") ComboboxChip.displayName = "ComboboxChip";
|
|
7353
|
-
|
|
7354
|
-
/**
|
|
7355
|
-
* A button to remove a chip.
|
|
7356
|
-
* Renders a `<button>` element.
|
|
7357
|
-
*/
|
|
7358
|
-
const ComboboxChipRemove = /*#__PURE__*/React__namespace.forwardRef(function ComboboxChipRemove(componentProps, forwardedRef) {
|
|
7359
|
-
const {
|
|
7360
|
-
render,
|
|
7361
|
-
className,
|
|
7362
|
-
disabled: disabledProp = false,
|
|
7363
|
-
nativeButton = true,
|
|
7364
|
-
...elementProps
|
|
7365
|
-
} = componentProps;
|
|
7366
|
-
const store = useComboboxRootContext();
|
|
7367
|
-
const {
|
|
7368
|
-
index
|
|
7369
|
-
} = useComboboxChipContext();
|
|
7370
|
-
const comboboxDisabled = ScrollAreaViewport.useStore(store, selectors.disabled);
|
|
7371
|
-
const readOnly = ScrollAreaViewport.useStore(store, selectors.readOnly);
|
|
7372
|
-
const selectedValue = ScrollAreaViewport.useStore(store, selectors.selectedValue);
|
|
7373
|
-
const isItemEqualToValue = ScrollAreaViewport.useStore(store, selectors.isItemEqualToValue);
|
|
7374
|
-
const disabled = comboboxDisabled || disabledProp;
|
|
7375
|
-
const {
|
|
7376
|
-
buttonRef,
|
|
7377
|
-
getButtonProps
|
|
7378
|
-
} = clamp.useButton({
|
|
7379
|
-
native: nativeButton,
|
|
7380
|
-
disabled: disabled || readOnly,
|
|
7381
|
-
focusableWhenDisabled: true
|
|
7382
|
-
});
|
|
7383
|
-
const state = {
|
|
7384
|
-
disabled
|
|
7385
|
-
};
|
|
7386
|
-
function clearActiveIndexForRemovedItem(removedItem) {
|
|
7387
|
-
const activeIndex = store.state.activeIndex;
|
|
7388
|
-
if (activeIndex == null) {
|
|
7389
|
-
return;
|
|
7390
|
-
}
|
|
7391
|
-
|
|
7392
|
-
// Try current visible list first; if not found, it's filtered out.
|
|
7393
|
-
// No need to clear highlight in that case since it can't equal activeIndex.
|
|
7394
|
-
const removedIndex = findItemIndex(store.state.valuesRef.current, removedItem, isItemEqualToValue);
|
|
7395
|
-
if (removedIndex !== -1 && activeIndex === removedIndex) {
|
|
7396
|
-
store.state.setIndices({
|
|
7397
|
-
activeIndex: null,
|
|
7398
|
-
type: store.state.keyboardActiveRef.current ? 'keyboard' : 'pointer'
|
|
7399
|
-
});
|
|
7400
|
-
}
|
|
7401
|
-
}
|
|
7402
|
-
function removeChip(event) {
|
|
7403
|
-
const eventDetails = clamp.createChangeEventDetails(clamp.chipRemovePress, event.nativeEvent);
|
|
7404
|
-
const removedItem = selectedValue[index];
|
|
7405
|
-
clearActiveIndexForRemovedItem(removedItem);
|
|
7406
|
-
store.state.setSelectedValue(selectedValue.filter((_, i) => i !== index), eventDetails);
|
|
7407
|
-
store.state.inputRef.current?.focus();
|
|
7408
|
-
return eventDetails;
|
|
7409
|
-
}
|
|
7410
|
-
const element = useRenderElement.useRenderElement('button', componentProps, {
|
|
7411
|
-
ref: [forwardedRef, buttonRef],
|
|
7412
|
-
state,
|
|
7413
|
-
props: [{
|
|
7414
|
-
tabIndex: -1,
|
|
7415
|
-
onClick(event) {
|
|
7416
|
-
if (disabled || readOnly) {
|
|
7417
|
-
return;
|
|
7418
|
-
}
|
|
7419
|
-
const eventDetails = removeChip(event);
|
|
7420
|
-
if (!eventDetails.isPropagationAllowed) {
|
|
7421
|
-
event.stopPropagation();
|
|
7422
|
-
}
|
|
7423
|
-
},
|
|
7424
|
-
onKeyDown(event) {
|
|
7425
|
-
if (disabled || readOnly) {
|
|
7426
|
-
return;
|
|
7427
|
-
}
|
|
7428
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
7429
|
-
const eventDetails = removeChip(event);
|
|
7430
|
-
if (!eventDetails.isPropagationAllowed) {
|
|
7431
|
-
clamp.stopEvent(event);
|
|
7432
|
-
}
|
|
7433
|
-
}
|
|
7434
|
-
}
|
|
7435
|
-
}, elementProps, getButtonProps]
|
|
7436
|
-
});
|
|
7437
|
-
return element;
|
|
7438
|
-
});
|
|
7439
|
-
if (process.env.NODE_ENV !== "production") ComboboxChipRemove.displayName = "ComboboxChipRemove";
|
|
7440
|
-
|
|
7441
4090
|
var index_parts$1 = /*#__PURE__*/Object.freeze({
|
|
7442
4091
|
__proto__: null,
|
|
7443
|
-
Arrow: ComboboxArrow,
|
|
7444
|
-
Backdrop: ComboboxBackdrop,
|
|
7445
|
-
Chip: ComboboxChip,
|
|
7446
|
-
ChipRemove: ComboboxChipRemove,
|
|
7447
|
-
Chips: ComboboxChips,
|
|
7448
|
-
Clear: ComboboxClear,
|
|
7449
|
-
Collection: ComboboxCollection,
|
|
7450
|
-
Empty: ComboboxEmpty,
|
|
7451
|
-
Group: ComboboxGroup,
|
|
7452
|
-
GroupLabel: ComboboxGroupLabel,
|
|
7453
|
-
Icon: ComboboxIcon,
|
|
7454
|
-
Input: ComboboxInput,
|
|
7455
|
-
InputGroup: ComboboxInputGroup,
|
|
7456
|
-
Item: ComboboxItem,
|
|
7457
|
-
ItemIndicator: ComboboxItemIndicator,
|
|
7458
|
-
Label: ComboboxLabel,
|
|
7459
|
-
List: ComboboxList,
|
|
7460
|
-
Popup: ComboboxPopup,
|
|
7461
|
-
Portal: ComboboxPortal,
|
|
7462
|
-
Positioner: ComboboxPositioner,
|
|
7463
|
-
Root: ComboboxRoot,
|
|
7464
|
-
Row: ComboboxRow,
|
|
4092
|
+
Arrow: ComboboxChipRemove.ComboboxArrow,
|
|
4093
|
+
Backdrop: ComboboxChipRemove.ComboboxBackdrop,
|
|
4094
|
+
Chip: ComboboxChipRemove.ComboboxChip,
|
|
4095
|
+
ChipRemove: ComboboxChipRemove.ComboboxChipRemove,
|
|
4096
|
+
Chips: ComboboxChipRemove.ComboboxChips,
|
|
4097
|
+
Clear: ComboboxChipRemove.ComboboxClear,
|
|
4098
|
+
Collection: ComboboxChipRemove.ComboboxCollection,
|
|
4099
|
+
Empty: ComboboxChipRemove.ComboboxEmpty,
|
|
4100
|
+
Group: ComboboxChipRemove.ComboboxGroup,
|
|
4101
|
+
GroupLabel: ComboboxChipRemove.ComboboxGroupLabel,
|
|
4102
|
+
Icon: ComboboxChipRemove.ComboboxIcon,
|
|
4103
|
+
Input: ComboboxChipRemove.ComboboxInput,
|
|
4104
|
+
InputGroup: ComboboxChipRemove.ComboboxInputGroup,
|
|
4105
|
+
Item: ComboboxChipRemove.ComboboxItem,
|
|
4106
|
+
ItemIndicator: ComboboxChipRemove.ComboboxItemIndicator,
|
|
4107
|
+
Label: ComboboxChipRemove.ComboboxLabel,
|
|
4108
|
+
List: ComboboxChipRemove.ComboboxList,
|
|
4109
|
+
Popup: ComboboxChipRemove.ComboboxPopup,
|
|
4110
|
+
Portal: ComboboxChipRemove.ComboboxPortal,
|
|
4111
|
+
Positioner: ComboboxChipRemove.ComboboxPositioner,
|
|
4112
|
+
Root: ComboboxChipRemove.ComboboxRoot,
|
|
4113
|
+
Row: ComboboxChipRemove.ComboboxRow,
|
|
7465
4114
|
Separator: Separator.Separator,
|
|
7466
|
-
Status: ComboboxStatus,
|
|
7467
|
-
Trigger: ComboboxTrigger,
|
|
7468
|
-
Value: ComboboxValue,
|
|
7469
|
-
useFilter: useComboboxFilter,
|
|
7470
|
-
useFilteredItems: useFilteredItems
|
|
4115
|
+
Status: ComboboxChipRemove.ComboboxStatus,
|
|
4116
|
+
Trigger: ComboboxChipRemove.ComboboxTrigger,
|
|
4117
|
+
Value: ComboboxChipRemove.ComboboxValue,
|
|
4118
|
+
useFilter: ComboboxChipRemove.useComboboxFilter,
|
|
4119
|
+
useFilteredItems: ComboboxChipRemove.useFilteredItems
|
|
7471
4120
|
});
|
|
7472
4121
|
|
|
7473
4122
|
const NumberFieldScrubAreaContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
@@ -7559,7 +4208,7 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
7559
4208
|
y: 0
|
|
7560
4209
|
});
|
|
7561
4210
|
const visualScaleRef = React__namespace.useRef(1);
|
|
7562
|
-
const exitPointerLockTimeout =
|
|
4211
|
+
const exitPointerLockTimeout = useButton.useTimeout();
|
|
7563
4212
|
const [isTouchInput, setIsTouchInput] = React__namespace.useState(false);
|
|
7564
4213
|
const [isPointerLockDenied, setIsPointerLockDenied] = React__namespace.useState(false);
|
|
7565
4214
|
const [isScrubbing, setIsScrubbing] = React__namespace.useState(false);
|
|
@@ -7574,7 +4223,7 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
7574
4223
|
scrubAreaCursorRef.current.style.transform = `translate3d(${x}px,${y}px,0) scale(${1 / visualScaleRef.current})`;
|
|
7575
4224
|
}
|
|
7576
4225
|
}
|
|
7577
|
-
const onScrub =
|
|
4226
|
+
const onScrub = useButton.useStableCallback(({
|
|
7578
4227
|
movementX,
|
|
7579
4228
|
movementY
|
|
7580
4229
|
}) => {
|
|
@@ -7604,7 +4253,7 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
7604
4253
|
virtualCursorCoords.current = newCoords;
|
|
7605
4254
|
updateCursorTransform(newCoords.x, newCoords.y);
|
|
7606
4255
|
});
|
|
7607
|
-
const onScrubbingChange =
|
|
4256
|
+
const onScrubbingChange = useButton.useStableCallback((scrubbingValue, {
|
|
7608
4257
|
clientX,
|
|
7609
4258
|
clientY
|
|
7610
4259
|
}) => {
|
|
@@ -7632,13 +4281,13 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
7632
4281
|
function handleScrubPointerUp(event) {
|
|
7633
4282
|
function handler() {
|
|
7634
4283
|
try {
|
|
7635
|
-
|
|
4284
|
+
useButton.ownerDocument(scrubAreaRef.current).exitPointerLock();
|
|
7636
4285
|
} catch {
|
|
7637
4286
|
// Ignore errors.
|
|
7638
4287
|
} finally {
|
|
7639
4288
|
isScrubbingRef.current = false;
|
|
7640
4289
|
onScrubbingChange(false, event);
|
|
7641
|
-
onValueCommitted(lastChangedValueRef.current ?? valueRef.current,
|
|
4290
|
+
onValueCommitted(lastChangedValueRef.current ?? valueRef.current, useButton.createGenericEventDetails(useButton.scrub, event));
|
|
7642
4291
|
|
|
7643
4292
|
// Manually dispatch a click event if no movement happened, since
|
|
7644
4293
|
// preventDefault on pointerdown prevents the browser click event.
|
|
@@ -7652,7 +4301,7 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
7652
4301
|
pointerDownTargetRef.current = null;
|
|
7653
4302
|
}
|
|
7654
4303
|
}
|
|
7655
|
-
if (
|
|
4304
|
+
if (useButton.isFirefox) {
|
|
7656
4305
|
// Firefox needs a small delay here when soft-clicking as the pointer
|
|
7657
4306
|
// lock will not release otherwise.
|
|
7658
4307
|
exitPointerLockTimeout.start(20, handler);
|
|
@@ -7683,7 +4332,7 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
7683
4332
|
incrementValue(Math.abs(rawAmount), {
|
|
7684
4333
|
direction: rawAmount >= 0 ? 1 : -1,
|
|
7685
4334
|
event,
|
|
7686
|
-
reason:
|
|
4335
|
+
reason: useButton.scrub
|
|
7687
4336
|
});
|
|
7688
4337
|
}
|
|
7689
4338
|
}
|
|
@@ -7738,12 +4387,12 @@ const NumberFieldScrubArea = /*#__PURE__*/React__namespace.forwardRef(function N
|
|
|
7738
4387
|
onScrubbingChange(true, event.nativeEvent);
|
|
7739
4388
|
|
|
7740
4389
|
// WebKit causes significant layout shift with the native message, so we can't use it.
|
|
7741
|
-
if (!isTouch && !
|
|
4390
|
+
if (!isTouch && !useButton.isWebKit) {
|
|
7742
4391
|
try {
|
|
7743
4392
|
// Avoid non-deterministic errors in testing environments. This error sometimes
|
|
7744
4393
|
// appears:
|
|
7745
4394
|
// "The root document of this element is not valid for pointer lock."
|
|
7746
|
-
await
|
|
4395
|
+
await useButton.ownerDocument(scrubAreaRef.current).body.requestPointerLock();
|
|
7747
4396
|
setIsPointerLockDenied(false);
|
|
7748
4397
|
} catch (error) {
|
|
7749
4398
|
setIsPointerLockDenied(true);
|
|
@@ -7805,7 +4454,7 @@ const NumberFieldScrubAreaCursor = /*#__PURE__*/React__namespace.forwardRef(func
|
|
|
7805
4454
|
scrubAreaCursorRef
|
|
7806
4455
|
} = useNumberFieldScrubAreaContext();
|
|
7807
4456
|
const [domElement, setDomElement] = React__namespace.useState(null);
|
|
7808
|
-
const shouldRender = isScrubbing && !
|
|
4457
|
+
const shouldRender = isScrubbing && !useButton.isWebKit && !isTouchInput && !isPointerLockDenied;
|
|
7809
4458
|
const element = useRenderElement.useRenderElement('span', componentProps, {
|
|
7810
4459
|
enabled: shouldRender,
|
|
7811
4460
|
ref: [forwardedRef, scrubAreaCursorRef, setDomElement],
|
|
@@ -7821,7 +4470,7 @@ const NumberFieldScrubAreaCursor = /*#__PURE__*/React__namespace.forwardRef(func
|
|
|
7821
4470
|
}, elementProps],
|
|
7822
4471
|
stateAttributesMapping: NumberFieldInput.stateAttributesMapping
|
|
7823
4472
|
});
|
|
7824
|
-
return element && /*#__PURE__*/ReactDOM__namespace.createPortal(element,
|
|
4473
|
+
return element && /*#__PURE__*/ReactDOM__namespace.createPortal(element, useButton.ownerDocument(domElement).body);
|
|
7825
4474
|
});
|
|
7826
4475
|
if (process.env.NODE_ENV !== "production") NumberFieldScrubAreaCursor.displayName = "NumberFieldScrubAreaCursor";
|
|
7827
4476
|
|