@fayz-ai/ui 0.22.0 → 0.23.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.
Files changed (71) hide show
  1. package/dist/analytics/AnalyticsCard.d.ts.map +1 -1
  2. package/dist/analytics/AnalyticsControls.d.ts.map +1 -1
  3. package/dist/analytics/DateRangeControl.d.ts +14 -0
  4. package/dist/analytics/DateRangeControl.d.ts.map +1 -0
  5. package/dist/analytics/StatementTable.d.ts +22 -0
  6. package/dist/analytics/StatementTable.d.ts.map +1 -0
  7. package/dist/analytics/context.d.ts +8 -0
  8. package/dist/analytics/context.d.ts.map +1 -1
  9. package/dist/analytics/derive.d.ts +13 -0
  10. package/dist/analytics/derive.d.ts.map +1 -1
  11. package/dist/analytics/index.d.ts +7 -1
  12. package/dist/analytics/index.d.ts.map +1 -1
  13. package/dist/analytics/statement.d.ts +58 -0
  14. package/dist/analytics/statement.d.ts.map +1 -0
  15. package/dist/{chunk-E44WOPCR.js → chunk-HO2P2XB4.js} +428 -58
  16. package/dist/chunk-HO2P2XB4.js.map +1 -0
  17. package/dist/{chunk-7G3O54CC.js → chunk-L4TXDKMN.js} +5 -5
  18. package/dist/chunk-L4TXDKMN.js.map +1 -0
  19. package/dist/{chunk-DHNUZF2X.js → chunk-OWN3GFDG.js} +4 -3
  20. package/dist/chunk-OWN3GFDG.js.map +1 -0
  21. package/dist/{chunk-PQUS22JE.js → chunk-RRNMNFLF.js} +483 -794
  22. package/dist/chunk-RRNMNFLF.js.map +1 -0
  23. package/dist/chunk-UP7WVKSU.js +631 -0
  24. package/dist/chunk-UP7WVKSU.js.map +1 -0
  25. package/dist/{chunk-ZSOT7KTE.js → chunk-XEUIYSW2.js} +321 -361
  26. package/dist/chunk-XEUIYSW2.js.map +1 -0
  27. package/dist/{chunk-SUSW4LSW.js → chunk-XKFYX3DG.js} +5 -5
  28. package/dist/{chunk-SUSW4LSW.js.map → chunk-XKFYX3DG.js.map} +1 -1
  29. package/dist/dashboard/index.js +4 -4
  30. package/dist/icons.js +1 -1
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +672 -87
  34. package/dist/index.js.map +1 -1
  35. package/dist/layout/AppShell.d.ts +7 -1
  36. package/dist/layout/AppShell.d.ts.map +1 -1
  37. package/dist/layout/ShellSearch.d.ts +53 -0
  38. package/dist/layout/ShellSearch.d.ts.map +1 -0
  39. package/dist/layout/Sidebar.d.ts +10 -6
  40. package/dist/layout/Sidebar.d.ts.map +1 -1
  41. package/dist/layout/Takeover.d.ts.map +1 -1
  42. package/dist/layout/index.d.ts +1 -0
  43. package/dist/layout/index.d.ts.map +1 -1
  44. package/dist/layout/index.js +4 -4
  45. package/dist/primitives/data-table.d.ts.map +1 -1
  46. package/dist/primitives/date-range-chip.d.ts +32 -0
  47. package/dist/primitives/date-range-chip.d.ts.map +1 -0
  48. package/dist/primitives/header-tabs.d.ts.map +1 -1
  49. package/dist/primitives/index.d.ts +2 -1
  50. package/dist/primitives/index.d.ts.map +1 -1
  51. package/dist/primitives/index.js +5 -5
  52. package/dist/primitives/list-view.d.ts +43 -1
  53. package/dist/primitives/list-view.d.ts.map +1 -1
  54. package/dist/primitives/modal.d.ts +2 -0
  55. package/dist/primitives/modal.d.ts.map +1 -1
  56. package/dist/primitives/page-actions.d.ts +14 -0
  57. package/dist/primitives/page-actions.d.ts.map +1 -1
  58. package/dist/primitives/page-toolbar.d.ts +16 -1
  59. package/dist/primitives/page-toolbar.d.ts.map +1 -1
  60. package/dist/primitives/segmented-control.d.ts.map +1 -1
  61. package/dist/stores/layout.store.d.ts +20 -1
  62. package/dist/stores/layout.store.d.ts.map +1 -1
  63. package/dist/styles.css +58 -0
  64. package/package.json +2 -2
  65. package/dist/chunk-7G3O54CC.js.map +0 -1
  66. package/dist/chunk-DHNUZF2X.js.map +0 -1
  67. package/dist/chunk-E44WOPCR.js.map +0 -1
  68. package/dist/chunk-HKGTF2YA.js +0 -117
  69. package/dist/chunk-HKGTF2YA.js.map +0 -1
  70. package/dist/chunk-PQUS22JE.js.map +0 -1
  71. package/dist/chunk-ZSOT7KTE.js.map +0 -1
