@fayz-ai/ui 0.21.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.
- package/dist/analytics/AnalyticsCard.d.ts.map +1 -1
- package/dist/analytics/AnalyticsControls.d.ts.map +1 -1
- package/dist/analytics/DateRangeControl.d.ts +14 -0
- package/dist/analytics/DateRangeControl.d.ts.map +1 -0
- package/dist/analytics/StatementTable.d.ts +22 -0
- package/dist/analytics/StatementTable.d.ts.map +1 -0
- package/dist/analytics/context.d.ts +8 -0
- package/dist/analytics/context.d.ts.map +1 -1
- package/dist/analytics/derive.d.ts +13 -0
- package/dist/analytics/derive.d.ts.map +1 -1
- package/dist/analytics/index.d.ts +7 -1
- package/dist/analytics/index.d.ts.map +1 -1
- package/dist/analytics/statement.d.ts +58 -0
- package/dist/analytics/statement.d.ts.map +1 -0
- package/dist/{chunk-E44WOPCR.js → chunk-HO2P2XB4.js} +428 -58
- package/dist/chunk-HO2P2XB4.js.map +1 -0
- package/dist/{chunk-P3YTL3MF.js → chunk-L4TXDKMN.js} +5 -5
- package/dist/chunk-L4TXDKMN.js.map +1 -0
- package/dist/{chunk-AIUHVTVK.js → chunk-OWN3GFDG.js} +5 -3
- package/dist/chunk-OWN3GFDG.js.map +1 -0
- package/dist/{chunk-EGHEU3U5.js → chunk-RRNMNFLF.js} +492 -789
- package/dist/chunk-RRNMNFLF.js.map +1 -0
- package/dist/chunk-UP7WVKSU.js +631 -0
- package/dist/chunk-UP7WVKSU.js.map +1 -0
- package/dist/{chunk-OYH7CEMB.js → chunk-XEUIYSW2.js} +330 -366
- package/dist/chunk-XEUIYSW2.js.map +1 -0
- package/dist/{chunk-MBGTFL4I.js → chunk-XKFYX3DG.js} +39 -8
- package/dist/chunk-XKFYX3DG.js.map +1 -0
- package/dist/dashboard/OnboardingWidget.d.ts +4 -1
- package/dist/dashboard/OnboardingWidget.d.ts.map +1 -1
- package/dist/dashboard/SidebarOnboarding.d.ts +11 -1
- package/dist/dashboard/SidebarOnboarding.d.ts.map +1 -1
- package/dist/dashboard/index.js +4 -4
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1109 -166
- package/dist/index.js.map +1 -1
- package/dist/layout/AppShell.d.ts +7 -1
- package/dist/layout/AppShell.d.ts.map +1 -1
- package/dist/layout/ModulePage.d.ts.map +1 -1
- package/dist/layout/SaveBar.d.ts.map +1 -1
- package/dist/layout/ShellSearch.d.ts +53 -0
- package/dist/layout/ShellSearch.d.ts.map +1 -0
- package/dist/layout/Sidebar.d.ts +10 -6
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Takeover.d.ts.map +1 -1
- package/dist/layout/index.d.ts +1 -0
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +4 -4
- package/dist/primitives/data-table.d.ts.map +1 -1
- package/dist/primitives/date-range-chip.d.ts +32 -0
- package/dist/primitives/date-range-chip.d.ts.map +1 -0
- package/dist/primitives/header-tabs.d.ts +7 -1
- package/dist/primitives/header-tabs.d.ts.map +1 -1
- package/dist/primitives/index.d.ts +2 -1
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +5 -5
- package/dist/primitives/list-view.d.ts +43 -1
- package/dist/primitives/list-view.d.ts.map +1 -1
- package/dist/primitives/modal.d.ts +2 -0
- package/dist/primitives/modal.d.ts.map +1 -1
- package/dist/primitives/page-actions.d.ts +14 -0
- package/dist/primitives/page-actions.d.ts.map +1 -1
- package/dist/primitives/page-toolbar.d.ts +16 -1
- package/dist/primitives/page-toolbar.d.ts.map +1 -1
- package/dist/primitives/search-select.d.ts +3 -1
- package/dist/primitives/search-select.d.ts.map +1 -1
- package/dist/primitives/segmented-control.d.ts.map +1 -1
- package/dist/primitives/stock-entry-form.d.ts +4 -1
- package/dist/primitives/stock-entry-form.d.ts.map +1 -1
- package/dist/stores/layout.store.d.ts +20 -1
- package/dist/stores/layout.store.d.ts.map +1 -1
- package/dist/styles.css +133 -0
- package/dist/tour/PracticeOverlay.d.ts +12 -0
- package/dist/tour/PracticeOverlay.d.ts.map +1 -0
- package/dist/tour/TourSpotlight.d.ts.map +1 -1
- package/dist/tour/confetti.d.ts +17 -0
- package/dist/tour/confetti.d.ts.map +1 -0
- package/dist/tour/index.d.ts +3 -0
- package/dist/tour/index.d.ts.map +1 -1
- package/dist/tour/practice.store.d.ts +28 -0
- package/dist/tour/practice.store.d.ts.map +1 -0
- package/dist/tour/tour.store.d.ts +4 -0
- package/dist/tour/tour.store.d.ts.map +1 -1
- package/dist/tour/types.d.ts +17 -0
- package/dist/tour/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-AIUHVTVK.js.map +0 -1
- package/dist/chunk-E44WOPCR.js.map +0 -1
- package/dist/chunk-EGHEU3U5.js.map +0 -1
- package/dist/chunk-HKGTF2YA.js +0 -117
- package/dist/chunk-HKGTF2YA.js.map +0 -1
- package/dist/chunk-MBGTFL4I.js.map +0 -1
- package/dist/chunk-OYH7CEMB.js.map +0 -1
- package/dist/chunk-P3YTL3MF.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
|