@longd/layout-ui 0.1.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.
@@ -0,0 +1,1095 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/layout/select.tsx
31
+ var select_exports = {};
32
+ __export(select_exports, {
33
+ LayoutSelect: () => LayoutSelect,
34
+ default: () => select_default
35
+ });
36
+ module.exports = __toCommonJS(select_exports);
37
+ var React = __toESM(require("react"), 1);
38
+ var import_react = require("react");
39
+ var import_popover = require("@base-ui/react/popover");
40
+ var import_tooltip = require("@base-ui/react/tooltip");
41
+ var import_cmdk = require("cmdk");
42
+ var import_core = require("@dnd-kit/core");
43
+ var import_sortable = require("@dnd-kit/sortable");
44
+ var import_modifiers = require("@dnd-kit/modifiers");
45
+ var import_react_virtual = require("@tanstack/react-virtual");
46
+ var import_lucide_react = require("lucide-react");
47
+
48
+ // src/lib/utils.ts
49
+ var import_clsx = require("clsx");
50
+ var import_tailwind_merge = require("tailwind-merge");
51
+ function cn(...inputs) {
52
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
53
+ }
54
+
55
+ // src/layout/select.tsx
56
+ var import_jsx_runtime = require("react/jsx-runtime");
57
+ function resolveIcon(icon) {
58
+ if (icon === void 0 || icon === null) return null;
59
+ if (typeof icon === "function") return icon();
60
+ return icon;
61
+ }
62
+ function flattenOptions(options) {
63
+ const result = [];
64
+ for (const opt of options) {
65
+ if (opt.children && opt.children.length > 0) {
66
+ result.push(...flattenOptions(opt.children));
67
+ } else {
68
+ result.push(opt);
69
+ }
70
+ }
71
+ return result;
72
+ }
73
+ function buildDisplayRows(options) {
74
+ const rows = [];
75
+ for (const opt of options) {
76
+ if (opt.children && opt.children.length > 0) {
77
+ rows.push({
78
+ kind: "group-header",
79
+ label: opt.label,
80
+ groupValue: opt.value
81
+ });
82
+ for (const child of opt.children) {
83
+ rows.push({ kind: "option", option: child, groupValue: opt.value });
84
+ }
85
+ } else {
86
+ rows.push({ kind: "option", option: opt });
87
+ }
88
+ }
89
+ return rows;
90
+ }
91
+ function hasGroups(options) {
92
+ return options.some((o) => o.children && o.children.length > 0);
93
+ }
94
+ function optionEq(a, b) {
95
+ return a.value === b.value;
96
+ }
97
+ function isSelected(option, value) {
98
+ if (!value) return false;
99
+ if (Array.isArray(value)) return value.some((v) => optionEq(v, option));
100
+ return optionEq(value, option);
101
+ }
102
+ function SortableItem({ id, children, disabled }) {
103
+ const {
104
+ setNodeRef,
105
+ attributes,
106
+ listeners,
107
+ transform,
108
+ transition,
109
+ isDragging
110
+ } = (0, import_sortable.useSortable)({ id, disabled });
111
+ const style = {
112
+ transform: transform ? `translate3d(${transform.x}px, ${transform.y}px, 0)` : void 0,
113
+ transition,
114
+ opacity: isDragging ? 0.5 : 1,
115
+ position: "relative",
116
+ zIndex: isDragging ? 50 : void 0
117
+ };
118
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: setNodeRef, style, className: "flex items-center", children: [
119
+ !disabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
120
+ "button",
121
+ {
122
+ type: "button",
123
+ className: "flex shrink-0 cursor-grab items-center px-1 text-muted-foreground hover:text-foreground active:cursor-grabbing",
124
+ ...attributes,
125
+ ...listeners,
126
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.GripVertical, { className: "size-3.5" })
127
+ }
128
+ ),
129
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "min-w-0 flex-1", children })
130
+ ] });
131
+ }
132
+ function MaybeTooltip({
133
+ tooltip,
134
+ children
135
+ }) {
136
+ if (!tooltip) return children;
137
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_tooltip.Tooltip.Root, { children: [
138
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltip.Tooltip.Trigger, { render: children }),
139
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltip.Tooltip.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltip.Tooltip.Positioner, { sideOffset: 6, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltip.Tooltip.Popup, { className: "rounded-md bg-foreground px-2.5 py-1 text-xs text-background shadow-md", children: tooltip }) }) })
140
+ ] });
141
+ }
142
+ function Chip({
143
+ option,
144
+ onRemove,
145
+ readOnly,
146
+ disabled,
147
+ className,
148
+ partial
149
+ }) {
150
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
151
+ "span",
152
+ {
153
+ "data-partial-chip": partial || void 0,
154
+ className: cn(
155
+ "inline-flex max-w-35 items-center gap-1 rounded-md border border-border bg-secondary px-2 py-0.5 text-xs leading-5 text-secondary-foreground",
156
+ disabled && "opacity-50",
157
+ className
158
+ ),
159
+ children: [
160
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex shrink-0 items-center [&_svg]:size-3", children: resolveIcon(option.icon) }),
161
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: option.label }),
162
+ !readOnly && !disabled && onRemove && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
163
+ "button",
164
+ {
165
+ type: "button",
166
+ className: "ml-0.5 flex shrink-0 items-center rounded-sm text-muted-foreground hover:text-foreground",
167
+ onClick: (e) => {
168
+ e.stopPropagation();
169
+ onRemove();
170
+ },
171
+ tabIndex: -1,
172
+ "aria-label": `Remove ${option.label}`,
173
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "size-3" })
174
+ }
175
+ )
176
+ ]
177
+ }
178
+ );
179
+ }
180
+ function OverflowBadge({
181
+ items,
182
+ onRemove
183
+ }) {
184
+ if (items.length === 0) return null;
185
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_tooltip.Tooltip.Root, { children: [
186
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
187
+ import_tooltip.Tooltip.Trigger,
188
+ {
189
+ render: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex shrink-0 items-center rounded-md border border-border bg-muted px-1.5 py-0.5 text-xs font-medium text-muted-foreground", children: [
190
+ "+",
191
+ items.length
192
+ ] })
193
+ }
194
+ ),
195
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltip.Tooltip.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltip.Tooltip.Positioner, { sideOffset: 6, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltip.Tooltip.Popup, { className: "max-w-xs rounded-md bg-foreground px-3 py-2 text-xs text-background shadow-md", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-wrap gap-1", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
196
+ "span",
197
+ {
198
+ className: "inline-flex items-center gap-1 rounded-md border border-background/20 bg-background/10 px-1.5 py-0.5 text-xs leading-4 text-background",
199
+ children: [
200
+ item.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex shrink-0 items-center [&_svg]:size-3", children: resolveIcon(item.icon) }),
201
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: item.label }),
202
+ onRemove && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
203
+ "button",
204
+ {
205
+ type: "button",
206
+ className: "ml-0.5 flex shrink-0 items-center rounded-sm text-background/60 hover:text-background",
207
+ onClick: (e) => {
208
+ e.stopPropagation();
209
+ onRemove(item);
210
+ },
211
+ tabIndex: -1,
212
+ "aria-label": `Remove ${item.label}`,
213
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "size-3" })
214
+ }
215
+ )
216
+ ]
217
+ },
218
+ item.value
219
+ )) }) }) }) })
220
+ ] });
221
+ }
222
+ function SingleTriggerContent({
223
+ value,
224
+ placeholder
225
+ }) {
226
+ if (!value) {
227
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate text-muted-foreground", children: placeholder });
228
+ }
229
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex items-center gap-2 truncate", children: [
230
+ value.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex shrink-0 items-center [&_svg]:size-4", children: resolveIcon(value.icon) }),
231
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: value.label })
232
+ ] });
233
+ }
234
+ function MultipleTriggerContent({
235
+ value,
236
+ placeholder,
237
+ collapsed,
238
+ showItemsLength,
239
+ onRemove,
240
+ readOnly,
241
+ disabled
242
+ }) {
243
+ const chipRowClass = "flex items-center gap-1";
244
+ const wrapperRef = (0, import_react.useRef)(null);
245
+ const measureRef = (0, import_react.useRef)(null);
246
+ const [visibleCount, setVisibleCount] = (0, import_react.useState)(value.length);
247
+ const [lastIsPartial, setLastIsPartial] = (0, import_react.useState)(false);
248
+ const [measured, setMeasured] = (0, import_react.useState)(false);
249
+ const measureCount = Math.min(value.length, 20);
250
+ const calculate = React.useEffectEvent(() => {
251
+ const measureContainer = measureRef.current;
252
+ if (!measureContainer) return;
253
+ const children = Array.from(measureContainer.children);
254
+ const containerRight = measureContainer.getBoundingClientRect().right;
255
+ const gap = parseFloat(getComputedStyle(measureContainer).columnGap) || 0;
256
+ const estimateBadgeWidth = (overflowCount) => overflowCount > 0 ? 14 + 8 * String(overflowCount).length : 0;
257
+ let count = 0;
258
+ let partial = false;
259
+ for (const child of children) {
260
+ const childRight = child.getBoundingClientRect().right;
261
+ const overflow = value.length - (count + 1);
262
+ const reserve = overflow > 0 ? Math.max(40, estimateBadgeWidth(overflow)) : 0;
263
+ if (childRight + reserve <= containerRight) {
264
+ count++;
265
+ } else {
266
+ break;
267
+ }
268
+ }
269
+ count = Math.max(1, count);
270
+ if (count < value.length && children.length >= count) {
271
+ const lastRight = children[count - 1].getBoundingClientRect().right;
272
+ const needsBadge = count + 1 < value.length;
273
+ const badgeReserve = needsBadge ? Math.max(40, estimateBadgeWidth(value.length - count - 1)) : 0;
274
+ const spaceForPartial = containerRight - badgeReserve - lastRight - gap;
275
+ const nextChip = value[count];
276
+ let minPartialWidth = 50;
277
+ if (nextChip.icon && children.length > count) {
278
+ const iconWrapper = children[count].firstElementChild;
279
+ if (iconWrapper) {
280
+ minPartialWidth += iconWrapper.getBoundingClientRect().width + gap;
281
+ }
282
+ }
283
+ if (spaceForPartial >= minPartialWidth) {
284
+ count++;
285
+ partial = true;
286
+ }
287
+ }
288
+ setVisibleCount(count);
289
+ setLastIsPartial(partial);
290
+ setMeasured(true);
291
+ });
292
+ (0, import_react.useLayoutEffect)(() => {
293
+ if (collapsed || value.length === 0) {
294
+ setVisibleCount(value.length);
295
+ setLastIsPartial(false);
296
+ setMeasured(true);
297
+ return;
298
+ }
299
+ const wrapper = wrapperRef.current;
300
+ const container = measureRef.current;
301
+ if (!wrapper || !container) return;
302
+ calculate();
303
+ const observer = new ResizeObserver(calculate);
304
+ observer.observe(wrapper);
305
+ return () => observer.disconnect();
306
+ }, [collapsed, value]);
307
+ if (value.length === 0) {
308
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate text-muted-foreground", children: placeholder });
309
+ }
310
+ const measureLayer = !collapsed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
311
+ "div",
312
+ {
313
+ ref: measureRef,
314
+ className: cn(
315
+ "pointer-events-none absolute inset-0 overflow-hidden opacity-0",
316
+ chipRowClass
317
+ ),
318
+ "aria-hidden": true,
319
+ children: value.slice(0, measureCount).map((opt) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
320
+ Chip,
321
+ {
322
+ option: opt,
323
+ onRemove: onRemove ? () => {
324
+ } : void 0,
325
+ readOnly,
326
+ disabled,
327
+ className: "shrink-0"
328
+ },
329
+ opt.value
330
+ ))
331
+ }
332
+ );
333
+ const showContent = collapsed || measured;
334
+ if (!showContent) {
335
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
336
+ "div",
337
+ {
338
+ ref: wrapperRef,
339
+ className: cn("relative min-w-0 flex-1 overflow-hidden", chipRowClass),
340
+ children: [
341
+ measureLayer,
342
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "truncate text-muted-foreground", children: [
343
+ value.length,
344
+ " selected"
345
+ ] })
346
+ ]
347
+ }
348
+ );
349
+ }
350
+ let maxVisible = collapsed ? value.length : visibleCount;
351
+ const hasExplicitLimit = !collapsed && showItemsLength !== void 0;
352
+ if (hasExplicitLimit) {
353
+ maxVisible = showItemsLength;
354
+ }
355
+ const hasOverflow = maxVisible < value.length;
356
+ const displayed = value.slice(0, maxVisible);
357
+ const overflowItems = value.slice(maxVisible);
358
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
359
+ "div",
360
+ {
361
+ ref: wrapperRef,
362
+ className: cn("relative min-w-0 flex-1", chipRowClass),
363
+ children: [
364
+ measureLayer,
365
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
366
+ "div",
367
+ {
368
+ className: cn(
369
+ "min-w-0 flex-1",
370
+ chipRowClass,
371
+ collapsed ? "flex-wrap" : "overflow-hidden"
372
+ ),
373
+ children: displayed.map((opt, i) => {
374
+ const isPartial = (hasOverflow || lastIsPartial) && !hasExplicitLimit && i === displayed.length - 1;
375
+ const shouldShrink = isPartial || hasExplicitLimit;
376
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
377
+ Chip,
378
+ {
379
+ option: opt,
380
+ onRemove: onRemove ? () => onRemove(opt) : void 0,
381
+ readOnly,
382
+ disabled,
383
+ partial: isPartial,
384
+ className: shouldShrink ? "min-w-0 shrink" : "shrink-0"
385
+ },
386
+ opt.value
387
+ );
388
+ })
389
+ }
390
+ ),
391
+ overflowItems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OverflowBadge, { items: overflowItems, onRemove }) })
392
+ ]
393
+ }
394
+ );
395
+ }
396
+ function OptionRow({
397
+ option,
398
+ selected,
399
+ renderItem,
400
+ onSelect,
401
+ highlighted = false
402
+ }) {
403
+ const content = renderItem ? renderItem(option, {
404
+ selected,
405
+ highlighted,
406
+ disabled: !!option.disabled
407
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex w-full items-center gap-2", children: [
408
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex shrink-0 items-center [&_svg]:size-4", children: resolveIcon(option.icon) }),
409
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex-1 truncate", children: option.label }),
410
+ selected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-auto flex shrink-0 items-center text-primary", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Check, { className: "size-4" }) })
411
+ ] });
412
+ const row = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
413
+ import_cmdk.Command.Item,
414
+ {
415
+ value: `${option.value}`,
416
+ disabled: option.disabled,
417
+ onSelect: () => {
418
+ if (!option.disabled) onSelect(option);
419
+ },
420
+ className: cn(
421
+ "relative flex w-full cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none",
422
+ "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground",
423
+ option.disabled && "pointer-events-none opacity-50"
424
+ ),
425
+ "data-highlighted": highlighted || void 0,
426
+ children: content
427
+ }
428
+ );
429
+ if (option.disabled && option.disabledTooltip) {
430
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MaybeTooltip, { tooltip: option.disabledTooltip, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: row }) });
431
+ }
432
+ return row;
433
+ }
434
+ function VirtualList({
435
+ options,
436
+ items,
437
+ selectedValue,
438
+ renderItem,
439
+ onSelect,
440
+ sortable,
441
+ sortableAcrossGroups,
442
+ onSortEnd,
443
+ onGroupSortEnd,
444
+ onTreeSort
445
+ }) {
446
+ const parentRef = (0, import_react.useRef)(null);
447
+ const [activeId, setActiveId] = (0, import_react.useState)(null);
448
+ const [dragTree, setDragTree] = (0, import_react.useState)(null);
449
+ const effectiveOptions = dragTree ?? options;
450
+ const grouped = (0, import_react.useMemo)(() => hasGroups(effectiveOptions), [effectiveOptions]);
451
+ const displayRows = (0, import_react.useMemo)(
452
+ () => grouped ? buildDisplayRows(effectiveOptions) : void 0,
453
+ [grouped, effectiveOptions]
454
+ );
455
+ const flatDisplayRows = (0, import_react.useMemo)(
456
+ () => items.map((o) => ({ kind: "option", option: o })),
457
+ [items]
458
+ );
459
+ const virtualItems = displayRows ?? flatDisplayRows;
460
+ const activeIndex = (0, import_react.useMemo)(() => {
461
+ if (!activeId) return null;
462
+ const idx = virtualItems.findIndex(
463
+ (r) => r.kind === "option" && `${r.option.value}` === activeId
464
+ );
465
+ return idx !== -1 ? idx : null;
466
+ }, [activeId, virtualItems]);
467
+ const rangeExtractor = (0, import_react.useCallback)(
468
+ (range) => {
469
+ const result = (0, import_react_virtual.defaultRangeExtractor)(range);
470
+ if (activeIndex !== null && !result.includes(activeIndex)) {
471
+ result.push(activeIndex);
472
+ result.sort((a, b) => a - b);
473
+ }
474
+ return result;
475
+ },
476
+ [activeIndex]
477
+ );
478
+ const virtualizer = (0, import_react_virtual.useVirtualizer)({
479
+ count: virtualItems.length,
480
+ getScrollElement: () => parentRef.current,
481
+ estimateSize: (index) => virtualItems[index].kind === "group-header" ? 28 : 36,
482
+ overscan: 8,
483
+ rangeExtractor
484
+ });
485
+ (0, import_react.useLayoutEffect)(() => {
486
+ virtualizer.measure();
487
+ }, [virtualizer, displayRows]);
488
+ const sensors = (0, import_core.useSensors)(
489
+ (0, import_core.useSensor)(import_core.PointerSensor, { activationConstraint: { distance: 4 } }),
490
+ (0, import_core.useSensor)(import_core.KeyboardSensor)
491
+ );
492
+ const flatSortableIds = (0, import_react.useMemo)(
493
+ () => virtualItems.filter(
494
+ (r) => r.kind === "option"
495
+ ).map((r) => `${r.option.value}`),
496
+ [virtualItems]
497
+ );
498
+ const sameGroupCollision = (0, import_react.useCallback)(
499
+ (args) => {
500
+ if (!displayRows) return (0, import_core.closestCenter)(args);
501
+ const draggedId = args.active.id;
502
+ const activeRow = displayRows.find(
503
+ (r) => r.kind === "option" && `${r.option.value}` === `${draggedId}`
504
+ );
505
+ if (!activeRow || activeRow.kind !== "option") return (0, import_core.closestCenter)(args);
506
+ const activeGroup = activeRow.groupValue;
507
+ const filtered = args.droppableContainers.filter((container) => {
508
+ const row = displayRows.find(
509
+ (r) => r.kind === "option" && `${r.option.value}` === `${container.id}`
510
+ );
511
+ return row && row.kind === "option" && row.groupValue === activeGroup;
512
+ });
513
+ return (0, import_core.closestCenter)({ ...args, droppableContainers: filtered });
514
+ },
515
+ [displayRows]
516
+ );
517
+ const sortingStrategy = (0, import_react.useMemo)(() => {
518
+ if (!grouped || !displayRows) return import_sortable.verticalListSortingStrategy;
519
+ const idToGroup = /* @__PURE__ */ new Map();
520
+ for (const row of displayRows) {
521
+ if (row.kind === "option") {
522
+ idToGroup.set(`${row.option.value}`, row.groupValue);
523
+ }
524
+ }
525
+ const noMove = { x: 0, y: 0, scaleX: 1, scaleY: 1 };
526
+ return (args) => {
527
+ const draggedId = flatSortableIds[args.activeIndex];
528
+ const currentId = flatSortableIds[args.index];
529
+ if (draggedId && currentId && idToGroup.get(draggedId) !== idToGroup.get(currentId)) {
530
+ return noMove;
531
+ }
532
+ return (0, import_sortable.verticalListSortingStrategy)(args);
533
+ };
534
+ }, [grouped, displayRows, flatSortableIds]);
535
+ const handleDragOver = (0, import_react.useCallback)(
536
+ (event) => {
537
+ if (!sortableAcrossGroups || !grouped) return;
538
+ const { active, over } = event;
539
+ if (!over || active.id === over.id) return;
540
+ const currentTree = dragTree ?? options;
541
+ const currentRows = buildDisplayRows(currentTree);
542
+ const activeRow = currentRows.find(
543
+ (r) => r.kind === "option" && `${r.option.value}` === `${active.id}`
544
+ );
545
+ const overRow = currentRows.find(
546
+ (r) => r.kind === "option" && `${r.option.value}` === `${over.id}`
547
+ );
548
+ if (!activeRow || activeRow.kind !== "option" || !overRow || overRow.kind !== "option")
549
+ return;
550
+ if (activeRow.groupValue === overRow.groupValue) return;
551
+ const newTree = currentTree.map((opt) => {
552
+ if (!opt.children) return opt;
553
+ if (opt.value === activeRow.groupValue) {
554
+ return {
555
+ ...opt,
556
+ children: opt.children.filter(
557
+ (c) => `${c.value}` !== `${active.id}`
558
+ )
559
+ };
560
+ }
561
+ if (opt.value === overRow.groupValue) {
562
+ const destChildren = opt.children.filter(
563
+ (c) => `${c.value}` !== `${active.id}`
564
+ );
565
+ const overIdx = destChildren.findIndex(
566
+ (c) => `${c.value}` === `${over.id}`
567
+ );
568
+ destChildren.splice(
569
+ overIdx !== -1 ? overIdx : destChildren.length,
570
+ 0,
571
+ activeRow.option
572
+ );
573
+ return { ...opt, children: destChildren };
574
+ }
575
+ return opt;
576
+ });
577
+ setDragTree(newTree);
578
+ },
579
+ [sortableAcrossGroups, grouped, dragTree, options]
580
+ );
581
+ const handleDragEndFlat = (0, import_react.useCallback)(
582
+ (event) => {
583
+ setActiveId(null);
584
+ setDragTree(null);
585
+ const { active, over } = event;
586
+ if (!over || active.id === over.id || !onSortEnd) return;
587
+ const oldIndex = items.findIndex((i) => `${i.value}` === `${active.id}`);
588
+ const newIndex = items.findIndex((i) => `${i.value}` === `${over.id}`);
589
+ if (oldIndex !== -1 && newIndex !== -1) {
590
+ onSortEnd((0, import_sortable.arrayMove)(items, oldIndex, newIndex));
591
+ }
592
+ },
593
+ [items, onSortEnd]
594
+ );
595
+ const handleDragEndGrouped = (0, import_react.useCallback)(
596
+ (event) => {
597
+ setActiveId(null);
598
+ const { active, over } = event;
599
+ if (!over || active.id === over.id) {
600
+ if (dragTree) onTreeSort?.(dragTree);
601
+ setDragTree(null);
602
+ return;
603
+ }
604
+ if (!displayRows) {
605
+ setDragTree(null);
606
+ return;
607
+ }
608
+ const activeRow = displayRows.find(
609
+ (r) => r.kind === "option" && `${r.option.value}` === `${active.id}`
610
+ );
611
+ const overRow = displayRows.find(
612
+ (r) => r.kind === "option" && `${r.option.value}` === `${over.id}`
613
+ );
614
+ if (!activeRow || activeRow.kind !== "option" || !overRow || overRow.kind !== "option") {
615
+ setDragTree(null);
616
+ return;
617
+ }
618
+ const activeGroup = activeRow.groupValue;
619
+ const overGroup = overRow.groupValue;
620
+ const baseTree = dragTree ?? options;
621
+ if (activeGroup === overGroup) {
622
+ const groupChildren = displayRows.filter(
623
+ (r) => r.kind === "option" && r.groupValue === activeGroup
624
+ ).map((r) => r.option);
625
+ const oldIdx = groupChildren.findIndex(
626
+ (i) => `${i.value}` === `${active.id}`
627
+ );
628
+ const newIdx = groupChildren.findIndex(
629
+ (i) => `${i.value}` === `${over.id}`
630
+ );
631
+ if (oldIdx !== -1 && newIdx !== -1 && oldIdx !== newIdx) {
632
+ const reordered = (0, import_sortable.arrayMove)(groupChildren, oldIdx, newIdx);
633
+ if (dragTree) {
634
+ const finalTree = baseTree.map((opt) => {
635
+ if (opt.value === activeGroup && opt.children) {
636
+ return { ...opt, children: reordered };
637
+ }
638
+ return opt;
639
+ });
640
+ onTreeSort?.(finalTree);
641
+ } else {
642
+ onGroupSortEnd?.(activeGroup, reordered);
643
+ }
644
+ } else if (dragTree) {
645
+ onTreeSort?.(baseTree);
646
+ }
647
+ } else {
648
+ const finalTree = baseTree.map((opt) => {
649
+ if (!opt.children) return opt;
650
+ if (opt.value === activeGroup) {
651
+ return {
652
+ ...opt,
653
+ children: opt.children.filter(
654
+ (c) => `${c.value}` !== `${active.id}`
655
+ )
656
+ };
657
+ }
658
+ if (opt.value === overGroup) {
659
+ const destChildren = [...opt.children];
660
+ const overIdx = destChildren.findIndex(
661
+ (c) => `${c.value}` === `${over.id}`
662
+ );
663
+ destChildren.splice(
664
+ overIdx !== -1 ? overIdx + 1 : destChildren.length,
665
+ 0,
666
+ activeRow.option
667
+ );
668
+ return { ...opt, children: destChildren };
669
+ }
670
+ return opt;
671
+ });
672
+ onTreeSort?.(finalTree);
673
+ }
674
+ setDragTree(null);
675
+ },
676
+ [dragTree, options, displayRows, onTreeSort, onGroupSortEnd]
677
+ );
678
+ const listContent = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
679
+ "div",
680
+ {
681
+ ref: parentRef,
682
+ className: cn(
683
+ "max-h-75 overflow-x-hidden",
684
+ activeIndex !== null ? "overflow-y-visible" : "overflow-y-auto"
685
+ ),
686
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
687
+ "div",
688
+ {
689
+ style: {
690
+ height: `${virtualizer.getTotalSize()}px`,
691
+ position: "relative",
692
+ width: "100%"
693
+ },
694
+ children: virtualizer.getVirtualItems().map((vItem) => {
695
+ const displayRow = virtualItems[vItem.index];
696
+ if (displayRow.kind === "group-header") {
697
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
698
+ "div",
699
+ {
700
+ style: {
701
+ position: "absolute",
702
+ top: 0,
703
+ left: 0,
704
+ width: "100%",
705
+ transform: `translateY(${vItem.start}px)`
706
+ },
707
+ "data-index": vItem.index,
708
+ ref: virtualizer.measureElement,
709
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "px-2 py-1 text-xs font-semibold text-muted-foreground", children: displayRow.label })
710
+ },
711
+ `gh-${displayRow.groupValue}`
712
+ );
713
+ }
714
+ const option = displayRow.option;
715
+ const row = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
716
+ OptionRow,
717
+ {
718
+ option,
719
+ selected: isSelected(option, selectedValue),
720
+ renderItem,
721
+ onSelect
722
+ },
723
+ option.value
724
+ );
725
+ const wrappedRow = sortable ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
726
+ SortableItem,
727
+ {
728
+ id: `${option.value}`,
729
+ disabled: option.disabled,
730
+ children: row
731
+ },
732
+ option.value
733
+ ) : row;
734
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
735
+ "div",
736
+ {
737
+ style: {
738
+ position: "absolute",
739
+ top: 0,
740
+ left: 0,
741
+ width: "100%",
742
+ transform: `translateY(${vItem.start}px)`
743
+ },
744
+ "data-index": vItem.index,
745
+ ref: virtualizer.measureElement,
746
+ children: wrappedRow
747
+ },
748
+ option.value
749
+ );
750
+ })
751
+ }
752
+ )
753
+ }
754
+ );
755
+ if (sortable) {
756
+ const handleDragStart = (event) => {
757
+ setActiveId(`${event.active.id}`);
758
+ };
759
+ const handleCancel = () => {
760
+ setActiveId(null);
761
+ setDragTree(null);
762
+ };
763
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
764
+ import_core.DndContext,
765
+ {
766
+ modifiers: [import_modifiers.restrictToVerticalAxis, import_modifiers.restrictToFirstScrollableAncestor],
767
+ sensors,
768
+ collisionDetection: grouped && !sortableAcrossGroups ? sameGroupCollision : import_core.closestCenter,
769
+ onDragStart: handleDragStart,
770
+ onDragOver: handleDragOver,
771
+ onDragEnd: grouped ? handleDragEndGrouped : handleDragEndFlat,
772
+ onDragCancel: handleCancel,
773
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_sortable.SortableContext, { items: flatSortableIds, strategy: sortingStrategy, children: listContent })
774
+ }
775
+ );
776
+ }
777
+ return listContent;
778
+ }
779
+ function LayoutSelect(props) {
780
+ const {
781
+ type,
782
+ options,
783
+ placeholder = "Select item",
784
+ disabled = false,
785
+ readOnly = false,
786
+ error = false,
787
+ clearable = false,
788
+ className,
789
+ triggerClassName,
790
+ popupClassName,
791
+ renderTrigger,
792
+ renderItem,
793
+ listPrefix,
794
+ listSuffix,
795
+ queryFn,
796
+ label
797
+ } = props;
798
+ const [open, setOpen] = (0, import_react.useState)(false);
799
+ const [search, setSearch] = (0, import_react.useState)("");
800
+ const [asyncOptions, setAsyncOptions] = (0, import_react.useState)(null);
801
+ const [loading, setLoading] = (0, import_react.useState)(false);
802
+ const [internalSortedOptions, setInternalSortedOptions] = (0, import_react.useState)(null);
803
+ const currentValue = (0, import_react.useMemo)(() => {
804
+ if (type === "single") {
805
+ return props.selectValue ?? null;
806
+ }
807
+ return props.selectValue ?? [];
808
+ }, [type, props]);
809
+ const resolvedOptions = (0, import_react.useMemo)(() => {
810
+ const base = asyncOptions ?? options;
811
+ return internalSortedOptions ?? base;
812
+ }, [asyncOptions, options, internalSortedOptions]);
813
+ const flatOptions = (0, import_react.useMemo)(
814
+ () => flattenOptions(resolvedOptions),
815
+ [resolvedOptions]
816
+ );
817
+ const filteredOptions = (0, import_react.useMemo)(() => {
818
+ if (!search) return flatOptions;
819
+ const q = search.toLowerCase();
820
+ return flatOptions.filter((o) => o.label.toLowerCase().includes(q));
821
+ }, [flatOptions, search]);
822
+ const filteredGroupedOptions = (0, import_react.useMemo)(() => {
823
+ if (!search) return resolvedOptions;
824
+ const q = search.toLowerCase();
825
+ return resolvedOptions.map((opt) => {
826
+ if (opt.children && opt.children.length > 0) {
827
+ const matched = opt.children.filter(
828
+ (c) => c.label.toLowerCase().includes(q)
829
+ );
830
+ if (matched.length === 0) return null;
831
+ return { ...opt, children: matched };
832
+ }
833
+ return opt.label.toLowerCase().includes(q) ? opt : null;
834
+ }).filter(Boolean);
835
+ }, [resolvedOptions, search]);
836
+ (0, import_react.useEffect)(() => {
837
+ if (open && queryFn) {
838
+ let cancelled = false;
839
+ setLoading(true);
840
+ queryFn().then((data) => {
841
+ if (!cancelled) {
842
+ setAsyncOptions(data);
843
+ }
844
+ }).finally(() => {
845
+ if (!cancelled) setLoading(false);
846
+ });
847
+ return () => {
848
+ cancelled = true;
849
+ };
850
+ }
851
+ }, [open, queryFn]);
852
+ (0, import_react.useEffect)(() => {
853
+ if (!open) {
854
+ setSearch("");
855
+ }
856
+ }, [open]);
857
+ const handleSelect = (0, import_react.useCallback)(
858
+ (option) => {
859
+ if (readOnly) return;
860
+ if (type === "single") {
861
+ const onChange = props.onChange;
862
+ const current = currentValue;
863
+ if (clearable && current && optionEq(current, option)) {
864
+ onChange?.(null, option);
865
+ } else {
866
+ onChange?.(option, option);
867
+ }
868
+ setOpen(false);
869
+ } else {
870
+ const onChange = props.onChange;
871
+ const current = currentValue;
872
+ const exists = current.some((v) => optionEq(v, option));
873
+ if (exists) {
874
+ onChange?.(
875
+ current.filter((v) => !optionEq(v, option)),
876
+ option
877
+ );
878
+ } else {
879
+ onChange?.([...current, option], option);
880
+ }
881
+ }
882
+ },
883
+ [type, currentValue, clearable, readOnly, props]
884
+ );
885
+ const handleRemoveChip = (0, import_react.useCallback)(
886
+ (option) => {
887
+ if (type !== "multiple" || readOnly || disabled) return;
888
+ const onChange = props.onChange;
889
+ const current = currentValue;
890
+ onChange?.(
891
+ current.filter((v) => !optionEq(v, option)),
892
+ option
893
+ );
894
+ },
895
+ [type, currentValue, readOnly, disabled, props]
896
+ );
897
+ const handleToggleAll = (0, import_react.useCallback)(() => {
898
+ if (type !== "multiple" || readOnly || disabled) return;
899
+ const onChange = props.onChange;
900
+ const current = currentValue;
901
+ const selectableOptions = flatOptions.filter((o) => !o.disabled);
902
+ const allSelected2 = selectableOptions.length > 0 && selectableOptions.every((o) => current.some((v) => optionEq(v, o)));
903
+ if (allSelected2) {
904
+ const kept = current.filter(
905
+ (v) => selectableOptions.every((o) => !optionEq(o, v))
906
+ );
907
+ onChange?.(kept, selectableOptions[0]);
908
+ } else {
909
+ const missing = selectableOptions.filter(
910
+ (o) => !current.some((v) => optionEq(v, o))
911
+ );
912
+ onChange?.([...current, ...missing], selectableOptions[0]);
913
+ }
914
+ }, [type, currentValue, flatOptions, readOnly, disabled, props]);
915
+ const allSelected = (0, import_react.useMemo)(() => {
916
+ if (type !== "multiple") return false;
917
+ const current = currentValue;
918
+ const selectableOptions = flatOptions.filter((o) => !o.disabled);
919
+ return selectableOptions.length > 0 && selectableOptions.every((o) => current.some((v) => optionEq(v, o)));
920
+ }, [type, currentValue, flatOptions]);
921
+ const sortable = props.sortable ?? false;
922
+ const sortableAcrossGroups = props.sortable ? props.sortableAcrossGroups ?? false : false;
923
+ const consumerOnSortEnd = props.sortable ? props.onSortEnd : void 0;
924
+ const handleSortEnd = (0, import_react.useCallback)(
925
+ (sorted) => {
926
+ setInternalSortedOptions(sorted);
927
+ consumerOnSortEnd?.(sorted);
928
+ },
929
+ [consumerOnSortEnd]
930
+ );
931
+ const handleGroupSortEnd = (0, import_react.useCallback)(
932
+ (groupValue, reorderedChildren) => {
933
+ const updated = resolvedOptions.map((opt) => {
934
+ if (opt.value === groupValue && opt.children) {
935
+ return { ...opt, children: reorderedChildren };
936
+ }
937
+ return opt;
938
+ });
939
+ setInternalSortedOptions(updated);
940
+ consumerOnSortEnd?.(flattenOptions(updated));
941
+ },
942
+ [resolvedOptions, consumerOnSortEnd]
943
+ );
944
+ const handleTreeSort = (0, import_react.useCallback)(
945
+ (newTree) => {
946
+ setInternalSortedOptions(newTree);
947
+ consumerOnSortEnd?.(flattenOptions(newTree));
948
+ },
949
+ [consumerOnSortEnd]
950
+ );
951
+ const handleOpenChange = (0, import_react.useCallback)(
952
+ (nextOpen) => {
953
+ if (disabled || readOnly) return;
954
+ setOpen(nextOpen);
955
+ },
956
+ [disabled, readOnly]
957
+ );
958
+ const triggerContent = (0, import_react.useMemo)(() => {
959
+ if (renderTrigger) {
960
+ return renderTrigger({
961
+ value: currentValue,
962
+ open,
963
+ disabled,
964
+ readOnly,
965
+ error,
966
+ placeholder
967
+ });
968
+ }
969
+ if (type === "single") {
970
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
971
+ SingleTriggerContent,
972
+ {
973
+ value: currentValue,
974
+ placeholder
975
+ }
976
+ );
977
+ }
978
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
979
+ MultipleTriggerContent,
980
+ {
981
+ value: currentValue,
982
+ placeholder,
983
+ collapsed: props.collapsed,
984
+ showItemsLength: props.showItemsLength,
985
+ onRemove: handleRemoveChip,
986
+ readOnly,
987
+ disabled
988
+ }
989
+ );
990
+ }, [
991
+ renderTrigger,
992
+ type,
993
+ currentValue,
994
+ open,
995
+ disabled,
996
+ readOnly,
997
+ error,
998
+ placeholder,
999
+ props,
1000
+ handleRemoveChip
1001
+ ]);
1002
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltip.Tooltip.Provider, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("relative inline-flex flex-col", className), children: [
1003
+ label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "mb-1 text-sm font-medium text-foreground", children: label }),
1004
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_popover.Popover.Root, { open, onOpenChange: handleOpenChange, children: [
1005
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1006
+ import_popover.Popover.Trigger,
1007
+ {
1008
+ disabled,
1009
+ render: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1010
+ "button",
1011
+ {
1012
+ type: "button",
1013
+ "aria-expanded": open,
1014
+ "aria-haspopup": "listbox",
1015
+ "aria-invalid": error || void 0,
1016
+ "data-readonly": readOnly || void 0,
1017
+ className: cn(
1018
+ "border-input flex min-h-9 w-full min-w-45 items-center gap-2 rounded-md border bg-transparent px-3 py-1.5 text-sm shadow-xs transition-[color,box-shadow,border-color] outline-none",
1019
+ "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
1020
+ "aria-invalid:border-destructive aria-invalid:ring-destructive/20",
1021
+ "data-readonly:pointer-events-none data-readonly:opacity-70",
1022
+ "disabled:cursor-not-allowed disabled:opacity-50",
1023
+ "[&_svg:not([class*='text-'])]:text-muted-foreground",
1024
+ triggerClassName
1025
+ )
1026
+ }
1027
+ ),
1028
+ children: [
1029
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex min-w-0 flex-1 items-center", children: triggerContent }),
1030
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronDown, { className: "size-4 shrink-0 opacity-50" })
1031
+ ]
1032
+ }
1033
+ ),
1034
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_popover.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_popover.Popover.Positioner, { sideOffset: 4, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1035
+ import_popover.Popover.Popup,
1036
+ {
1037
+ className: cn(
1038
+ "z-50 min-w-(--anchor-width) rounded-md border bg-popover text-popover-foreground shadow-md outline-none",
1039
+ "data-starting-style:scale-95 data-starting-style:opacity-0",
1040
+ "data-ending-style:scale-95 data-ending-style:opacity-0",
1041
+ "origin-(--transform-origin) transition-[transform,scale,opacity] duration-150",
1042
+ popupClassName
1043
+ ),
1044
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_cmdk.Command, { shouldFilter: false, loop: true, children: [
1045
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border-b p-1", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1046
+ import_cmdk.Command.Input,
1047
+ {
1048
+ value: search,
1049
+ onValueChange: setSearch,
1050
+ placeholder: "Search...",
1051
+ className: "h-8 w-full rounded-sm bg-transparent px-2 text-sm outline-none placeholder:text-muted-foreground"
1052
+ }
1053
+ ) }),
1054
+ listPrefix && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border-b px-2 py-1.5", children: listPrefix }),
1055
+ type === "multiple" && !readOnly && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border-b px-1 py-1", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1056
+ "button",
1057
+ {
1058
+ type: "button",
1059
+ onClick: handleToggleAll,
1060
+ className: "w-full rounded-sm px-2 py-1 text-left text-sm text-muted-foreground hover:bg-accent hover:text-accent-foreground",
1061
+ children: allSelected ? "Unselect all" : "Select all"
1062
+ }
1063
+ ) }),
1064
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_cmdk.Command.List, { className: "p-1", children: [
1065
+ loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_cmdk.Command.Loading, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-center justify-center py-4 text-sm text-muted-foreground", children: "Loading\u2026" }) }),
1066
+ !loading && filteredOptions.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_cmdk.Command.Empty, { className: "py-4 text-center text-sm text-muted-foreground", children: "No results found." }),
1067
+ !loading && filteredOptions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1068
+ VirtualList,
1069
+ {
1070
+ options: filteredGroupedOptions,
1071
+ items: filteredOptions,
1072
+ selectedValue: currentValue,
1073
+ renderItem,
1074
+ onSelect: handleSelect,
1075
+ sortable,
1076
+ sortableAcrossGroups,
1077
+ onSortEnd: handleSortEnd,
1078
+ onGroupSortEnd: handleGroupSortEnd,
1079
+ onTreeSort: handleTreeSort
1080
+ }
1081
+ )
1082
+ ] }),
1083
+ listSuffix && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border-t px-2 py-1.5", children: listSuffix })
1084
+ ] })
1085
+ }
1086
+ ) }) })
1087
+ ] })
1088
+ ] }) });
1089
+ }
1090
+ var select_default = LayoutSelect;
1091
+ // Annotate the CommonJS export names for ESM import in node:
1092
+ 0 && (module.exports = {
1093
+ LayoutSelect
1094
+ });
1095
+ //# sourceMappingURL=select.cjs.map