@pactor-app/ui 1.2.0 → 1.7.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,727 @@
1
+ import {
2
+ Popover,
3
+ PopoverContent,
4
+ PopoverTrigger,
5
+ SidebarContent,
6
+ SidebarFooter,
7
+ SidebarHeader,
8
+ SidebarInset,
9
+ SidebarMenu,
10
+ SidebarMenuButton,
11
+ SidebarMenuItem,
12
+ SidebarProvider,
13
+ SidebarRoot,
14
+ Tooltip,
15
+ TooltipContent,
16
+ TooltipTrigger,
17
+ useIsMobile,
18
+ useSidebar
19
+ } from "./chunk-L4Z7MNYY.js";
20
+ import {
21
+ cn
22
+ } from "./chunk-WKJUCGV4.js";
23
+
24
+ // src/components/components/Icon/index.tsx
25
+ import {
26
+ ArrowDown,
27
+ ArrowLeft,
28
+ ArrowRight,
29
+ ArrowUp,
30
+ Bell,
31
+ Bookmark,
32
+ Brain,
33
+ Briefcase,
34
+ Building2,
35
+ Calendar,
36
+ Camera,
37
+ ChartColumn,
38
+ Check,
39
+ ChevronDown,
40
+ ChevronLeft,
41
+ ChevronRight,
42
+ ChevronsUpDown,
43
+ ChevronUp,
44
+ CircleAlert,
45
+ CircleCheck,
46
+ CircleQuestionMark,
47
+ CircleX,
48
+ Clock,
49
+ Cloud,
50
+ Code,
51
+ Copy,
52
+ CreditCard,
53
+ Database,
54
+ Download,
55
+ Ellipsis,
56
+ EllipsisVertical,
57
+ ExternalLink,
58
+ Eye,
59
+ File,
60
+ FileText,
61
+ Flag,
62
+ Folder,
63
+ Funnel,
64
+ Globe,
65
+ Heart,
66
+ History,
67
+ House,
68
+ Image,
69
+ Info,
70
+ Key,
71
+ Languages,
72
+ LayoutGrid,
73
+ Link,
74
+ List,
75
+ ListFilter,
76
+ LoaderCircle,
77
+ Lock,
78
+ LockOpen,
79
+ LogIn,
80
+ LogOut,
81
+ Mail,
82
+ MapPin,
83
+ Menu,
84
+ MessageCircle,
85
+ MessageSquare,
86
+ Minus,
87
+ Moon,
88
+ Package,
89
+ PanelLeft,
90
+ PanelRightOpen,
91
+ Paperclip,
92
+ Pencil,
93
+ Phone,
94
+ Plus,
95
+ Quote,
96
+ RefreshCcw,
97
+ RotateCcw,
98
+ Save,
99
+ Search,
100
+ Send,
101
+ Settings,
102
+ Share2,
103
+ Shield,
104
+ ShoppingCart,
105
+ Square,
106
+ SquarePen,
107
+ Star,
108
+ Sun,
109
+ Table,
110
+ Tag,
111
+ Terminal,
112
+ ThumbsDown,
113
+ ThumbsUp,
114
+ Trash2,
115
+ TriangleAlert,
116
+ Upload,
117
+ User,
118
+ Users,
119
+ X,
120
+ Zap
121
+ } from "lucide-react";
122
+ import { jsx } from "react/jsx-runtime";
123
+ var ICONS = {
124
+ "arrow-left": ArrowLeft,
125
+ "arrow-right": ArrowRight,
126
+ "arrow-up": ArrowUp,
127
+ "arrow-down": ArrowDown,
128
+ "chevron-left": ChevronLeft,
129
+ "chevron-right": ChevronRight,
130
+ "chevron-up": ChevronUp,
131
+ "chevron-down": ChevronDown,
132
+ check: Check,
133
+ x: X,
134
+ plus: Plus,
135
+ minus: Minus,
136
+ search: Search,
137
+ settings: Settings,
138
+ user: User,
139
+ users: Users,
140
+ home: House,
141
+ menu: Menu,
142
+ bell: Bell,
143
+ calendar: Calendar,
144
+ clock: Clock,
145
+ download: Download,
146
+ upload: Upload,
147
+ pencil: Pencil,
148
+ edit: SquarePen,
149
+ trash: Trash2,
150
+ eye: Eye,
151
+ info: Info,
152
+ warning: TriangleAlert,
153
+ error: CircleAlert,
154
+ "check-circle": CircleCheck,
155
+ "x-circle": CircleX,
156
+ "help-circle": CircleQuestionMark,
157
+ loading: LoaderCircle,
158
+ spinner: LoaderCircle,
159
+ star: Star,
160
+ heart: Heart,
161
+ bookmark: Bookmark,
162
+ share: Share2,
163
+ copy: Copy,
164
+ "external-link": ExternalLink,
165
+ link: Link,
166
+ mail: Mail,
167
+ phone: Phone,
168
+ lock: Lock,
169
+ unlock: LockOpen,
170
+ "log-in": LogIn,
171
+ "log-out": LogOut,
172
+ sun: Sun,
173
+ moon: Moon,
174
+ globe: Globe,
175
+ filter: Funnel,
176
+ "list-filter": ListFilter,
177
+ "more-horizontal": Ellipsis,
178
+ "more-vertical": EllipsisVertical,
179
+ refresh: RefreshCcw,
180
+ save: Save,
181
+ file: File,
182
+ folder: Folder,
183
+ image: Image,
184
+ camera: Camera,
185
+ chart: ChartColumn,
186
+ table: Table,
187
+ list: List,
188
+ grid: LayoutGrid,
189
+ tag: Tag,
190
+ "shopping-cart": ShoppingCart,
191
+ "credit-card": CreditCard,
192
+ package: Package,
193
+ "map-pin": MapPin,
194
+ building: Building2,
195
+ briefcase: Briefcase,
196
+ send: Send,
197
+ message: MessageCircle,
198
+ "message-square": MessageSquare,
199
+ paperclip: Paperclip,
200
+ "thumbs-up": ThumbsUp,
201
+ "thumbs-down": ThumbsDown,
202
+ zap: Zap,
203
+ flag: Flag,
204
+ key: Key,
205
+ shield: Shield,
206
+ terminal: Terminal,
207
+ code: Code,
208
+ database: Database,
209
+ cloud: Cloud,
210
+ languages: Languages,
211
+ // @pactor-app/chat 收敛(spec: chat-icon-convergence):chat 既有图标与
212
+ // 契约图标名(menu.icon / messageActions[].icon 的既有取值)直通
213
+ "chevrons-up-down": ChevronsUpDown,
214
+ "file-text": FileText,
215
+ "panel-left": PanelLeft,
216
+ "panel-right-open": PanelRightOpen,
217
+ square: Square,
218
+ history: History,
219
+ "rotate-ccw": RotateCcw,
220
+ quote: Quote,
221
+ chat: MessageSquare,
222
+ brain: Brain
223
+ };
224
+ function normalizeIconName(name) {
225
+ return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[_\s]+/g, "-").toLowerCase();
226
+ }
227
+ var sizePx = {
228
+ sm: 16,
229
+ default: 20,
230
+ lg: 24
231
+ };
232
+ function Icon({
233
+ name,
234
+ size = "default",
235
+ color,
236
+ strokeWidth,
237
+ className,
238
+ style
239
+ }) {
240
+ const key = name ? normalizeIconName(name) : "";
241
+ const Lucide = ICONS[key];
242
+ const px = typeof size === "number" ? size : sizePx[size];
243
+ if (!Lucide) {
244
+ return /* @__PURE__ */ jsx(
245
+ CircleQuestionMark,
246
+ {
247
+ "data-slot": "icon",
248
+ "data-unknown": name,
249
+ size: px,
250
+ color,
251
+ strokeWidth,
252
+ className: cn("shrink-0 text-muted-foreground", className),
253
+ style,
254
+ "aria-hidden": "true"
255
+ }
256
+ );
257
+ }
258
+ return /* @__PURE__ */ jsx(
259
+ Lucide,
260
+ {
261
+ "data-slot": "icon",
262
+ size: px,
263
+ color,
264
+ strokeWidth,
265
+ className: cn("shrink-0", className),
266
+ style,
267
+ "aria-hidden": "true"
268
+ }
269
+ );
270
+ }
271
+
272
+ // src/components/components/Sidebar/rail-tooltip.tsx
273
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
274
+ function RailTooltip({
275
+ label,
276
+ children
277
+ }) {
278
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
279
+ /* @__PURE__ */ jsx2(TooltipTrigger, { render: children }),
280
+ /* @__PURE__ */ jsx2(TooltipContent, { side: "right", sideOffset: 8, children: label })
281
+ ] });
282
+ }
283
+
284
+ // src/components/components/Sidebar/index.tsx
285
+ import { useI18n, useRenderer } from "@pactor-app/runtime";
286
+ import {
287
+ useEffect,
288
+ useRef
289
+ } from "react";
290
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
291
+ function useSidebarDrawer() {
292
+ try {
293
+ const ctx = useSidebar();
294
+ return {
295
+ close: () => ctx.setOpenMobile(false),
296
+ collapsed: ctx.state === "collapsed"
297
+ };
298
+ } catch {
299
+ return null;
300
+ }
301
+ }
302
+ function useOptionalRenderer() {
303
+ try {
304
+ return useRenderer();
305
+ } catch {
306
+ return null;
307
+ }
308
+ }
309
+ function SidebarContentSlot({ content }) {
310
+ const renderer = useOptionalRenderer();
311
+ if (renderer !== null && typeof content === "object" && content !== null && !("$$typeof" in content) && "type" in content) {
312
+ return /* @__PURE__ */ jsx3(Fragment, { children: renderer.renderChildren([content]) });
313
+ }
314
+ return /* @__PURE__ */ jsx3(Fragment, { children: content });
315
+ }
316
+ function isBrandObject(brand) {
317
+ return typeof brand === "object" && brand !== null && !("$$typeof" in brand) && "title" in brand;
318
+ }
319
+ function BrandNode({ brand, collapsed }) {
320
+ if (brand === void 0 || brand === null) {
321
+ return null;
322
+ }
323
+ if (isBrandObject(brand)) {
324
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
325
+ brand.logo ? /* @__PURE__ */ jsx3(
326
+ "img",
327
+ {
328
+ "data-slot": "sidebar-brand-logo",
329
+ src: brand.logo,
330
+ alt: brand.title,
331
+ className: "size-6 shrink-0"
332
+ }
333
+ ) : null,
334
+ collapsed ? null : /* @__PURE__ */ jsx3("span", { className: "truncate text-sm font-semibold", children: brand.title })
335
+ ] });
336
+ }
337
+ return /* @__PURE__ */ jsx3(Fragment, { children: brand });
338
+ }
339
+ function SidebarNavItems({ items }) {
340
+ return /* @__PURE__ */ jsx3(SidebarMenu, { children: items.map((item, index) => /* @__PURE__ */ jsx3(SidebarNavEntry, { item, depth: 0 }, item.href ?? item.label ?? index)) });
341
+ }
342
+ function SidebarNavEntry({ item, depth }) {
343
+ const iconNode = item.icon ? /* @__PURE__ */ jsx3(Icon, { name: item.icon, size: "sm" }) : null;
344
+ const labelNode = item.label;
345
+ const button = item.href ? /* @__PURE__ */ jsx3(SidebarMenuButton, { asChild: true, tooltip: item.label, children: /* @__PURE__ */ jsxs2("a", { href: item.href, children: [
346
+ iconNode,
347
+ /* @__PURE__ */ jsx3("span", { children: labelNode })
348
+ ] }) }) : /* @__PURE__ */ jsxs2(SidebarMenuButton, { tooltip: item.label, children: [
349
+ iconNode,
350
+ /* @__PURE__ */ jsx3("span", { children: labelNode })
351
+ ] });
352
+ return /* @__PURE__ */ jsxs2(SidebarMenuItem, { children: [
353
+ button,
354
+ item.children && item.children.length > 0 && /* @__PURE__ */ jsx3("div", { className: cn("ml-4"), children: item.children.map((child, index) => /* @__PURE__ */ jsx3(
355
+ SidebarNavEntry,
356
+ {
357
+ item: child,
358
+ depth: depth + 1
359
+ },
360
+ child.href ?? child.label ?? index
361
+ )) })
362
+ ] });
363
+ }
364
+ function Sidebar({
365
+ brand,
366
+ items = [],
367
+ content,
368
+ sidebarFooter,
369
+ collapsible,
370
+ onCollapse,
371
+ locationKey,
372
+ drawer = true,
373
+ className,
374
+ style,
375
+ children
376
+ }) {
377
+ return /* @__PURE__ */ jsx3(
378
+ SidebarProvider,
379
+ {
380
+ defaultOpen: true,
381
+ className,
382
+ style,
383
+ children: /* @__PURE__ */ jsx3(
384
+ SidebarInner,
385
+ {
386
+ brand,
387
+ items,
388
+ content,
389
+ sidebarFooter,
390
+ collapsible,
391
+ onCollapse,
392
+ locationKey,
393
+ drawer,
394
+ children
395
+ }
396
+ )
397
+ }
398
+ );
399
+ }
400
+ function SidebarInner({
401
+ brand,
402
+ items = [],
403
+ content,
404
+ sidebarFooter,
405
+ collapsible,
406
+ onCollapse,
407
+ locationKey,
408
+ drawer = true,
409
+ children
410
+ }) {
411
+ const { t } = useI18n();
412
+ const isMobile = useIsMobile();
413
+ const { state, setOpenMobile, toggleSidebar } = useSidebar();
414
+ const collapsed = state === "collapsed";
415
+ const prevCollapsed = useRef(collapsed);
416
+ useEffect(() => {
417
+ if (prevCollapsed.current !== collapsed) {
418
+ prevCollapsed.current = collapsed;
419
+ onCollapse?.(collapsed);
420
+ }
421
+ }, [collapsed, onCollapse]);
422
+ useEffect(() => {
423
+ if (locationKey !== void 0) {
424
+ setOpenMobile(false);
425
+ }
426
+ }, [locationKey, setOpenMobile]);
427
+ const collapsedEffective = collapsible === true && collapsed && !isMobile;
428
+ const brandNode = /* @__PURE__ */ jsx3(BrandNode, { brand, collapsed: collapsedEffective });
429
+ const sidebarContent = content !== void 0 && content !== null ? /* @__PURE__ */ jsx3(SidebarContentSlot, { content }) : items.length > 0 ? /* @__PURE__ */ jsx3(SidebarNavItems, { items }) : null;
430
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
431
+ /* @__PURE__ */ jsxs2(
432
+ SidebarRoot,
433
+ {
434
+ collapsible: collapsible ? "icon" : "offcanvas",
435
+ children: [
436
+ (brand !== void 0 || collapsible) && /* @__PURE__ */ jsx3(SidebarHeader, { children: /* @__PURE__ */ jsxs2(
437
+ "div",
438
+ {
439
+ "data-slot": "sidebar-brand",
440
+ className: cn(
441
+ "flex h-14 shrink-0 items-center gap-2 px-2",
442
+ collapsedEffective && "justify-center px-0"
443
+ ),
444
+ children: [
445
+ collapsedEffective ? null : /* @__PURE__ */ jsx3("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: brandNode }),
446
+ collapsible && !isMobile && /* @__PURE__ */ jsx3(
447
+ "button",
448
+ {
449
+ type: "button",
450
+ "data-slot": "sidebar-collapse-trigger",
451
+ "aria-label": collapsedEffective ? t("pactor.layout.expandSidebar") : t("pactor.layout.collapseSidebar"),
452
+ "aria-expanded": !collapsedEffective,
453
+ className: "flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md text-sidebar-foreground/60 transition-colors hover:bg-sidebar-accent hover:text-sidebar-foreground",
454
+ onClick: toggleSidebar,
455
+ children: /* @__PURE__ */ jsx3(Icon, { name: collapsedEffective ? "chevron-right" : "chevron-left", size: 16 })
456
+ }
457
+ )
458
+ ]
459
+ }
460
+ ) }),
461
+ /* @__PURE__ */ jsx3(SidebarContent, { children: sidebarContent }),
462
+ sidebarFooter !== void 0 && sidebarFooter !== null && !collapsedEffective && /* @__PURE__ */ jsx3(SidebarFooter, { children: sidebarFooter })
463
+ ]
464
+ }
465
+ ),
466
+ /* @__PURE__ */ jsxs2(SidebarInset, { children: [
467
+ drawer && /* @__PURE__ */ jsxs2(
468
+ "div",
469
+ {
470
+ "data-slot": "sidebar-topbar",
471
+ className: "flex h-14 items-center gap-2 border-b border-sidebar-border bg-sidebar px-3 md:hidden",
472
+ children: [
473
+ /* @__PURE__ */ jsx3(
474
+ "button",
475
+ {
476
+ type: "button",
477
+ "data-slot": "sidebar-menu-trigger",
478
+ "aria-label": t("pactor.layout.openNavigation"),
479
+ className: "flex size-8 items-center justify-center rounded-md text-sidebar-foreground/60 transition-colors hover:bg-sidebar-accent hover:text-sidebar-foreground",
480
+ onClick: toggleSidebar,
481
+ children: /* @__PURE__ */ jsx3(Icon, { name: "menu", size: 18 })
482
+ }
483
+ ),
484
+ brandNode
485
+ ]
486
+ }
487
+ ),
488
+ children
489
+ ] })
490
+ ] });
491
+ }
492
+
493
+ // src/components/components/Menu/index.tsx
494
+ import { useEffect as useEffect2, useRef as useRef2, useState } from "react";
495
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
496
+ function collectAncestors(items, target, into, trail = []) {
497
+ for (const item of items) {
498
+ if (item.key === target) {
499
+ for (const key of trail) into.add(key);
500
+ return true;
501
+ }
502
+ if (item.children?.length && collectAncestors(item.children, target, into, [...trail, item.key])) {
503
+ return true;
504
+ }
505
+ }
506
+ return false;
507
+ }
508
+ function Menu2({
509
+ items = [],
510
+ mode = "inline",
511
+ selectedKey,
512
+ collapsible = false,
513
+ defaultExpandedKeys,
514
+ onSelect,
515
+ className,
516
+ style
517
+ }) {
518
+ const drawer = useSidebarDrawer();
519
+ const collapsed = mode === "inline" && drawer?.collapsed === true;
520
+ const collapsibleOn = collapsible && mode === "inline" && !collapsed;
521
+ const [expandedKeys, setExpandedKeys] = useState(() => {
522
+ const initial = new Set(defaultExpandedKeys ?? []);
523
+ if (selectedKey !== void 0) {
524
+ collectAncestors(items, selectedKey, initial);
525
+ }
526
+ return initial;
527
+ });
528
+ const toggleExpanded = (key) => {
529
+ setExpandedKeys((prev) => {
530
+ const next = new Set(prev);
531
+ if (next.has(key)) {
532
+ next.delete(key);
533
+ } else {
534
+ next.add(key);
535
+ }
536
+ return next;
537
+ });
538
+ };
539
+ let previousGroup;
540
+ return /* @__PURE__ */ jsx4(
541
+ "nav",
542
+ {
543
+ "data-slot": "menu",
544
+ "data-mode": mode,
545
+ "data-collapsed": collapsed || void 0,
546
+ className: cn(
547
+ mode === "horizontal" ? "flex items-center gap-1" : "flex flex-col gap-0.5 p-2",
548
+ className
549
+ ),
550
+ style,
551
+ children: items.map((item) => {
552
+ let groupLabel;
553
+ if (!collapsed && mode === "inline" && item.group !== void 0 && item.group !== previousGroup) {
554
+ groupLabel = item.group;
555
+ }
556
+ previousGroup = item.group;
557
+ return /* @__PURE__ */ jsxs3("div", { "data-slot": "menu-group-entry", children: [
558
+ groupLabel !== void 0 && /* @__PURE__ */ jsx4(
559
+ "div",
560
+ {
561
+ "data-slot": "menu-group",
562
+ className: "px-3 pb-1 pt-3 text-xs font-medium text-muted-foreground first:pt-1",
563
+ children: groupLabel
564
+ }
565
+ ),
566
+ /* @__PURE__ */ jsx4(
567
+ MenuEntry,
568
+ {
569
+ item,
570
+ mode,
571
+ depth: 0,
572
+ selectedKey,
573
+ onSelect,
574
+ collapsed,
575
+ collapsible: collapsibleOn,
576
+ expandedKeys,
577
+ onToggle: toggleExpanded
578
+ }
579
+ )
580
+ ] }, item.key);
581
+ })
582
+ }
583
+ );
584
+ }
585
+ function MenuEntry({
586
+ item,
587
+ mode,
588
+ depth,
589
+ selectedKey,
590
+ onSelect,
591
+ collapsed = false,
592
+ collapsible = false,
593
+ expandedKeys,
594
+ onToggle
595
+ }) {
596
+ const selected = item.key === selectedKey;
597
+ const hasChildren = (item.children?.length ?? 0) > 0;
598
+ const isDirectory = collapsible && hasChildren;
599
+ const expanded = isDirectory && expandedKeys?.has(item.key) === true;
600
+ const railDirectory = collapsed && hasChildren;
601
+ const [flyoutOpen, setFlyoutOpen] = useState(false);
602
+ const flyoutTimer = useRef2(void 0);
603
+ const flyoutOpenNow = () => {
604
+ window.clearTimeout(flyoutTimer.current);
605
+ setFlyoutOpen(true);
606
+ };
607
+ const flyoutCloseLater = () => {
608
+ window.clearTimeout(flyoutTimer.current);
609
+ flyoutTimer.current = window.setTimeout(() => setFlyoutOpen(false), 200);
610
+ };
611
+ useEffect2(() => () => window.clearTimeout(flyoutTimer.current), []);
612
+ const button = /* @__PURE__ */ jsxs3(
613
+ "button",
614
+ {
615
+ type: "button",
616
+ "data-slot": "menu-item",
617
+ "aria-current": selected ? "page" : void 0,
618
+ "aria-expanded": isDirectory ? expanded : railDirectory ? flyoutOpen : void 0,
619
+ disabled: item.disabled,
620
+ className: cn(
621
+ "flex w-full items-center gap-2 rounded-md text-sm transition-colors",
622
+ mode === "horizontal" ? "px-3 py-2" : "px-3 py-2 text-left",
623
+ collapsed && "justify-center px-0",
624
+ selected ? "bg-(--menu-active-background) font-medium text-(--menu-active-foreground)" : "cursor-pointer text-muted-foreground hover:bg-(--menu-hover-background)/50 hover:text-foreground",
625
+ item.disabled && "cursor-not-allowed opacity-50 hover:bg-transparent hover:text-muted-foreground"
626
+ ),
627
+ style: mode === "inline" && depth > 0 && !collapsed ? { paddingLeft: 12 + depth * 16 } : void 0,
628
+ onMouseEnter: railDirectory ? flyoutOpenNow : void 0,
629
+ onMouseLeave: railDirectory ? flyoutCloseLater : void 0,
630
+ onClick: () => {
631
+ if (item.disabled) return;
632
+ if (railDirectory) return;
633
+ if (isDirectory) {
634
+ onToggle?.(item.key);
635
+ } else {
636
+ onSelect?.(item.key);
637
+ }
638
+ },
639
+ children: [
640
+ item.icon ? /* @__PURE__ */ jsx4(Icon, { name: item.icon, size: "sm" }) : null,
641
+ collapsed ? null : /* @__PURE__ */ jsx4("span", { className: "min-w-0 flex-1 truncate text-left", children: item.label }),
642
+ item.dot && !collapsed ? /* @__PURE__ */ jsx4("span", { "data-slot": "menu-item-dot", className: "size-1.5 shrink-0 rounded-full bg-destructive" }) : null,
643
+ item.badge !== void 0 && !collapsed ? /* @__PURE__ */ jsx4(
644
+ "span",
645
+ {
646
+ "data-slot": "menu-item-badge",
647
+ className: "shrink-0 rounded-full bg-muted px-1.5 py-0.5 text-xs text-muted-foreground",
648
+ children: item.badge
649
+ }
650
+ ) : null,
651
+ isDirectory ? /* @__PURE__ */ jsx4(
652
+ "span",
653
+ {
654
+ "data-slot": "menu-item-chevron",
655
+ className: cn(
656
+ "shrink-0 transition-transform",
657
+ expanded && "rotate-180"
658
+ ),
659
+ children: /* @__PURE__ */ jsx4(Icon, { name: "chevron-down", size: "sm" })
660
+ }
661
+ ) : null
662
+ ]
663
+ }
664
+ );
665
+ return /* @__PURE__ */ jsxs3("div", { "data-slot": "menu-entry", "data-key": item.key, children: [
666
+ railDirectory ? /* @__PURE__ */ jsxs3(Popover, { open: flyoutOpen, onOpenChange: setFlyoutOpen, children: [
667
+ /* @__PURE__ */ jsx4(PopoverTrigger, { render: button }),
668
+ /* @__PURE__ */ jsxs3(
669
+ PopoverContent,
670
+ {
671
+ "data-slot": "menu-flyout",
672
+ side: "right",
673
+ align: "start",
674
+ sideOffset: 8,
675
+ className: "max-h-[70vh] w-48 overflow-auto p-1",
676
+ initialFocus: false,
677
+ onMouseEnter: flyoutOpenNow,
678
+ onMouseLeave: flyoutCloseLater,
679
+ onClick: (event) => {
680
+ if (event.target.closest("[data-slot=menu-item]")) {
681
+ setFlyoutOpen(false);
682
+ }
683
+ },
684
+ children: [
685
+ /* @__PURE__ */ jsx4("div", { className: "px-3 pt-2 pb-1 text-xs font-semibold text-muted-foreground", children: item.label }),
686
+ item.children?.map((child) => /* @__PURE__ */ jsx4(
687
+ MenuEntry,
688
+ {
689
+ item: child,
690
+ mode: "inline",
691
+ depth: 0,
692
+ selectedKey,
693
+ onSelect
694
+ },
695
+ child.key
696
+ ))
697
+ ]
698
+ }
699
+ )
700
+ ] }) : collapsed ? /* @__PURE__ */ jsx4(RailTooltip, { label: item.label, children: button }) : button,
701
+ railDirectory || isDirectory && !expanded ? null : item.children?.map((child) => /* @__PURE__ */ jsx4(
702
+ MenuEntry,
703
+ {
704
+ item: child,
705
+ mode,
706
+ depth: depth + 1,
707
+ selectedKey,
708
+ onSelect,
709
+ collapsed,
710
+ collapsible,
711
+ expandedKeys,
712
+ onToggle
713
+ },
714
+ child.key
715
+ ))
716
+ ] });
717
+ }
718
+
719
+ export {
720
+ ICONS,
721
+ normalizeIconName,
722
+ Icon,
723
+ RailTooltip,
724
+ useSidebarDrawer,
725
+ Sidebar,
726
+ Menu2 as Menu
727
+ };