@@ -0,0 +1,631 @@
1
+ import { usePageRailSlot, useModuleHeaderActionsSlot, useRegisterPageActions, useHasPageHeaderHost, useCrossModuleBack, useBackHandler, PageHeaderCrumb, usePageHeader, useHasPageHeaderBack, PageTitlePortal } from './chunk-RRNMNFLF.js';
2
+ import { cn } from './chunk-OKZ6WQB3.js';
3
+ import { ICON_MAP } from './chunk-OWN3GFDG.js';
4
+ import * as React3 from 'react';
5
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
6
+ import { X, ChevronDown, ChevronRight, ChevronLeft, Crown } from 'lucide-react';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+ import { createPortal } from 'react-dom';
9
+ import { useTranslation } from '@fayz-ai/core';
10
+
11
+ var STYLE_ID = "saas-sheet-styles";
12
+ if (typeof document !== "undefined" && !document.getElementById(STYLE_ID)) {
13
+ const style = document.createElement("style");
14
+ style.id = STYLE_ID;
15
+ style.textContent = `
16
+ @keyframes saas-sheet-fade-in { from { opacity: 0 } to { opacity: 1 } }
17
+ @keyframes saas-sheet-fade-out { from { opacity: 1 } to { opacity: 0 } }
18
+ @keyframes saas-sheet-slide-in { from { transform: translateX(100%) } to { transform: translateX(0) } }
19
+ @keyframes saas-sheet-slide-out { from { transform: translateX(0) } to { transform: translateX(100%) } }
20
+ .saas-sheet-overlay[data-state="open"] { animation: saas-sheet-fade-in 200ms ease-out }
21
+ .saas-sheet-overlay[data-state="closed"] { animation: saas-sheet-fade-out 150ms ease-in }
22
+ .saas-sheet-content[data-state="open"] { animation: saas-sheet-slide-in 280ms cubic-bezier(0.16, 1, 0.3, 1) }
23
+ .saas-sheet-content[data-state="closed"] { animation: saas-sheet-slide-out 200ms ease-in }
24
+ `;
25
+ document.head.appendChild(style);
26
+ }
27
+ var Sheet = DialogPrimitive.Root;
28
+ var SheetTrigger = DialogPrimitive.Trigger;
29
+ var SheetClose = DialogPrimitive.Close;
30
+ var SheetPortal = DialogPrimitive.Portal;
31
+ var SheetOverlay = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
32
+ DialogPrimitive.Overlay,
33
+ {
34
+ ref,
35
+ className: cn(
36
+ "saas-sheet-overlay fixed inset-0 z-[100] bg-black/40 backdrop-blur-[2px]",
37
+ className
38
+ ),
39
+ ...props
40
+ }
41
+ ));
42
+ SheetOverlay.displayName = "SheetOverlay";
43
+ var SheetContent = React3.forwardRef(({ className, children, width, hideClose, overlay = "blur", onPointerDownOutside, onInteractOutside, ...props }, ref) => /* @__PURE__ */ jsxs(SheetPortal, { children: [
44
+ /* @__PURE__ */ jsx(SheetOverlay, { className: overlay === "none" ? "bg-transparent backdrop-blur-0" : overlay === "dim" ? "backdrop-blur-0" : void 0 }),
45
+ /* @__PURE__ */ jsxs(
46
+ DialogPrimitive.Content,
47
+ {
48
+ ref,
49
+ onPointerDownOutside: (e) => {
50
+ const target = e.target;
51
+ if (target.closest("[data-modal-passthrough]") || target.closest("[data-radix-popper-content-wrapper]")) {
52
+ e.preventDefault();
53
+ }
54
+ onPointerDownOutside?.(e);
55
+ },
56
+ onInteractOutside: (e) => {
57
+ const target = e.target;
58
+ if (target.closest("[data-modal-passthrough]") || target.closest("[data-radix-popper-content-wrapper]")) {
59
+ e.preventDefault();
60
+ }
61
+ onInteractOutside?.(e);
62
+ },
63
+ className: cn(
64
+ "fayz-glass-surface saas-sheet-content fixed inset-y-0 right-0 z-[100] flex flex-col border-l bg-card shadow-2xl outline-none",
65
+ "w-full",
66
+ width ?? "max-w-md",
67
+ className
68
+ ),
69
+ ...props,
70
+ children: [
71
+ children,
72
+ !hideClose && /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 z-10 flex h-7 w-7 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring", children: [
73
+ /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
74
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
75
+ ] })
76
+ ]
77
+ }
78
+ )
79
+ ] }));
80
+ SheetContent.displayName = "SheetContent";
81
+ function SheetHeader({ className, ...props }) {
82
+ return /* @__PURE__ */ jsx(
83
+ "div",
84
+ {
85
+ className: cn("flex flex-col gap-1 px-5 py-4 border-b shrink-0", className),
86
+ ...props
87
+ }
88
+ );
89
+ }
90
+ SheetHeader.displayName = "SheetHeader";
91
+ function SheetFooter({ className, ...props }) {
92
+ return /* @__PURE__ */ jsx(
93
+ "div",
94
+ {
95
+ className: cn("flex items-center gap-2 px-5 py-3 border-t shrink-0", className),
96
+ ...props
97
+ }
98
+ );
99
+ }
100
+ SheetFooter.displayName = "SheetFooter";
101
+ var SheetTitle = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
102
+ DialogPrimitive.Title,
103
+ {
104
+ ref,
105
+ className: cn("text-sm font-semibold leading-none tracking-tight", className),
106
+ ...props
107
+ }
108
+ ));
109
+ SheetTitle.displayName = "SheetTitle";
110
+ var SheetDescription = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
111
+ DialogPrimitive.Description,
112
+ {
113
+ ref,
114
+ className: cn("text-xs text-muted-foreground", className),
115
+ ...props
116
+ }
117
+ ));
118
+ SheetDescription.displayName = "SheetDescription";
119
+ function SheetBody({ className, ...props }) {
120
+ return /* @__PURE__ */ jsx(
121
+ "div",
122
+ {
123
+ className: cn("flex-1 overflow-y-auto px-5 py-5", className),
124
+ ...props
125
+ }
126
+ );
127
+ }
128
+ SheetBody.displayName = "SheetBody";
129
+ function HeaderTabs({
130
+ tabs,
131
+ value,
132
+ onChange,
133
+ className,
134
+ fill,
135
+ anchorPrefix,
136
+ ...rest
137
+ }) {
138
+ return /* @__PURE__ */ jsx(
139
+ "div",
140
+ {
141
+ role: "tablist",
142
+ "aria-label": rest["aria-label"],
143
+ className: cn(
144
+ "inline-flex max-w-full gap-5 overflow-x-auto scrollbar-none",
145
+ fill ? "items-stretch" : "items-center",
146
+ className
147
+ ),
148
+ children: tabs.map((tab) => {
149
+ const active = tab.value === value;
150
+ const Icon = tab.icon;
151
+ const box = cn(
152
+ "relative flex shrink-0 items-center gap-1.5 whitespace-nowrap text-sm transition-colors",
153
+ fill ? "h-full" : "pb-1.5",
154
+ active ? "font-medium text-foreground" : "text-muted-foreground hover:text-foreground",
155
+ tab.dim && "opacity-50 hover:opacity-100"
156
+ );
157
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
158
+ Icon ? /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }) : null,
159
+ /* @__PURE__ */ jsx("span", { children: tab.label }),
160
+ tab.count != null && /* @__PURE__ */ jsx("span", { className: cn(
161
+ "ml-0.5 rounded-full px-1.5 text-[11px] tabular-nums",
162
+ active ? "bg-muted text-foreground" : "bg-muted/70 text-muted-foreground"
163
+ ), children: tab.count }),
164
+ tab.badge
165
+ ] });
166
+ const underline = active ? /* @__PURE__ */ jsx("span", { className: "absolute inset-x-0 bottom-0 h-0.5 rounded-full bg-foreground" }) : null;
167
+ if (!tab.trailing) {
168
+ return /* @__PURE__ */ jsxs(
169
+ "button",
170
+ {
171
+ type: "button",
172
+ role: "tab",
173
+ "aria-selected": active,
174
+ "data-tour": anchorPrefix ? `${anchorPrefix}.${tab.value}` : void 0,
175
+ onClick: () => onChange(tab.value),
176
+ className: box,
177
+ children: [
178
+ inner,
179
+ underline
180
+ ]
181
+ },
182
+ tab.value
183
+ );
184
+ }
185
+ return /* @__PURE__ */ jsxs("div", { className: box, children: [
186
+ /* @__PURE__ */ jsx(
187
+ "button",
188
+ {
189
+ type: "button",
190
+ role: "tab",
191
+ "aria-selected": active,
192
+ "data-tour": anchorPrefix ? `${anchorPrefix}.${tab.value}` : void 0,
193
+ onClick: () => onChange(tab.value),
194
+ className: "flex items-center gap-1.5 whitespace-nowrap",
195
+ children: inner
196
+ }
197
+ ),
198
+ tab.trailing,
199
+ underline
200
+ ] }, tab.value);
201
+ })
202
+ }
203
+ );
204
+ }
205
+ function PageTabs({ actions, className, ...props }) {
206
+ return /* @__PURE__ */ jsxs(
207
+ "div",
208
+ {
209
+ style: { background: "var(--page-surface, hsl(var(--background)))" },
210
+ className: cn(
211
+ "sticky top-0 z-20 -mx-3 -mt-3 mb-4 flex flex-wrap items-end justify-between gap-3 border-b border-border px-3 pt-2 md:-mx-6 md:-mt-4 md:px-6",
212
+ // 48px no desktop, a mesma altura do subcabeçalho dos painéis do
213
+ // assistente à direita (TasksFilterBar, NotebookPanel). Eram 34 aqui e
214
+ // 48 lá: os dois fios que fecham as duas faixas paravam em alturas
215
+ // diferentes, lado a lado na mesma tela. `min-h` e não `h` porque a
216
+ // faixa QUEBRA — doze abas no Financeiro — e uma altura fixa cortaria a
217
+ // segunda linha.
218
+ "md:min-h-[2.5rem]",
219
+ className
220
+ ),
221
+ children: [
222
+ /* @__PURE__ */ jsx(HeaderTabs, { ...props, className: "-mb-px" }),
223
+ actions && /* @__PURE__ */ jsx("div", { className: "ml-auto flex shrink-0 items-center gap-2 pb-1.5", children: actions })
224
+ ]
225
+ }
226
+ );
227
+ }
228
+ var SIZE = {
229
+ sm: { container: "h-[26px]", segment: "px-2.5 text-xs" },
230
+ md: { container: "h-[30px]", segment: "px-3 text-sm" }
231
+ };
232
+ function SegmentedControl({
233
+ options,
234
+ value,
235
+ onChange,
236
+ size = "sm",
237
+ className,
238
+ ...rest
239
+ }) {
240
+ const items = options.map((o) => typeof o === "string" ? { value: o, label: o } : o);
241
+ return /* @__PURE__ */ jsx(
242
+ "div",
243
+ {
244
+ role: "tablist",
245
+ "aria-label": rest["aria-label"],
246
+ className: cn(
247
+ // `fz-segmented`: gancho para a faixa do cabeçalho trocar este chrome
248
+ // de cartão pelo de faixa (ver .fz-on-band em styles.css).
249
+ "fz-segmented inline-flex items-center rounded-button border border-border bg-card p-0.5 shadow-button",
250
+ SIZE[size].container,
251
+ className
252
+ ),
253
+ children: items.map((item) => {
254
+ const active = item.value === value;
255
+ return /* @__PURE__ */ jsx(
256
+ "button",
257
+ {
258
+ type: "button",
259
+ role: "tab",
260
+ "aria-selected": active,
261
+ onClick: () => onChange(item.value),
262
+ className: cn(
263
+ "flex h-full items-center rounded-button font-semibold transition-colors",
264
+ SIZE[size].segment,
265
+ active ? "bg-foreground text-background" : "text-muted-foreground hover:bg-muted/60"
266
+ ),
267
+ children: item.label
268
+ },
269
+ item.value
270
+ );
271
+ })
272
+ }
273
+ );
274
+ }
275
+ var NavTransitionContext = React3.createContext("slide");
276
+ function NavTransitionProvider({ value, children }) {
277
+ return /* @__PURE__ */ jsx(NavTransitionContext.Provider, { value, children });
278
+ }
279
+ function useNavTransition() {
280
+ return React3.useContext(NavTransitionContext);
281
+ }
282
+ function resolveTransitionClass(transition, direction) {
283
+ if (transition === "none") return "";
284
+ if (transition === "fade") return "saas-page-enter";
285
+ if (direction === "back") return "saas-nav-back";
286
+ if (direction === "forward") return "saas-nav-forward";
287
+ return "saas-page-enter";
288
+ }
289
+ function PageTransition({
290
+ transitionKey,
291
+ direction,
292
+ className,
293
+ children
294
+ }) {
295
+ const transition = useNavTransition();
296
+ const animClass = resolveTransitionClass(transition, direction);
297
+ return /* @__PURE__ */ jsx("div", { className: cn(animClass, className), children }, transitionKey);
298
+ }
299
+ function PageRail({ children }) {
300
+ const slot = usePageRailSlot();
301
+ if (slot) return createPortal(children, slot);
302
+ return /* @__PURE__ */ jsx(Fragment, { children });
303
+ }
304
+ function PageHeaderActions({ children }) {
305
+ const slot = useModuleHeaderActionsSlot();
306
+ useRegisterPageActions();
307
+ if (slot) return createPortal(children, slot);
308
+ return /* @__PURE__ */ jsx("div", { className: "mb-4 flex items-center justify-end gap-2", children });
309
+ }
310
+ function PremiumBadge({ className }) {
311
+ const t = useTranslation();
312
+ const tip = t("upgrade.badgeTooltip");
313
+ return /* @__PURE__ */ jsx("span", { title: tip, "aria-label": tip, className: cn("inline-flex shrink-0", className), children: /* @__PURE__ */ jsx(Crown, { className: "h-3.5 w-3.5 text-amber-500", "aria-hidden": true }) });
314
+ }
315
+ var ModuleLayoutContext = React3.createContext("rail");
316
+ function ModuleLayoutProvider({ variant, children }) {
317
+ return /* @__PURE__ */ jsx(ModuleLayoutContext.Provider, { value: variant, children });
318
+ }
319
+ function useModuleLayout() {
320
+ return React3.useContext(ModuleLayoutContext);
321
+ }
322
+ function RailNavItem({ item }) {
323
+ const [expanded, setExpanded] = React3.useState(true);
324
+ const Icon = item.icon ? ICON_MAP[item.icon] ?? null : null;
325
+ const hasChildren = item.children && item.children.length > 0;
326
+ const hasActiveChild = hasChildren && item.children.some((c) => c.active);
327
+ const isActive = item.active || hasActiveChild;
328
+ return /* @__PURE__ */ jsxs("div", { children: [
329
+ /* @__PURE__ */ jsxs(
330
+ "button",
331
+ {
332
+ type: "button",
333
+ "data-tour": `modnav.${item.id}`,
334
+ onClick: () => hasChildren ? setExpanded(!expanded) : item.onClick?.(),
335
+ className: cn(
336
+ "flex items-center gap-2 w-full rounded-md px-2.5 py-1.5 text-sm transition-colors",
337
+ isActive ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
338
+ ),
339
+ children: [
340
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }),
341
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: item.label }),
342
+ item.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" }),
343
+ hasChildren && (expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }))
344
+ ]
345
+ }
346
+ ),
347
+ hasChildren && expanded && /* @__PURE__ */ jsx("div", { className: "ml-4 mt-0.5 space-y-0.5 border-l pl-2", children: item.children.map((child) => /* @__PURE__ */ jsxs(
348
+ "button",
349
+ {
350
+ type: "button",
351
+ "data-tour": `modnav.${child.id}`,
352
+ onClick: child.onClick,
353
+ className: cn(
354
+ "flex items-center w-full rounded-md px-2.5 py-1 text-xs transition-colors",
355
+ child.active ? "text-primary font-medium bg-primary/5" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
356
+ ),
357
+ children: [
358
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: child.label }),
359
+ child.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" })
360
+ ]
361
+ },
362
+ child.id
363
+ )) })
364
+ ] });
365
+ }
366
+ function defaultChildOf(item) {
367
+ const kids = (item.children ?? []).filter((c) => c.kind !== "action");
368
+ return kids.find((c) => c.defaultChild) ?? kids.find((c) => /(^|-)list$/i.test(c.id)) ?? kids.find((c) => !/(^|-)(new|novo|nova|create)$/i.test(c.id)) ?? kids[0];
369
+ }
370
+ function MobileTabs({ nav }) {
371
+ const scrollRef = React3.useRef(null);
372
+ const [expandedId, setExpandedId] = React3.useState(null);
373
+ React3.useEffect(() => {
374
+ const container = scrollRef.current;
375
+ if (!container) return;
376
+ const activeEl = container.querySelector('[data-active="true"]');
377
+ if (activeEl) {
378
+ const left = activeEl.offsetLeft - container.offsetWidth / 2 + activeEl.offsetWidth / 2;
379
+ container.scrollTo({ left: Math.max(0, left), behavior: "smooth" });
380
+ }
381
+ }, [nav]);
382
+ return /* @__PURE__ */ jsxs("div", { className: "md:hidden -mx-1 mb-4 no-print", children: [
383
+ /* @__PURE__ */ jsx("div", { ref: scrollRef, className: "flex gap-1 px-1 pb-2 overflow-x-auto scrollbar-none", children: nav.map((item) => {
384
+ const Icon = item.icon ? ICON_MAP[item.icon] ?? null : null;
385
+ const hasChildren = item.children && item.children.length > 0;
386
+ const isActive = item.active || item.children?.some((c) => c.active);
387
+ const isExpanded = expandedId === item.id;
388
+ return /* @__PURE__ */ jsxs(
389
+ "button",
390
+ {
391
+ type: "button",
392
+ "data-active": isActive || void 0,
393
+ onClick: () => {
394
+ if (hasChildren) {
395
+ if (!isExpanded) defaultChildOf(item)?.onClick?.();
396
+ setExpandedId(isExpanded ? null : item.id);
397
+ } else {
398
+ item.onClick?.();
399
+ setExpandedId(null);
400
+ }
401
+ },
402
+ className: cn(
403
+ // This strip is the most-tapped control in most modules and it
404
+ // was 28px tall — a third under the comfortable minimum. Height
405
+ // and text step up on touch; the desktop rail is unaffected.
406
+ "flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full px-4 text-sm font-medium transition-colors",
407
+ "min-h-[2.75rem] active:scale-[0.98]",
408
+ isActive ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:text-foreground"
409
+ ),
410
+ children: [
411
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }),
412
+ item.label,
413
+ item.premium && /* @__PURE__ */ jsx(PremiumBadge, {}),
414
+ hasChildren && /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-2.5 w-2.5 transition-transform", isExpanded && "rotate-180") })
415
+ ]
416
+ },
417
+ item.id
418
+ );
419
+ }) }),
420
+ expandedId && (() => {
421
+ const item = nav.find((n) => n.id === expandedId);
422
+ const shown = (item?.children ?? []).filter((c) => c.kind !== "action");
423
+ if (shown.length < 2) return null;
424
+ return /* @__PURE__ */ jsx("div", { className: "flex gap-1 px-2 pb-2 animate-in fade-in-0 slide-in-from-top-1", children: shown.map((child) => /* @__PURE__ */ jsxs(
425
+ "button",
426
+ {
427
+ type: "button",
428
+ onClick: () => {
429
+ child.onClick?.();
430
+ setExpandedId(null);
431
+ },
432
+ className: cn(
433
+ "whitespace-nowrap rounded-full px-2.5 py-1 text-[11px] font-medium transition-colors shrink-0",
434
+ child.active ? "bg-foreground/10 text-foreground" : "text-muted-foreground hover:text-foreground"
435
+ ),
436
+ children: [
437
+ child.label,
438
+ child.premium && /* @__PURE__ */ jsx(PremiumBadge, {})
439
+ ]
440
+ },
441
+ child.id
442
+ )) });
443
+ })()
444
+ ] });
445
+ }
446
+ var BackStyleContext = React3.createContext("link");
447
+ function BackStyleProvider({ style, children }) {
448
+ return /* @__PURE__ */ jsx(BackStyleContext.Provider, { value: style, children });
449
+ }
450
+ function useBackStyle() {
451
+ return React3.useContext(BackStyleContext);
452
+ }
453
+ function SubpageHeader({ title, subtitle, icon, onBack, parentLabel, actions, backStyle, inline }) {
454
+ const t = useTranslation();
455
+ const appStyle = useBackStyle();
456
+ const hasShellBar = useHasPageHeaderHost() && !inline;
457
+ const cross = useCrossModuleBack(onBack, parentLabel);
458
+ const effectiveOnBack = inline ? onBack : cross.onBack;
459
+ const effectiveParentLabel = inline ? parentLabel : cross.parentLabel;
460
+ useBackHandler(effectiveOnBack);
461
+ const Icon = icon ? ICON_MAP[icon] ?? null : null;
462
+ if (inline && effectiveOnBack) {
463
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
464
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
465
+ /* @__PURE__ */ jsx(PageHeaderCrumb, { title, parentLabel: effectiveParentLabel, onBack: effectiveOnBack }),
466
+ actions && /* @__PURE__ */ jsx("div", { className: "no-print", children: actions })
467
+ ] }),
468
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: subtitle })
469
+ ] });
470
+ }
471
+ if (hasShellBar) {
472
+ return /* @__PURE__ */ jsx(
473
+ ShellSubpageHeader,
474
+ {
475
+ title,
476
+ subtitle,
477
+ icon: Icon,
478
+ onBack: effectiveOnBack,
479
+ parentLabel: effectiveParentLabel,
480
+ actions
481
+ }
482
+ );
483
+ }
484
+ const style = !effectiveOnBack ? "icon" : backStyle ?? appStyle;
485
+ const effectiveStyle = style !== "icon" && !effectiveParentLabel ? "icon" : style;
486
+ const titleBlock = /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
487
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
488
+ effectiveStyle === "icon" && effectiveOnBack && /* @__PURE__ */ jsx(
489
+ "button",
490
+ {
491
+ onClick: effectiveOnBack,
492
+ className: "flex h-8 w-8 items-center justify-center rounded-lg border hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors",
493
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
494
+ }
495
+ ),
496
+ Icon && /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-xl bg-muted", children: /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5 text-muted-foreground" }) }),
497
+ /* @__PURE__ */ jsxs("div", { children: [
498
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold", children: title }),
499
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: subtitle })
500
+ ] })
501
+ ] }),
502
+ actions && /* @__PURE__ */ jsx("div", { className: "no-print", children: actions })
503
+ ] });
504
+ if (effectiveStyle === "breadcrumb") {
505
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4 mb-6", children: [
506
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
507
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
508
+ /* @__PURE__ */ jsx("button", { onClick: effectiveOnBack, className: "hover:text-foreground transition-colors", children: effectiveParentLabel }),
509
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5" }),
510
+ /* @__PURE__ */ jsx("span", { className: "text-foreground font-medium", children: title })
511
+ ] }),
512
+ actions && /* @__PURE__ */ jsx("div", { className: "no-print", children: actions })
513
+ ] }),
514
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground -mt-2", children: subtitle })
515
+ ] });
516
+ }
517
+ if (effectiveStyle === "link") {
518
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3 mb-6", children: [
519
+ /* @__PURE__ */ jsxs(
520
+ "button",
521
+ {
522
+ onClick: effectiveOnBack,
523
+ className: "inline-flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors",
524
+ children: [
525
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" }),
526
+ t("crud.detail.backTo", { entities: effectiveParentLabel })
527
+ ]
528
+ }
529
+ ),
530
+ titleBlock
531
+ ] });
532
+ }
533
+ return /* @__PURE__ */ jsx("div", { className: "space-y-4 mb-6", children: titleBlock });
534
+ }
535
+ function ShellSubpageHeader({
536
+ title,
537
+ subtitle,
538
+ icon: Icon,
539
+ onBack,
540
+ parentLabel,
541
+ actions
542
+ }) {
543
+ usePageHeader(true, { back: !!onBack });
544
+ const crumb = /* @__PURE__ */ jsx(PageTitlePortal, { children: /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
545
+ Icon && !onBack && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
546
+ /* @__PURE__ */ jsx(PageHeaderCrumb, { title, parentLabel, onBack })
547
+ ] }) });
548
+ if (!actions) return crumb;
549
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
550
+ crumb,
551
+ /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx("div", { className: "no-print flex shrink-0 items-center gap-2", children: actions }) })
552
+ ] });
553
+ }
554
+ function ModuleHeader({ nav }) {
555
+ function defaultChild(item) {
556
+ const kids2 = (item.children ?? []).filter((c) => c.kind !== "action");
557
+ return kids2.find((c) => /list/i.test(c.id) || /^list$/i.test(c.label)) ?? kids2[kids2.length - 1];
558
+ }
559
+ const activeItem = nav.find((item) => item.active || item.children?.some((c) => c.active));
560
+ const tabs = nav.map((item) => ({
561
+ value: item.id,
562
+ label: item.label,
563
+ icon: item.icon ? ICON_MAP[item.icon] ?? void 0 : void 0,
564
+ // Plan-gated views keep their upgrade marker — dropping it would hide the
565
+ // only signal that the tab costs an upgrade.
566
+ badge: item.premium ? /* @__PURE__ */ jsx(PremiumBadge, {}) : void 0
567
+ }));
568
+ const onChange = (id) => {
569
+ const item = nav.find((n) => n.id === id);
570
+ if (!item) return;
571
+ const hasChildren = item.children && item.children.length > 0;
572
+ if (hasChildren) defaultChild(item)?.onClick?.();
573
+ else item.onClick?.();
574
+ };
575
+ const kids = (activeItem?.children ?? []).filter((c) => c.kind !== "action");
576
+ const activeKid = kids.find((c) => c.active)?.id ?? kids[0]?.id;
577
+ const childControl = kids.length > 1 ? /* @__PURE__ */ jsx(
578
+ SegmentedControl,
579
+ {
580
+ size: "sm",
581
+ "aria-label": activeItem?.label,
582
+ options: kids.map((c) => ({ value: c.id, label: c.label })),
583
+ value: activeKid ?? "",
584
+ onChange: (id) => kids.find((c) => c.id === id)?.onClick?.()
585
+ }
586
+ ) : void 0;
587
+ return /* @__PURE__ */ jsx(
588
+ PageTabs,
589
+ {
590
+ tabs,
591
+ value: activeItem?.id ?? nav[0]?.id ?? "",
592
+ onChange,
593
+ actions: childControl,
594
+ anchorPrefix: "modnav"
595
+ }
596
+ );
597
+ }
598
+ function ModulePage({ title: _title, subtitle, nav, children, className, headerAction, showHeader = true, sidebarFooter, navVariant, viewKey, direction }) {
599
+ const ctxVariant = useModuleLayout();
600
+ const variant = navVariant ?? ctxVariant;
601
+ const transitionKey = viewKey ?? "view";
602
+ const onSubpage = useHasPageHeaderBack();
603
+ if (variant === "sidebar") {
604
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
605
+ showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
606
+ /* @__PURE__ */ jsx(PageTransition, { transitionKey, direction, className: cn("min-w-0", className), children })
607
+ ] });
608
+ }
609
+ if (variant === "tabs") {
610
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
611
+ !onSubpage && /* @__PURE__ */ jsx(ModuleHeader, { nav }),
612
+ showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
613
+ /* @__PURE__ */ jsx(PageTransition, { transitionKey, direction, className: cn("min-w-0", className), children })
614
+ ] });
615
+ }
616
+ return /* @__PURE__ */ jsxs("div", { className: cn("min-w-0", className), children: [
617
+ /* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */ jsxs("div", { className: "hidden w-48 shrink-0 flex-col overflow-y-auto border-r border-border p-3 no-print md:flex", children: [
618
+ /* @__PURE__ */ jsx("nav", { className: "space-y-0.5", children: nav.map((item) => /* @__PURE__ */ jsx(RailNavItem, { item }, item.id)) }),
619
+ sidebarFooter && /* @__PURE__ */ jsx("div", { className: "mt-auto pt-3", children: sidebarFooter })
620
+ ] }) }),
621
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
622
+ showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
623
+ !onSubpage && /* @__PURE__ */ jsx(MobileTabs, { nav }),
624
+ /* @__PURE__ */ jsx(PageTransition, { transitionKey, direction, children })
625
+ ] })
626
+ ] });
627
+ }
628
+
629
+ export { BackStyleProvider, HeaderTabs, ModuleLayoutProvider, ModulePage, NavTransitionProvider, PageHeaderActions, PageRail, PageTabs, PageTransition, RailNavItem, SegmentedControl, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SubpageHeader, useBackStyle, useModuleLayout, useNavTransition };
630
+ //# sourceMappingURL=chunk-UP7WVKSU.js.map
631
+ //# sourceMappingURL=chunk-UP7WVKSU.js.map