@huin-core/react-select 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js ADDED
@@ -0,0 +1,1385 @@
1
+ "use strict";
2
+ "use client";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // packages/react/select/src/index.ts
32
+ var src_exports = {};
33
+ __export(src_exports, {
34
+ Root: () => Root2,
35
+ Select: () => Select,
36
+ SelectArrow: () => SelectArrow,
37
+ SelectContent: () => SelectContent,
38
+ SelectGroup: () => SelectGroup,
39
+ SelectIcon: () => SelectIcon,
40
+ SelectItem: () => SelectItem,
41
+ SelectItemIndicator: () => SelectItemIndicator,
42
+ SelectItemText: () => SelectItemText,
43
+ SelectLabel: () => SelectLabel,
44
+ SelectPortal: () => SelectPortal,
45
+ SelectScrollDownButton: () => SelectScrollDownButton,
46
+ SelectScrollUpButton: () => SelectScrollUpButton,
47
+ SelectSeparator: () => SelectSeparator,
48
+ SelectTrigger: () => SelectTrigger,
49
+ SelectValue: () => SelectValue,
50
+ SelectViewport: () => SelectViewport,
51
+ createSelectScope: () => createSelectScope
52
+ });
53
+ module.exports = __toCommonJS(src_exports);
54
+
55
+ // packages/react/select/src/Select.tsx
56
+ var React = __toESM(require("react"));
57
+ var import_react_collection = require("@huin-core/react-collection");
58
+ var import_react_compose_refs = require("@huin-core/react-compose-refs");
59
+ var import_react_context = require("@huin-core/react-context");
60
+ var import_react_direction = require("@huin-core/react-direction");
61
+ var import_react_id = require("@huin-core/react-id");
62
+ var PopperPrimitive = __toESM(require("@huin-core/react-popper"));
63
+ var import_react_popper = require("@huin-core/react-popper");
64
+ var import_react_use_controllable_state = require("@huin-core/react-use-controllable-state");
65
+ var import_react_use_previous = require("@huin-core/react-use-previous");
66
+ var import_react_visually_hidden = require("@huin-core/react-visually-hidden");
67
+ var import_jsx_runtime = require("react/jsx-runtime");
68
+ var SELECT_NAME = "Select";
69
+ var [Collection, useCollection, createCollectionScope] = (0, import_react_collection.createCollection)(SELECT_NAME);
70
+ var [createSelectContext, createSelectScope] = (0, import_react_context.createContextScope)(
71
+ SELECT_NAME,
72
+ [createCollectionScope, import_react_popper.createPopperScope]
73
+ );
74
+ var usePopperScope = (0, import_react_popper.createPopperScope)();
75
+ var [SelectProvider, useSelectContext] = createSelectContext(SELECT_NAME);
76
+ var [SelectNativeOptionsProvider, useSelectNativeOptionsContext] = createSelectContext(SELECT_NAME);
77
+ var Select = (props) => {
78
+ const {
79
+ __scopeSelect,
80
+ children,
81
+ open: openProp,
82
+ defaultOpen,
83
+ onOpenChange,
84
+ value: valueProp,
85
+ defaultValue,
86
+ onValueChange,
87
+ dir,
88
+ name,
89
+ autoComplete,
90
+ disabled,
91
+ required
92
+ } = props;
93
+ const popperScope = usePopperScope(__scopeSelect);
94
+ const [trigger, setTrigger] = React.useState(
95
+ null
96
+ );
97
+ const [valueNode, setValueNode] = React.useState(
98
+ null
99
+ );
100
+ const [valueNodeHasChildren, setValueNodeHasChildren] = React.useState(false);
101
+ const direction = (0, import_react_direction.useDirection)(dir);
102
+ const [open = false, setOpen] = (0, import_react_use_controllable_state.useControllableState)({
103
+ prop: openProp,
104
+ defaultProp: defaultOpen,
105
+ onChange: onOpenChange
106
+ });
107
+ const [value, setValue] = (0, import_react_use_controllable_state.useControllableState)({
108
+ prop: valueProp,
109
+ defaultProp: defaultValue,
110
+ onChange: onValueChange
111
+ });
112
+ const triggerPointerDownPosRef = React.useRef(null);
113
+ const isFormControl = trigger ? Boolean(trigger.closest("form")) : true;
114
+ const [nativeOptionsSet, setNativeOptionsSet] = React.useState(
115
+ /* @__PURE__ */ new Set()
116
+ );
117
+ const nativeSelectKey = Array.from(nativeOptionsSet).map((option) => option.props.value).join(";");
118
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PopperPrimitive.Root, { ...popperScope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
119
+ SelectProvider,
120
+ {
121
+ required,
122
+ scope: __scopeSelect,
123
+ trigger,
124
+ onTriggerChange: setTrigger,
125
+ valueNode,
126
+ onValueNodeChange: setValueNode,
127
+ valueNodeHasChildren,
128
+ onValueNodeHasChildrenChange: setValueNodeHasChildren,
129
+ contentId: (0, import_react_id.useId)(),
130
+ value,
131
+ onValueChange: setValue,
132
+ open,
133
+ onOpenChange: setOpen,
134
+ dir: direction,
135
+ triggerPointerDownPosRef,
136
+ disabled,
137
+ children: [
138
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Collection.Provider, { scope: __scopeSelect, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
139
+ SelectNativeOptionsProvider,
140
+ {
141
+ scope: props.__scopeSelect,
142
+ onNativeOptionAdd: React.useCallback((option) => {
143
+ setNativeOptionsSet((prev) => new Set(prev).add(option));
144
+ }, []),
145
+ onNativeOptionRemove: React.useCallback((option) => {
146
+ setNativeOptionsSet((prev) => {
147
+ const optionsSet = new Set(prev);
148
+ optionsSet.delete(option);
149
+ return optionsSet;
150
+ });
151
+ }, []),
152
+ children
153
+ }
154
+ ) }),
155
+ isFormControl ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
156
+ BubbleSelect,
157
+ {
158
+ "aria-hidden": true,
159
+ required,
160
+ tabIndex: -1,
161
+ name,
162
+ autoComplete,
163
+ value,
164
+ onChange: (event) => setValue(event.target.value),
165
+ disabled,
166
+ children: [
167
+ value === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "" }) : null,
168
+ Array.from(nativeOptionsSet)
169
+ ]
170
+ },
171
+ nativeSelectKey
172
+ ) : null
173
+ ]
174
+ }
175
+ ) });
176
+ };
177
+ Select.displayName = SELECT_NAME;
178
+ var BubbleSelect = React.forwardRef((props, forwardedRef) => {
179
+ const { value, ...selectProps } = props;
180
+ const ref = React.useRef(null);
181
+ const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref);
182
+ const prevValue = (0, import_react_use_previous.usePrevious)(value);
183
+ React.useEffect(() => {
184
+ const select = ref.current;
185
+ const selectProto = window.HTMLSelectElement.prototype;
186
+ const descriptor = Object.getOwnPropertyDescriptor(
187
+ selectProto,
188
+ "value"
189
+ );
190
+ const setValue = descriptor.set;
191
+ if (prevValue !== value && setValue) {
192
+ const event = new Event("change", { bubbles: true });
193
+ setValue.call(select, value);
194
+ select.dispatchEvent(event);
195
+ }
196
+ }, [prevValue, value]);
197
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_visually_hidden.VisuallyHidden, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { ...selectProps, ref: composedRefs, defaultValue: value }) });
198
+ });
199
+ BubbleSelect.displayName = "BubbleSelect";
200
+ var Root2 = Select;
201
+
202
+ // packages/react/select/src/SelectTrigger.tsx
203
+ var import_react4 = __toESM(require("react"));
204
+ var import_react_primitive4 = require("@huin-core/react-primitive");
205
+ var import_react_compose_refs5 = require("@huin-core/react-compose-refs");
206
+
207
+ // packages/react/select/src/SelectContent.tsx
208
+ var import_react2 = __toESM(require("react"));
209
+ var import_react_use_layout_effect = require("@huin-core/react-use-layout-effect");
210
+ var import_react_dom = __toESM(require("react-dom"));
211
+ var import_react_primitive2 = require("@huin-core/react-primitive");
212
+
213
+ // packages/react/select/src/SelectViewport.tsx
214
+ var import_react = __toESM(require("react"));
215
+ var import_react_primitive = require("@huin-core/react-primitive");
216
+ var import_react_compose_refs2 = require("@huin-core/react-compose-refs");
217
+ var import_primitive = require("@huin-core/primitive");
218
+ var import_jsx_runtime2 = require("react/jsx-runtime");
219
+ var CONTENT_NAME = "SelectContent";
220
+ var [SelectViewportProvider, useSelectViewportContext] = createSelectContext(CONTENT_NAME, {});
221
+ var VIEWPORT_NAME = "SelectViewport";
222
+ var SelectViewport = import_react.default.forwardRef((props, forwardedRef) => {
223
+ const { __scopeSelect, nonce, ...viewportProps } = props;
224
+ const contentContext = useSelectContentContext(VIEWPORT_NAME, __scopeSelect);
225
+ const viewportContext = useSelectViewportContext(
226
+ VIEWPORT_NAME,
227
+ __scopeSelect
228
+ );
229
+ const composedRefs = (0, import_react_compose_refs2.useComposedRefs)(
230
+ forwardedRef,
231
+ contentContext.onViewportChange
232
+ );
233
+ const prevScrollTopRef = import_react.default.useRef(0);
234
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
235
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
236
+ "style",
237
+ {
238
+ dangerouslySetInnerHTML: {
239
+ __html: `[data-huin-core-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-huin-core-select-viewport]::-webkit-scrollbar{display:none}`
240
+ },
241
+ nonce
242
+ }
243
+ ),
244
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Collection.Slot, { scope: __scopeSelect, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
245
+ import_react_primitive.Primitive.div,
246
+ {
247
+ "data-huin-core-select-viewport": "",
248
+ role: "presentation",
249
+ ...viewportProps,
250
+ ref: composedRefs,
251
+ style: {
252
+ // we use position: 'relative' here on the `viewport` so that when we call
253
+ // `selectedItem.offsetTop` in calculations, the offset is relative to the viewport
254
+ // (independent of the scrollUpButton).
255
+ position: "relative",
256
+ flex: 1,
257
+ overflow: "auto",
258
+ ...viewportProps.style
259
+ },
260
+ onScroll: (0, import_primitive.composeEventHandlers)(viewportProps.onScroll, (event) => {
261
+ const viewport = event.currentTarget;
262
+ const { contentWrapper, shouldExpandOnScrollRef } = viewportContext;
263
+ if (shouldExpandOnScrollRef?.current && contentWrapper) {
264
+ const scrolledBy = Math.abs(
265
+ prevScrollTopRef.current - viewport.scrollTop
266
+ );
267
+ if (scrolledBy > 0) {
268
+ const availableHeight = window.innerHeight - CONTENT_MARGIN * 2;
269
+ const cssMinHeight = parseFloat(contentWrapper.style.minHeight);
270
+ const cssHeight = parseFloat(contentWrapper.style.height);
271
+ const prevHeight = Math.max(cssMinHeight, cssHeight);
272
+ if (prevHeight < availableHeight) {
273
+ const nextHeight = prevHeight + scrolledBy;
274
+ const clampedNextHeight = Math.min(
275
+ availableHeight,
276
+ nextHeight
277
+ );
278
+ const heightDiff = nextHeight - clampedNextHeight;
279
+ contentWrapper.style.height = clampedNextHeight + "px";
280
+ if (contentWrapper.style.bottom === "0px") {
281
+ viewport.scrollTop = heightDiff > 0 ? heightDiff : 0;
282
+ contentWrapper.style.justifyContent = "flex-end";
283
+ }
284
+ }
285
+ }
286
+ }
287
+ prevScrollTopRef.current = viewport.scrollTop;
288
+ })
289
+ }
290
+ ) })
291
+ ] });
292
+ });
293
+ SelectViewport.displayName = VIEWPORT_NAME;
294
+
295
+ // packages/react/select/src/SelectContent.tsx
296
+ var import_react_dismissable_layer = require("@huin-core/react-dismissable-layer");
297
+ var import_react_focus_scope = require("@huin-core/react-focus-scope");
298
+ var import_react_compose_refs3 = require("@huin-core/react-compose-refs");
299
+ var import_aria_hidden = require("aria-hidden");
300
+ var import_react_focus_guards = require("@huin-core/react-focus-guards");
301
+ var import_react_remove_scroll = require("react-remove-scroll");
302
+ var import_react_slot = require("@huin-core/react-slot");
303
+ var import_primitive2 = require("@huin-core/primitive");
304
+ var import_number = require("@huin-core/number");
305
+ var PopperPrimitive2 = __toESM(require("@huin-core/react-popper"));
306
+ var import_react_use_callback_ref = require("@huin-core/react-use-callback-ref");
307
+ var import_jsx_runtime3 = require("react/jsx-runtime");
308
+ var CONTENT_NAME2 = "SelectContent";
309
+ var SelectContent = import_react2.default.forwardRef(
310
+ (props, forwardedRef) => {
311
+ const context = useSelectContext(CONTENT_NAME2, props.__scopeSelect);
312
+ const [fragment, setFragment] = import_react2.default.useState();
313
+ (0, import_react_use_layout_effect.useLayoutEffect)(() => {
314
+ setFragment(new DocumentFragment());
315
+ }, []);
316
+ if (!context.open) {
317
+ const frag = fragment;
318
+ return frag ? import_react_dom.default.createPortal(
319
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SelectContentProvider, { scope: props.__scopeSelect, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Collection.Slot, { scope: props.__scopeSelect, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: props.children }) }) }),
320
+ frag
321
+ ) : null;
322
+ }
323
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SelectContentImpl, { ...props, ref: forwardedRef });
324
+ }
325
+ );
326
+ SelectContent.displayName = CONTENT_NAME2;
327
+ var CONTENT_MARGIN = 10;
328
+ var [SelectContentProvider, useSelectContentContext] = createSelectContext(CONTENT_NAME2);
329
+ var CONTENT_IMPL_NAME = "SelectContentImpl";
330
+ var SelectContentImpl = import_react2.default.forwardRef((props, forwardedRef) => {
331
+ const {
332
+ __scopeSelect,
333
+ position = "item-aligned",
334
+ onCloseAutoFocus,
335
+ onEscapeKeyDown,
336
+ onPointerDownOutside,
337
+ //
338
+ // PopperContent props
339
+ side,
340
+ sideOffset,
341
+ align,
342
+ alignOffset,
343
+ arrowPadding,
344
+ collisionBoundary,
345
+ collisionPadding,
346
+ sticky,
347
+ hideWhenDetached,
348
+ avoidCollisions,
349
+ //
350
+ ...contentProps
351
+ } = props;
352
+ const context = useSelectContext(CONTENT_NAME2, __scopeSelect);
353
+ const [content, setContent] = import_react2.default.useState(
354
+ null
355
+ );
356
+ const [viewport, setViewport] = import_react2.default.useState(
357
+ null
358
+ );
359
+ const composedRefs = (0, import_react_compose_refs3.useComposedRefs)(
360
+ forwardedRef,
361
+ (node) => setContent(node)
362
+ );
363
+ const [selectedItem, setSelectedItem] = import_react2.default.useState(null);
364
+ const [selectedItemText, setSelectedItemText] = import_react2.default.useState(null);
365
+ const getItems = useCollection(__scopeSelect);
366
+ const [isPositioned, setIsPositioned] = import_react2.default.useState(false);
367
+ const firstValidItemFoundRef = import_react2.default.useRef(false);
368
+ import_react2.default.useEffect(() => {
369
+ if (content) return (0, import_aria_hidden.hideOthers)(content);
370
+ }, [content]);
371
+ (0, import_react_focus_guards.useFocusGuards)();
372
+ const focusFirst = import_react2.default.useCallback(
373
+ (candidates) => {
374
+ const [firstItem, ...restItems] = getItems().map(
375
+ (item) => item.ref.current
376
+ );
377
+ const [lastItem] = restItems.slice(-1);
378
+ const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
379
+ for (const candidate of candidates) {
380
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
381
+ candidate?.scrollIntoView({ block: "nearest" });
382
+ if (candidate === firstItem && viewport) viewport.scrollTop = 0;
383
+ if (candidate === lastItem && viewport)
384
+ viewport.scrollTop = viewport.scrollHeight;
385
+ candidate?.focus();
386
+ if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
387
+ }
388
+ },
389
+ [getItems, viewport]
390
+ );
391
+ const focusSelectedItem = import_react2.default.useCallback(
392
+ () => focusFirst([selectedItem, content]),
393
+ [focusFirst, selectedItem, content]
394
+ );
395
+ import_react2.default.useEffect(() => {
396
+ if (isPositioned) {
397
+ focusSelectedItem();
398
+ }
399
+ }, [isPositioned, focusSelectedItem]);
400
+ const { onOpenChange, triggerPointerDownPosRef } = context;
401
+ import_react2.default.useEffect(() => {
402
+ if (content) {
403
+ let pointerMoveDelta = { x: 0, y: 0 };
404
+ const handlePointerMove = (event) => {
405
+ pointerMoveDelta = {
406
+ x: Math.abs(
407
+ Math.round(event.pageX) - (triggerPointerDownPosRef.current?.x ?? 0)
408
+ ),
409
+ y: Math.abs(
410
+ Math.round(event.pageY) - (triggerPointerDownPosRef.current?.y ?? 0)
411
+ )
412
+ };
413
+ };
414
+ const handlePointerUp = (event) => {
415
+ if (pointerMoveDelta.x <= 10 && pointerMoveDelta.y <= 10) {
416
+ event.preventDefault();
417
+ } else {
418
+ if (!content.contains(event.target)) {
419
+ onOpenChange(false);
420
+ }
421
+ }
422
+ document.removeEventListener("pointermove", handlePointerMove);
423
+ triggerPointerDownPosRef.current = null;
424
+ };
425
+ if (triggerPointerDownPosRef.current !== null) {
426
+ document.addEventListener("pointermove", handlePointerMove);
427
+ document.addEventListener("pointerup", handlePointerUp, {
428
+ capture: true,
429
+ once: true
430
+ });
431
+ }
432
+ return () => {
433
+ document.removeEventListener("pointermove", handlePointerMove);
434
+ document.removeEventListener("pointerup", handlePointerUp, {
435
+ capture: true
436
+ });
437
+ };
438
+ }
439
+ }, [content, onOpenChange, triggerPointerDownPosRef]);
440
+ import_react2.default.useEffect(() => {
441
+ const close = () => onOpenChange(false);
442
+ window.addEventListener("blur", close);
443
+ window.addEventListener("resize", close);
444
+ return () => {
445
+ window.removeEventListener("blur", close);
446
+ window.removeEventListener("resize", close);
447
+ };
448
+ }, [onOpenChange]);
449
+ const [searchRef, handleTypeaheadSearch] = useTypeaheadSearch((search) => {
450
+ const enabledItems = getItems().filter((item) => !item.disabled);
451
+ const currentItem = enabledItems.find(
452
+ (item) => item.ref.current === document.activeElement
453
+ );
454
+ const nextItem = findNextItem(enabledItems, search, currentItem);
455
+ if (nextItem) {
456
+ setTimeout(() => nextItem.ref.current.focus());
457
+ }
458
+ });
459
+ const itemRefCallback = import_react2.default.useCallback(
460
+ (node, value, disabled) => {
461
+ const isFirstValidItem = !firstValidItemFoundRef.current && !disabled;
462
+ const isSelectedItem = context.value !== void 0 && context.value === value;
463
+ if (isSelectedItem || isFirstValidItem) {
464
+ setSelectedItem(node);
465
+ if (isFirstValidItem) firstValidItemFoundRef.current = true;
466
+ }
467
+ },
468
+ [context.value]
469
+ );
470
+ const handleItemLeave = import_react2.default.useCallback(() => content?.focus(), [content]);
471
+ const itemTextRefCallback = import_react2.default.useCallback(
472
+ (node, value, disabled) => {
473
+ const isFirstValidItem = !firstValidItemFoundRef.current && !disabled;
474
+ const isSelectedItem = context.value !== void 0 && context.value === value;
475
+ if (isSelectedItem || isFirstValidItem) {
476
+ setSelectedItemText(node);
477
+ }
478
+ },
479
+ [context.value]
480
+ );
481
+ const SelectPosition = position === "popper" ? SelectPopperPosition : SelectItemAlignedPosition;
482
+ const popperContentProps = SelectPosition === SelectPopperPosition ? {
483
+ side,
484
+ sideOffset,
485
+ align,
486
+ alignOffset,
487
+ arrowPadding,
488
+ collisionBoundary,
489
+ collisionPadding,
490
+ sticky,
491
+ hideWhenDetached,
492
+ avoidCollisions
493
+ } : {};
494
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
495
+ SelectContentProvider,
496
+ {
497
+ scope: __scopeSelect,
498
+ content,
499
+ viewport,
500
+ onViewportChange: setViewport,
501
+ itemRefCallback,
502
+ selectedItem,
503
+ onItemLeave: handleItemLeave,
504
+ itemTextRefCallback,
505
+ focusSelectedItem,
506
+ selectedItemText,
507
+ position,
508
+ isPositioned,
509
+ searchRef,
510
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_remove_scroll.RemoveScroll, { as: import_react_slot.Slot, allowPinchZoom: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
511
+ import_react_focus_scope.FocusScope,
512
+ {
513
+ asChild: true,
514
+ trapped: context.open,
515
+ onMountAutoFocus: (event) => {
516
+ event.preventDefault();
517
+ },
518
+ onUnmountAutoFocus: (0, import_primitive2.composeEventHandlers)(
519
+ onCloseAutoFocus,
520
+ (event) => {
521
+ context.trigger?.focus({ preventScroll: true });
522
+ event.preventDefault();
523
+ }
524
+ ),
525
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
526
+ import_react_dismissable_layer.DismissableLayer,
527
+ {
528
+ asChild: true,
529
+ disableOutsidePointerEvents: true,
530
+ onEscapeKeyDown,
531
+ onPointerDownOutside,
532
+ onFocusOutside: (event) => event.preventDefault(),
533
+ onDismiss: () => context.onOpenChange(false),
534
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
535
+ SelectPosition,
536
+ {
537
+ role: "listbox",
538
+ id: context.contentId,
539
+ "data-state": context.open ? "open" : "closed",
540
+ dir: context.dir,
541
+ onContextMenu: (event) => event.preventDefault(),
542
+ ...contentProps,
543
+ ...popperContentProps,
544
+ onPlaced: () => setIsPositioned(true),
545
+ ref: composedRefs,
546
+ style: {
547
+ // flex layout so we can place the scroll buttons properly
548
+ display: "flex",
549
+ flexDirection: "column",
550
+ // reset the outline by default as the content MAY get focused
551
+ outline: "none",
552
+ ...contentProps.style
553
+ },
554
+ onKeyDown: (0, import_primitive2.composeEventHandlers)(
555
+ contentProps.onKeyDown,
556
+ (event) => {
557
+ const isModifierKey = event.ctrlKey || event.altKey || event.metaKey;
558
+ if (event.key === "Tab") event.preventDefault();
559
+ if (!isModifierKey && event.key.length === 1)
560
+ handleTypeaheadSearch(event.key);
561
+ if (["ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) {
562
+ const items = getItems().filter((item) => !item.disabled);
563
+ let candidateNodes = items.map((item) => item.ref.current);
564
+ if (["ArrowUp", "End"].includes(event.key)) {
565
+ candidateNodes = candidateNodes.slice().reverse();
566
+ }
567
+ if (["ArrowUp", "ArrowDown"].includes(event.key)) {
568
+ const currentElement = event.target;
569
+ const currentIndex = candidateNodes.indexOf(currentElement);
570
+ candidateNodes = candidateNodes.slice(currentIndex + 1);
571
+ }
572
+ setTimeout(() => focusFirst(candidateNodes));
573
+ event.preventDefault();
574
+ }
575
+ }
576
+ )
577
+ }
578
+ )
579
+ }
580
+ )
581
+ }
582
+ ) })
583
+ }
584
+ );
585
+ });
586
+ SelectContentImpl.displayName = CONTENT_IMPL_NAME;
587
+ var ITEM_ALIGNED_POSITION_NAME = "SelectItemAlignedPosition";
588
+ var SelectItemAlignedPosition = import_react2.default.forwardRef((props, forwardedRef) => {
589
+ const { __scopeSelect, onPlaced, ...popperProps } = props;
590
+ const context = useSelectContext(CONTENT_NAME2, __scopeSelect);
591
+ const contentContext = useSelectContentContext(CONTENT_NAME2, __scopeSelect);
592
+ const [contentWrapper, setContentWrapper] = import_react2.default.useState(null);
593
+ const [content, setContent] = import_react2.default.useState(null);
594
+ const composedRefs = (0, import_react_compose_refs3.useComposedRefs)(
595
+ forwardedRef,
596
+ (node) => setContent(node)
597
+ );
598
+ const getItems = useCollection(__scopeSelect);
599
+ const shouldExpandOnScrollRef = import_react2.default.useRef(false);
600
+ const shouldRepositionRef = import_react2.default.useRef(true);
601
+ const { viewport, selectedItem, selectedItemText, focusSelectedItem } = contentContext;
602
+ const position = import_react2.default.useCallback(() => {
603
+ if (context.trigger && context.valueNode && contentWrapper && content && viewport && selectedItem && selectedItemText) {
604
+ const triggerRect = context.trigger.getBoundingClientRect();
605
+ const contentRect = content.getBoundingClientRect();
606
+ const valueNodeRect = context.valueNode.getBoundingClientRect();
607
+ const itemTextRect = selectedItemText.getBoundingClientRect();
608
+ if (context.dir !== "rtl") {
609
+ const itemTextOffset = itemTextRect.left - contentRect.left;
610
+ const left = valueNodeRect.left - itemTextOffset;
611
+ const leftDelta = triggerRect.left - left;
612
+ const minContentWidth = triggerRect.width + leftDelta;
613
+ const contentWidth = Math.max(minContentWidth, contentRect.width);
614
+ const rightEdge = window.innerWidth - CONTENT_MARGIN;
615
+ const clampedLeft = (0, import_number.clamp)(left, [
616
+ CONTENT_MARGIN,
617
+ rightEdge - contentWidth
618
+ ]);
619
+ contentWrapper.style.minWidth = minContentWidth + "px";
620
+ contentWrapper.style.left = clampedLeft + "px";
621
+ } else {
622
+ const itemTextOffset = contentRect.right - itemTextRect.right;
623
+ const right = window.innerWidth - valueNodeRect.right - itemTextOffset;
624
+ const rightDelta = window.innerWidth - triggerRect.right - right;
625
+ const minContentWidth = triggerRect.width + rightDelta;
626
+ const contentWidth = Math.max(minContentWidth, contentRect.width);
627
+ const leftEdge = window.innerWidth - CONTENT_MARGIN;
628
+ const clampedRight = (0, import_number.clamp)(right, [
629
+ CONTENT_MARGIN,
630
+ leftEdge - contentWidth
631
+ ]);
632
+ contentWrapper.style.minWidth = minContentWidth + "px";
633
+ contentWrapper.style.right = clampedRight + "px";
634
+ }
635
+ const items = getItems();
636
+ const availableHeight = window.innerHeight - CONTENT_MARGIN * 2;
637
+ const itemsHeight = viewport.scrollHeight;
638
+ const contentStyles = window.getComputedStyle(content);
639
+ const contentBorderTopWidth = parseInt(contentStyles.borderTopWidth, 10);
640
+ const contentPaddingTop = parseInt(contentStyles.paddingTop, 10);
641
+ const contentBorderBottomWidth = parseInt(
642
+ contentStyles.borderBottomWidth,
643
+ 10
644
+ );
645
+ const contentPaddingBottom = parseInt(contentStyles.paddingBottom, 10);
646
+ const fullContentHeight = contentBorderTopWidth + contentPaddingTop + itemsHeight + contentPaddingBottom + contentBorderBottomWidth;
647
+ const minContentHeight = Math.min(
648
+ selectedItem.offsetHeight * 5,
649
+ fullContentHeight
650
+ );
651
+ const viewportStyles = window.getComputedStyle(viewport);
652
+ const viewportPaddingTop = parseInt(viewportStyles.paddingTop, 10);
653
+ const viewportPaddingBottom = parseInt(viewportStyles.paddingBottom, 10);
654
+ const topEdgeToTriggerMiddle = triggerRect.top + triggerRect.height / 2 - CONTENT_MARGIN;
655
+ const triggerMiddleToBottomEdge = availableHeight - topEdgeToTriggerMiddle;
656
+ const selectedItemHalfHeight = selectedItem.offsetHeight / 2;
657
+ const itemOffsetMiddle = selectedItem.offsetTop + selectedItemHalfHeight;
658
+ const contentTopToItemMiddle = contentBorderTopWidth + contentPaddingTop + itemOffsetMiddle;
659
+ const itemMiddleToContentBottom = fullContentHeight - contentTopToItemMiddle;
660
+ const willAlignWithoutTopOverflow = contentTopToItemMiddle <= topEdgeToTriggerMiddle;
661
+ if (willAlignWithoutTopOverflow) {
662
+ const isLastItem = selectedItem === items[items.length - 1].ref.current;
663
+ contentWrapper.style.bottom = "0px";
664
+ const viewportOffsetBottom = content.clientHeight - viewport.offsetTop - viewport.offsetHeight;
665
+ const clampedTriggerMiddleToBottomEdge = Math.max(
666
+ triggerMiddleToBottomEdge,
667
+ selectedItemHalfHeight + // viewport might have padding bottom, include it to avoid a scrollable viewport
668
+ (isLastItem ? viewportPaddingBottom : 0) + viewportOffsetBottom + contentBorderBottomWidth
669
+ );
670
+ const height = contentTopToItemMiddle + clampedTriggerMiddleToBottomEdge;
671
+ contentWrapper.style.height = height + "px";
672
+ } else {
673
+ const isFirstItem = selectedItem === items[0].ref.current;
674
+ contentWrapper.style.top = "0px";
675
+ const clampedTopEdgeToTriggerMiddle = Math.max(
676
+ topEdgeToTriggerMiddle,
677
+ contentBorderTopWidth + viewport.offsetTop + // viewport might have padding top, include it to avoid a scrollable viewport
678
+ (isFirstItem ? viewportPaddingTop : 0) + selectedItemHalfHeight
679
+ );
680
+ const height = clampedTopEdgeToTriggerMiddle + itemMiddleToContentBottom;
681
+ contentWrapper.style.height = height + "px";
682
+ viewport.scrollTop = contentTopToItemMiddle - topEdgeToTriggerMiddle + viewport.offsetTop;
683
+ }
684
+ contentWrapper.style.margin = `${CONTENT_MARGIN}px 0`;
685
+ contentWrapper.style.minHeight = minContentHeight + "px";
686
+ contentWrapper.style.maxHeight = availableHeight + "px";
687
+ onPlaced?.();
688
+ requestAnimationFrame(() => shouldExpandOnScrollRef.current = true);
689
+ }
690
+ }, [
691
+ getItems,
692
+ context.trigger,
693
+ context.valueNode,
694
+ contentWrapper,
695
+ content,
696
+ viewport,
697
+ selectedItem,
698
+ selectedItemText,
699
+ context.dir,
700
+ onPlaced
701
+ ]);
702
+ (0, import_react_use_layout_effect.useLayoutEffect)(() => position(), [position]);
703
+ const [contentZIndex, setContentZIndex] = import_react2.default.useState();
704
+ (0, import_react_use_layout_effect.useLayoutEffect)(() => {
705
+ if (content) setContentZIndex(window.getComputedStyle(content).zIndex);
706
+ }, [content]);
707
+ const handleScrollButtonChange = import_react2.default.useCallback(
708
+ (node) => {
709
+ if (node && shouldRepositionRef.current === true) {
710
+ position();
711
+ focusSelectedItem?.();
712
+ shouldRepositionRef.current = false;
713
+ }
714
+ },
715
+ [position, focusSelectedItem]
716
+ );
717
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
718
+ SelectViewportProvider,
719
+ {
720
+ scope: __scopeSelect,
721
+ contentWrapper,
722
+ shouldExpandOnScrollRef,
723
+ onScrollButtonChange: handleScrollButtonChange,
724
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
725
+ "div",
726
+ {
727
+ ref: setContentWrapper,
728
+ style: {
729
+ display: "flex",
730
+ flexDirection: "column",
731
+ position: "fixed",
732
+ zIndex: contentZIndex
733
+ },
734
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
735
+ import_react_primitive2.Primitive.div,
736
+ {
737
+ ...popperProps,
738
+ ref: composedRefs,
739
+ style: {
740
+ // When we get the height of the content, it includes borders. If we were to set
741
+ // the height without having `boxSizing: 'border-box'` it would be too big.
742
+ boxSizing: "border-box",
743
+ // We need to ensure the content doesn't get taller than the wrapper
744
+ maxHeight: "100%",
745
+ ...popperProps.style
746
+ }
747
+ }
748
+ )
749
+ }
750
+ )
751
+ }
752
+ );
753
+ });
754
+ SelectItemAlignedPosition.displayName = ITEM_ALIGNED_POSITION_NAME;
755
+ var POPPER_POSITION_NAME = "SelectPopperPosition";
756
+ var SelectPopperPosition = import_react2.default.forwardRef((props, forwardedRef) => {
757
+ const {
758
+ __scopeSelect,
759
+ align = "start",
760
+ collisionPadding = CONTENT_MARGIN,
761
+ ...popperProps
762
+ } = props;
763
+ const popperScope = usePopperScope(__scopeSelect);
764
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
765
+ PopperPrimitive2.Content,
766
+ {
767
+ ...popperScope,
768
+ ...popperProps,
769
+ ref: forwardedRef,
770
+ align,
771
+ collisionPadding,
772
+ style: {
773
+ // Ensure border-box for floating-ui calculations
774
+ boxSizing: "border-box",
775
+ ...popperProps.style,
776
+ // re-namespace exposed content custom properties
777
+ ...{
778
+ "--huin-core-select-content-transform-origin": "var(--huin-core-popper-transform-origin)",
779
+ "--huin-core-select-content-available-width": "var(--huin-core-popper-available-width)",
780
+ "--huin-core-select-content-available-height": "var(--huin-core-popper-available-height)",
781
+ "--huin-core-select-trigger-width": "var(--huin-core-popper-anchor-width)",
782
+ "--huin-core-select-trigger-height": "var(--huin-core-popper-anchor-height)"
783
+ }
784
+ }
785
+ }
786
+ );
787
+ });
788
+ SelectPopperPosition.displayName = POPPER_POSITION_NAME;
789
+ function useTypeaheadSearch(onSearchChange) {
790
+ const handleSearchChange = (0, import_react_use_callback_ref.useCallbackRef)(onSearchChange);
791
+ const searchRef = import_react2.default.useRef("");
792
+ const timerRef = import_react2.default.useRef(0);
793
+ const handleTypeaheadSearch = import_react2.default.useCallback(
794
+ (key) => {
795
+ const search = searchRef.current + key;
796
+ handleSearchChange(search);
797
+ (function updateSearch(value) {
798
+ searchRef.current = value;
799
+ window.clearTimeout(timerRef.current);
800
+ if (value !== "")
801
+ timerRef.current = window.setTimeout(() => updateSearch(""), 1e3);
802
+ })(search);
803
+ },
804
+ [handleSearchChange]
805
+ );
806
+ const resetTypeahead = import_react2.default.useCallback(() => {
807
+ searchRef.current = "";
808
+ window.clearTimeout(timerRef.current);
809
+ }, []);
810
+ import_react2.default.useEffect(() => {
811
+ return () => window.clearTimeout(timerRef.current);
812
+ }, []);
813
+ return [searchRef, handleTypeaheadSearch, resetTypeahead];
814
+ }
815
+ function findNextItem(items, search, currentItem) {
816
+ const isRepeated = search.length > 1 && Array.from(search).every((char) => char === search[0]);
817
+ const normalizedSearch = isRepeated ? search[0] : search;
818
+ const currentItemIndex = currentItem ? items.indexOf(currentItem) : -1;
819
+ let wrappedItems = wrapArray(items, Math.max(currentItemIndex, 0));
820
+ const excludeCurrentItem = normalizedSearch.length === 1;
821
+ if (excludeCurrentItem)
822
+ wrappedItems = wrappedItems.filter((v) => v !== currentItem);
823
+ const nextItem = wrappedItems.find(
824
+ (item) => item.textValue.toLowerCase().startsWith(normalizedSearch.toLowerCase())
825
+ );
826
+ return nextItem !== currentItem ? nextItem : void 0;
827
+ }
828
+ function wrapArray(array, startIndex) {
829
+ return array.map((_, index) => array[(startIndex + index) % array.length]);
830
+ }
831
+
832
+ // packages/react/select/src/SelectTrigger.tsx
833
+ var PopperPrimitive3 = __toESM(require("@huin-core/react-popper"));
834
+
835
+ // packages/react/select/src/SelectValue.tsx
836
+ var import_react3 = __toESM(require("react"));
837
+ var import_react_primitive3 = require("@huin-core/react-primitive");
838
+ var import_react_compose_refs4 = require("@huin-core/react-compose-refs");
839
+ var import_react_use_layout_effect2 = require("@huin-core/react-use-layout-effect");
840
+ var import_jsx_runtime4 = require("react/jsx-runtime");
841
+ var VALUE_NAME = "SelectValue";
842
+ var SelectValue = import_react3.default.forwardRef(
843
+ (props, forwardedRef) => {
844
+ const { __scopeSelect, className, style, children, placeholder = "", ...valueProps } = props;
845
+ const context = useSelectContext(VALUE_NAME, __scopeSelect);
846
+ const { onValueNodeHasChildrenChange } = context;
847
+ const hasChildren = children !== void 0;
848
+ const composedRefs = (0, import_react_compose_refs4.useComposedRefs)(
849
+ forwardedRef,
850
+ context.onValueNodeChange
851
+ );
852
+ (0, import_react_use_layout_effect2.useLayoutEffect)(() => {
853
+ onValueNodeHasChildrenChange(hasChildren);
854
+ }, [onValueNodeHasChildrenChange, hasChildren]);
855
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
856
+ import_react_primitive3.Primitive.span,
857
+ {
858
+ ...valueProps,
859
+ ref: composedRefs,
860
+ style: { pointerEvents: "none" },
861
+ children: shouldShowPlaceholder(context.value) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: placeholder }) : children
862
+ }
863
+ );
864
+ }
865
+ );
866
+ SelectValue.displayName = VALUE_NAME;
867
+ function shouldShowPlaceholder(value) {
868
+ return value === "" || value === void 0;
869
+ }
870
+
871
+ // packages/react/select/src/SelectTrigger.tsx
872
+ var import_primitive3 = require("@huin-core/primitive");
873
+ var import_jsx_runtime5 = require("react/jsx-runtime");
874
+ var OPEN_KEYS = [" ", "Enter", "ArrowUp", "ArrowDown"];
875
+ var TRIGGER_NAME = "SelectTrigger";
876
+ var SelectTrigger = import_react4.default.forwardRef((props, forwardedRef) => {
877
+ const { __scopeSelect, disabled = false, ...triggerProps } = props;
878
+ const popperScope = usePopperScope(__scopeSelect);
879
+ const context = useSelectContext(TRIGGER_NAME, __scopeSelect);
880
+ const isDisabled = context.disabled || disabled;
881
+ const composedRefs = (0, import_react_compose_refs5.useComposedRefs)(forwardedRef, context.onTriggerChange);
882
+ const getItems = useCollection(__scopeSelect);
883
+ const pointerTypeRef = import_react4.default.useRef("touch");
884
+ const [searchRef, handleTypeaheadSearch, resetTypeahead] = useTypeaheadSearch(
885
+ (search) => {
886
+ const enabledItems = getItems().filter((item) => !item.disabled);
887
+ const currentItem = enabledItems.find(
888
+ (item) => item.value === context.value
889
+ );
890
+ const nextItem = findNextItem(enabledItems, search, currentItem);
891
+ if (nextItem !== void 0) {
892
+ context.onValueChange(nextItem.value);
893
+ }
894
+ }
895
+ );
896
+ const handleOpen = (pointerEvent) => {
897
+ if (!isDisabled) {
898
+ context.onOpenChange(true);
899
+ resetTypeahead();
900
+ }
901
+ if (pointerEvent) {
902
+ context.triggerPointerDownPosRef.current = {
903
+ x: Math.round(pointerEvent.pageX),
904
+ y: Math.round(pointerEvent.pageY)
905
+ };
906
+ }
907
+ };
908
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PopperPrimitive3.Anchor, { asChild: true, ...popperScope, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
909
+ import_react_primitive4.Primitive.button,
910
+ {
911
+ type: "button",
912
+ role: "combobox",
913
+ "aria-controls": context.contentId,
914
+ "aria-expanded": context.open,
915
+ "aria-required": context.required,
916
+ "aria-autocomplete": "none",
917
+ dir: context.dir,
918
+ "data-state": context.open ? "open" : "closed",
919
+ disabled: isDisabled,
920
+ "data-disabled": isDisabled ? "" : void 0,
921
+ "data-placeholder": shouldShowPlaceholder(context.value) ? "" : void 0,
922
+ ...triggerProps,
923
+ ref: composedRefs,
924
+ onClick: (0, import_primitive3.composeEventHandlers)(triggerProps.onClick, (event) => {
925
+ event.currentTarget.focus();
926
+ if (pointerTypeRef.current !== "mouse") {
927
+ handleOpen(event);
928
+ }
929
+ }),
930
+ onPointerDown: (0, import_primitive3.composeEventHandlers)(triggerProps.onPointerDown, (event) => {
931
+ pointerTypeRef.current = event.pointerType;
932
+ const target = event.target;
933
+ if (target.hasPointerCapture(event.pointerId)) {
934
+ target.releasePointerCapture(event.pointerId);
935
+ }
936
+ if (event.button === 0 && event.ctrlKey === false && event.pointerType === "mouse") {
937
+ handleOpen(event);
938
+ event.preventDefault();
939
+ }
940
+ }),
941
+ onKeyDown: (0, import_primitive3.composeEventHandlers)(triggerProps.onKeyDown, (event) => {
942
+ const isTypingAhead = searchRef.current !== "";
943
+ const isModifierKey = event.ctrlKey || event.altKey || event.metaKey;
944
+ if (!isModifierKey && event.key.length === 1) handleTypeaheadSearch(event.key);
945
+ if (isTypingAhead && event.key === " ") return;
946
+ if (OPEN_KEYS.includes(event.key)) {
947
+ handleOpen();
948
+ event.preventDefault();
949
+ }
950
+ })
951
+ }
952
+ ) });
953
+ });
954
+ SelectTrigger.displayName = TRIGGER_NAME;
955
+
956
+ // packages/react/select/src/SelectIcon.tsx
957
+ var import_react5 = __toESM(require("react"));
958
+ var import_react_primitive5 = require("@huin-core/react-primitive");
959
+ var import_jsx_runtime6 = require("react/jsx-runtime");
960
+ var ICON_NAME = "SelectIcon";
961
+ var SelectIcon = import_react5.default.forwardRef(
962
+ (props, forwardedRef) => {
963
+ const { __scopeSelect, children, ...iconProps } = props;
964
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_primitive5.Primitive.span, { "aria-hidden": true, ...iconProps, ref: forwardedRef, children: children || "\u25BC" });
965
+ }
966
+ );
967
+ SelectIcon.displayName = ICON_NAME;
968
+
969
+ // packages/react/select/src/SelectPortal.tsx
970
+ var import_react_portal = require("@huin-core/react-portal");
971
+ var import_jsx_runtime7 = require("react/jsx-runtime");
972
+ var PORTAL_NAME = "SelectPortal";
973
+ var SelectPortal = (props) => {
974
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_portal.Portal, { asChild: true, ...props });
975
+ };
976
+ SelectPortal.displayName = PORTAL_NAME;
977
+
978
+ // packages/react/select/src/SelectGroup.tsx
979
+ var import_react6 = __toESM(require("react"));
980
+ var import_react_primitive6 = require("@huin-core/react-primitive");
981
+ var import_react_id2 = require("@huin-core/react-id");
982
+ var import_jsx_runtime8 = require("react/jsx-runtime");
983
+ var GROUP_NAME = "SelectGroup";
984
+ var [SelectGroupContextProvider, useSelectGroupContext] = createSelectContext(GROUP_NAME);
985
+ var SelectGroup = import_react6.default.forwardRef(
986
+ (props, forwardedRef) => {
987
+ const { __scopeSelect, ...groupProps } = props;
988
+ const groupId = (0, import_react_id2.useId)();
989
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectGroupContextProvider, { scope: __scopeSelect, id: groupId, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
990
+ import_react_primitive6.Primitive.div,
991
+ {
992
+ role: "group",
993
+ "aria-labelledby": groupId,
994
+ ...groupProps,
995
+ ref: forwardedRef
996
+ }
997
+ ) });
998
+ }
999
+ );
1000
+ SelectGroup.displayName = GROUP_NAME;
1001
+
1002
+ // packages/react/select/src/SelectLabel.tsx
1003
+ var import_react7 = __toESM(require("react"));
1004
+ var import_react_primitive7 = require("@huin-core/react-primitive");
1005
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1006
+ var LABEL_NAME = "SelectLabel";
1007
+ var SelectLabel = import_react7.default.forwardRef(
1008
+ (props, forwardedRef) => {
1009
+ const { __scopeSelect, ...labelProps } = props;
1010
+ const groupContext = useSelectGroupContext(LABEL_NAME, __scopeSelect);
1011
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_primitive7.Primitive.div, { id: groupContext.id, ...labelProps, ref: forwardedRef });
1012
+ }
1013
+ );
1014
+ SelectLabel.displayName = LABEL_NAME;
1015
+
1016
+ // packages/react/select/src/SelectItem.tsx
1017
+ var import_react8 = __toESM(require("react"));
1018
+ var import_react_primitive8 = require("@huin-core/react-primitive");
1019
+ var import_react_compose_refs6 = require("@huin-core/react-compose-refs");
1020
+ var import_react_id3 = require("@huin-core/react-id");
1021
+ var import_primitive4 = require("@huin-core/primitive");
1022
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1023
+ var SELECTION_KEYS = [" ", "Enter"];
1024
+ var ITEM_NAME = "SelectItem";
1025
+ var [SelectItemContextProvider, useSelectItemContext] = createSelectContext(ITEM_NAME);
1026
+ var SelectItem = import_react8.default.forwardRef(
1027
+ (props, forwardedRef) => {
1028
+ const {
1029
+ __scopeSelect,
1030
+ value,
1031
+ disabled = false,
1032
+ textValue: textValueProp,
1033
+ ...itemProps
1034
+ } = props;
1035
+ const context = useSelectContext(ITEM_NAME, __scopeSelect);
1036
+ const contentContext = useSelectContentContext(ITEM_NAME, __scopeSelect);
1037
+ const isSelected = context.value === value;
1038
+ const [textValue, setTextValue] = import_react8.default.useState(textValueProp ?? "");
1039
+ const [isFocused, setIsFocused] = import_react8.default.useState(false);
1040
+ const composedRefs = (0, import_react_compose_refs6.useComposedRefs)(
1041
+ forwardedRef,
1042
+ (node) => contentContext.itemRefCallback?.(node, value, disabled)
1043
+ );
1044
+ const textId = (0, import_react_id3.useId)();
1045
+ const pointerTypeRef = import_react8.default.useRef("touch");
1046
+ const handleSelect = () => {
1047
+ if (!disabled) {
1048
+ context.onValueChange(value);
1049
+ context.onOpenChange(false);
1050
+ }
1051
+ };
1052
+ if (value === "") {
1053
+ throw new Error(
1054
+ "A <Select.Item /> must have a value prop that is not an empty string. This is because the Select value can be set to an empty string to clear the selection and show the placeholder."
1055
+ );
1056
+ }
1057
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1058
+ SelectItemContextProvider,
1059
+ {
1060
+ scope: __scopeSelect,
1061
+ value,
1062
+ disabled,
1063
+ textId,
1064
+ isSelected,
1065
+ onItemTextChange: import_react8.default.useCallback((node) => {
1066
+ setTextValue((prevTextValue) => prevTextValue || (node?.textContent ?? "").trim());
1067
+ }, []),
1068
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1069
+ Collection.ItemSlot,
1070
+ {
1071
+ scope: __scopeSelect,
1072
+ value,
1073
+ disabled,
1074
+ textValue,
1075
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1076
+ import_react_primitive8.Primitive.div,
1077
+ {
1078
+ role: "option",
1079
+ "aria-labelledby": textId,
1080
+ "data-highlighted": isFocused ? "" : void 0,
1081
+ "aria-selected": isSelected && isFocused,
1082
+ "data-state": isSelected ? "checked" : "unchecked",
1083
+ "aria-disabled": disabled || void 0,
1084
+ "data-disabled": disabled ? "" : void 0,
1085
+ tabIndex: disabled ? void 0 : -1,
1086
+ ...itemProps,
1087
+ ref: composedRefs,
1088
+ onFocus: (0, import_primitive4.composeEventHandlers)(itemProps.onFocus, () => setIsFocused(true)),
1089
+ onBlur: (0, import_primitive4.composeEventHandlers)(itemProps.onBlur, () => setIsFocused(false)),
1090
+ onClick: (0, import_primitive4.composeEventHandlers)(itemProps.onClick, () => {
1091
+ if (pointerTypeRef.current !== "mouse") handleSelect();
1092
+ }),
1093
+ onPointerUp: (0, import_primitive4.composeEventHandlers)(itemProps.onPointerUp, () => {
1094
+ if (pointerTypeRef.current === "mouse") handleSelect();
1095
+ }),
1096
+ onPointerDown: (0, import_primitive4.composeEventHandlers)(itemProps.onPointerDown, (event) => {
1097
+ pointerTypeRef.current = event.pointerType;
1098
+ }),
1099
+ onPointerMove: (0, import_primitive4.composeEventHandlers)(itemProps.onPointerMove, (event) => {
1100
+ pointerTypeRef.current = event.pointerType;
1101
+ if (disabled) {
1102
+ contentContext.onItemLeave?.();
1103
+ } else if (pointerTypeRef.current === "mouse") {
1104
+ event.currentTarget.focus({ preventScroll: true });
1105
+ }
1106
+ }),
1107
+ onPointerLeave: (0, import_primitive4.composeEventHandlers)(itemProps.onPointerLeave, (event) => {
1108
+ if (event.currentTarget === document.activeElement) {
1109
+ contentContext.onItemLeave?.();
1110
+ }
1111
+ }),
1112
+ onKeyDown: (0, import_primitive4.composeEventHandlers)(itemProps.onKeyDown, (event) => {
1113
+ const isTypingAhead = contentContext.searchRef?.current !== "";
1114
+ if (isTypingAhead && event.key === " ") return;
1115
+ if (SELECTION_KEYS.includes(event.key)) handleSelect();
1116
+ if (event.key === " ") event.preventDefault();
1117
+ })
1118
+ }
1119
+ )
1120
+ }
1121
+ )
1122
+ }
1123
+ );
1124
+ }
1125
+ );
1126
+ SelectItem.displayName = ITEM_NAME;
1127
+
1128
+ // packages/react/select/src/SelectItemText.tsx
1129
+ var import_react9 = __toESM(require("react"));
1130
+ var import_react_primitive9 = require("@huin-core/react-primitive");
1131
+ var import_react_compose_refs7 = require("@huin-core/react-compose-refs");
1132
+ var import_react_use_layout_effect3 = require("@huin-core/react-use-layout-effect");
1133
+ var import_react_dom2 = __toESM(require("react-dom"));
1134
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1135
+ var ITEM_TEXT_NAME = "SelectItemText";
1136
+ var SelectItemText = import_react9.default.forwardRef((props, forwardedRef) => {
1137
+ const { __scopeSelect, className, style, ...itemTextProps } = props;
1138
+ const context = useSelectContext(ITEM_TEXT_NAME, __scopeSelect);
1139
+ const contentContext = useSelectContentContext(ITEM_TEXT_NAME, __scopeSelect);
1140
+ const itemContext = useSelectItemContext(ITEM_TEXT_NAME, __scopeSelect);
1141
+ const nativeOptionsContext = useSelectNativeOptionsContext(
1142
+ ITEM_TEXT_NAME,
1143
+ __scopeSelect
1144
+ );
1145
+ const [itemTextNode, setItemTextNode] = import_react9.default.useState(null);
1146
+ const composedRefs = (0, import_react_compose_refs7.useComposedRefs)(
1147
+ forwardedRef,
1148
+ (node) => setItemTextNode(node),
1149
+ itemContext.onItemTextChange,
1150
+ (node) => contentContext.itemTextRefCallback?.(
1151
+ node,
1152
+ itemContext.value,
1153
+ itemContext.disabled
1154
+ )
1155
+ );
1156
+ const textContent = itemTextNode?.textContent;
1157
+ const nativeOption = import_react9.default.useMemo(
1158
+ () => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1159
+ "option",
1160
+ {
1161
+ value: itemContext.value,
1162
+ disabled: itemContext.disabled,
1163
+ children: textContent
1164
+ },
1165
+ itemContext.value
1166
+ ),
1167
+ [itemContext.disabled, itemContext.value, textContent]
1168
+ );
1169
+ const { onNativeOptionAdd, onNativeOptionRemove } = nativeOptionsContext;
1170
+ (0, import_react_use_layout_effect3.useLayoutEffect)(() => {
1171
+ onNativeOptionAdd(nativeOption);
1172
+ return () => onNativeOptionRemove(nativeOption);
1173
+ }, [onNativeOptionAdd, onNativeOptionRemove, nativeOption]);
1174
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1175
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_primitive9.Primitive.span, { id: itemContext.textId, ...itemTextProps, ref: composedRefs }),
1176
+ itemContext.isSelected && context.valueNode && !context.valueNodeHasChildren ? import_react_dom2.default.createPortal(itemTextProps.children, context.valueNode) : null
1177
+ ] });
1178
+ });
1179
+ SelectItemText.displayName = ITEM_TEXT_NAME;
1180
+
1181
+ // packages/react/select/src/SelectItemIndicator.tsx
1182
+ var import_react10 = __toESM(require("react"));
1183
+ var import_react_primitive10 = require("@huin-core/react-primitive");
1184
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1185
+ var ITEM_INDICATOR_NAME = "SelectItemIndicator";
1186
+ var SelectItemIndicator = import_react10.default.forwardRef((props, forwardedRef) => {
1187
+ const { __scopeSelect, ...itemIndicatorProps } = props;
1188
+ const itemContext = useSelectItemContext(ITEM_INDICATOR_NAME, __scopeSelect);
1189
+ return itemContext.isSelected ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_primitive10.Primitive.span, { "aria-hidden": true, ...itemIndicatorProps, ref: forwardedRef }) : null;
1190
+ });
1191
+ SelectItemIndicator.displayName = ITEM_INDICATOR_NAME;
1192
+
1193
+ // packages/react/select/src/SelectScrollUpButton.tsx
1194
+ var import_react12 = __toESM(require("react"));
1195
+
1196
+ // packages/react/select/src/SelectScrollDownButton.tsx
1197
+ var import_react11 = __toESM(require("react"));
1198
+ var import_react_compose_refs8 = require("@huin-core/react-compose-refs");
1199
+ var import_react_use_layout_effect4 = require("@huin-core/react-use-layout-effect");
1200
+ var import_react_primitive11 = require("@huin-core/react-primitive");
1201
+ var import_primitive5 = require("@huin-core/primitive");
1202
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1203
+ var SCROLL_DOWN_BUTTON_NAME = "SelectScrollDownButton";
1204
+ var SelectScrollDownButton = import_react11.default.forwardRef((props, forwardedRef) => {
1205
+ const contentContext = useSelectContentContext(
1206
+ SCROLL_DOWN_BUTTON_NAME,
1207
+ props.__scopeSelect
1208
+ );
1209
+ const viewportContext = useSelectViewportContext(
1210
+ SCROLL_DOWN_BUTTON_NAME,
1211
+ props.__scopeSelect
1212
+ );
1213
+ const [canScrollDown, setCanScrollDown] = import_react11.default.useState(false);
1214
+ const composedRefs = (0, import_react_compose_refs8.useComposedRefs)(
1215
+ forwardedRef,
1216
+ viewportContext.onScrollButtonChange
1217
+ );
1218
+ (0, import_react_use_layout_effect4.useLayoutEffect)(() => {
1219
+ if (contentContext.viewport && contentContext.isPositioned) {
1220
+ let handleScroll2 = function() {
1221
+ const maxScroll = viewport.scrollHeight - viewport.clientHeight;
1222
+ const canScrollDown2 = Math.ceil(viewport.scrollTop) < maxScroll;
1223
+ setCanScrollDown(canScrollDown2);
1224
+ };
1225
+ var handleScroll = handleScroll2;
1226
+ const viewport = contentContext.viewport;
1227
+ handleScroll2();
1228
+ viewport.addEventListener("scroll", handleScroll2);
1229
+ return () => viewport.removeEventListener("scroll", handleScroll2);
1230
+ }
1231
+ }, [contentContext.viewport, contentContext.isPositioned]);
1232
+ return canScrollDown ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1233
+ SelectScrollButtonImpl,
1234
+ {
1235
+ ...props,
1236
+ ref: composedRefs,
1237
+ onAutoScroll: () => {
1238
+ const { viewport, selectedItem } = contentContext;
1239
+ if (viewport && selectedItem) {
1240
+ viewport.scrollTop = viewport.scrollTop + selectedItem.offsetHeight;
1241
+ }
1242
+ }
1243
+ }
1244
+ ) : null;
1245
+ });
1246
+ SelectScrollDownButton.displayName = SCROLL_DOWN_BUTTON_NAME;
1247
+ var SelectScrollButtonImpl = import_react11.default.forwardRef((props, forwardedRef) => {
1248
+ const { __scopeSelect, onAutoScroll, ...scrollIndicatorProps } = props;
1249
+ const contentContext = useSelectContentContext(
1250
+ "SelectScrollButton",
1251
+ __scopeSelect
1252
+ );
1253
+ const autoScrollTimerRef = import_react11.default.useRef(null);
1254
+ const getItems = useCollection(__scopeSelect);
1255
+ const clearAutoScrollTimer = import_react11.default.useCallback(() => {
1256
+ if (autoScrollTimerRef.current !== null) {
1257
+ window.clearInterval(autoScrollTimerRef.current);
1258
+ autoScrollTimerRef.current = null;
1259
+ }
1260
+ }, []);
1261
+ import_react11.default.useEffect(() => {
1262
+ return () => clearAutoScrollTimer();
1263
+ }, [clearAutoScrollTimer]);
1264
+ (0, import_react_use_layout_effect4.useLayoutEffect)(() => {
1265
+ const activeItem = getItems().find(
1266
+ (item) => item.ref.current === document.activeElement
1267
+ );
1268
+ activeItem?.ref.current?.scrollIntoView({ block: "nearest" });
1269
+ }, [getItems]);
1270
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1271
+ import_react_primitive11.Primitive.div,
1272
+ {
1273
+ "aria-hidden": true,
1274
+ ...scrollIndicatorProps,
1275
+ ref: forwardedRef,
1276
+ style: { flexShrink: 0, ...scrollIndicatorProps.style },
1277
+ onPointerDown: (0, import_primitive5.composeEventHandlers)(
1278
+ scrollIndicatorProps.onPointerDown,
1279
+ () => {
1280
+ if (autoScrollTimerRef.current === null) {
1281
+ autoScrollTimerRef.current = window.setInterval(onAutoScroll, 50);
1282
+ }
1283
+ }
1284
+ ),
1285
+ onPointerMove: (0, import_primitive5.composeEventHandlers)(
1286
+ scrollIndicatorProps.onPointerMove,
1287
+ () => {
1288
+ contentContext.onItemLeave?.();
1289
+ if (autoScrollTimerRef.current === null) {
1290
+ autoScrollTimerRef.current = window.setInterval(onAutoScroll, 50);
1291
+ }
1292
+ }
1293
+ ),
1294
+ onPointerLeave: (0, import_primitive5.composeEventHandlers)(
1295
+ scrollIndicatorProps.onPointerLeave,
1296
+ () => {
1297
+ clearAutoScrollTimer();
1298
+ }
1299
+ )
1300
+ }
1301
+ );
1302
+ });
1303
+
1304
+ // packages/react/select/src/SelectScrollUpButton.tsx
1305
+ var import_react_compose_refs9 = require("@huin-core/react-compose-refs");
1306
+ var import_react_use_layout_effect5 = require("@huin-core/react-use-layout-effect");
1307
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1308
+ var SCROLL_UP_BUTTON_NAME = "SelectScrollUpButton";
1309
+ var SelectScrollUpButton = import_react12.default.forwardRef((props, forwardedRef) => {
1310
+ const contentContext = useSelectContentContext(
1311
+ SCROLL_UP_BUTTON_NAME,
1312
+ props.__scopeSelect
1313
+ );
1314
+ const viewportContext = useSelectViewportContext(
1315
+ SCROLL_UP_BUTTON_NAME,
1316
+ props.__scopeSelect
1317
+ );
1318
+ const [canScrollUp, setCanScrollUp] = import_react12.default.useState(false);
1319
+ const composedRefs = (0, import_react_compose_refs9.useComposedRefs)(
1320
+ forwardedRef,
1321
+ viewportContext.onScrollButtonChange
1322
+ );
1323
+ (0, import_react_use_layout_effect5.useLayoutEffect)(() => {
1324
+ if (contentContext.viewport && contentContext.isPositioned) {
1325
+ let handleScroll2 = function() {
1326
+ const canScrollUp2 = viewport.scrollTop > 0;
1327
+ setCanScrollUp(canScrollUp2);
1328
+ };
1329
+ var handleScroll = handleScroll2;
1330
+ const viewport = contentContext.viewport;
1331
+ handleScroll2();
1332
+ viewport.addEventListener("scroll", handleScroll2);
1333
+ return () => viewport.removeEventListener("scroll", handleScroll2);
1334
+ }
1335
+ }, [contentContext.viewport, contentContext.isPositioned]);
1336
+ return canScrollUp ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1337
+ SelectScrollButtonImpl,
1338
+ {
1339
+ ...props,
1340
+ ref: composedRefs,
1341
+ onAutoScroll: () => {
1342
+ const { viewport, selectedItem } = contentContext;
1343
+ if (viewport && selectedItem) {
1344
+ viewport.scrollTop = viewport.scrollTop - selectedItem.offsetHeight;
1345
+ }
1346
+ }
1347
+ }
1348
+ ) : null;
1349
+ });
1350
+ SelectScrollUpButton.displayName = SCROLL_UP_BUTTON_NAME;
1351
+
1352
+ // packages/react/select/src/SelectSeparator.tsx
1353
+ var import_react13 = __toESM(require("react"));
1354
+ var import_react_primitive12 = require("@huin-core/react-primitive");
1355
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1356
+ var SEPARATOR_NAME = "SelectSeparator";
1357
+ var SelectSeparator = import_react13.default.forwardRef((props, forwardedRef) => {
1358
+ const { __scopeSelect, ...separatorProps } = props;
1359
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_primitive12.Primitive.div, { "aria-hidden": true, ...separatorProps, ref: forwardedRef });
1360
+ });
1361
+ SelectSeparator.displayName = SEPARATOR_NAME;
1362
+
1363
+ // packages/react/select/src/SelectArrow.tsx
1364
+ var PopperPrimitive4 = __toESM(require("@huin-core/react-popper"));
1365
+ var import_react14 = __toESM(require("react"));
1366
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1367
+ var ARROW_NAME = "SelectArrow";
1368
+ var SelectArrow = import_react14.default.forwardRef(
1369
+ (props, forwardedRef) => {
1370
+ const { __scopeSelect, ...arrowProps } = props;
1371
+ const popperScope = usePopperScope(__scopeSelect);
1372
+ const context = useSelectContext(ARROW_NAME, __scopeSelect);
1373
+ const contentContext = useSelectContentContext(ARROW_NAME, __scopeSelect);
1374
+ return context.open && contentContext.position === "popper" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1375
+ PopperPrimitive4.Arrow,
1376
+ {
1377
+ ...popperScope,
1378
+ ...arrowProps,
1379
+ ref: forwardedRef
1380
+ }
1381
+ ) : null;
1382
+ }
1383
+ );
1384
+ SelectArrow.displayName = ARROW_NAME;
1385
+ //# sourceMappingURL=index.js.map