@fayz-ai/ui 0.12.0 → 0.14.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/AnalyticsControls.d.ts +5 -1
- package/dist/analytics/AnalyticsControls.d.ts.map +1 -1
- package/dist/{chunk-JGJNRNQW.js → chunk-2EFRFYGF.js} +117 -41
- package/dist/chunk-2EFRFYGF.js.map +1 -0
- package/dist/{chunk-7BMXN7MP.js → chunk-46UZAKFJ.js} +24 -24
- package/dist/chunk-46UZAKFJ.js.map +1 -0
- package/dist/chunk-5KAGNW45.js +152 -0
- package/dist/chunk-5KAGNW45.js.map +1 -0
- package/dist/{chunk-7BHG3XGJ.js → chunk-77CUIMOI.js} +201 -119
- package/dist/chunk-77CUIMOI.js.map +1 -0
- package/dist/chunk-LFZFBN3P.js +142 -0
- package/dist/chunk-LFZFBN3P.js.map +1 -0
- package/dist/{chunk-ZDRHCKRK.js → chunk-MVH64JFG.js} +1029 -767
- package/dist/chunk-MVH64JFG.js.map +1 -0
- package/dist/{chunk-22EVFMS3.js → chunk-UZYXFEQS.js} +4 -3
- package/dist/chunk-UZYXFEQS.js.map +1 -0
- package/dist/dashboard/DashboardCanvas.d.ts.map +1 -1
- package/dist/dashboard/DashboardCustomizeMenu.d.ts.map +1 -1
- package/dist/dashboard/DashboardRange.d.ts +8 -2
- package/dist/dashboard/DashboardRange.d.ts.map +1 -1
- package/dist/dashboard/index.js +4 -5
- 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 +69 -96
- package/dist/index.js.map +1 -1
- package/dist/layout/AppShell.d.ts +1 -0
- package/dist/layout/AppShell.d.ts.map +1 -1
- package/dist/layout/ModulePage.d.ts +24 -1
- package/dist/layout/ModulePage.d.ts.map +1 -1
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/index.d.ts +2 -1
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +4 -5
- package/dist/layout/rail-flyout.d.ts +10 -0
- package/dist/layout/rail-flyout.d.ts.map +1 -1
- package/dist/primitives/bulk-action-bar.d.ts +3 -1
- package/dist/primitives/bulk-action-bar.d.ts.map +1 -1
- package/dist/primitives/header-tabs.d.ts +36 -6
- 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 -4
- package/dist/primitives/list-view.d.ts +3 -1
- package/dist/primitives/list-view.d.ts.map +1 -1
- package/dist/primitives/page-toolbar.d.ts +61 -0
- package/dist/primitives/page-toolbar.d.ts.map +1 -0
- package/dist/primitives/search-select.d.ts +3 -1
- package/dist/primitives/search-select.d.ts.map +1 -1
- package/dist/primitives/tabs.d.ts.map +1 -1
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/page-header.store.d.ts +26 -2
- package/dist/stores/page-header.store.d.ts.map +1 -1
- package/dist/styles.css +54 -17
- package/package.json +5 -5
- package/dist/chunk-22EVFMS3.js.map +0 -1
- package/dist/chunk-7BHG3XGJ.js.map +0 -1
- package/dist/chunk-7BMXN7MP.js.map +0 -1
- package/dist/chunk-JGJNRNQW.js.map +0 -1
- package/dist/chunk-OKZ6WQB3.js +0 -57
- package/dist/chunk-OKZ6WQB3.js.map +0 -1
- package/dist/chunk-VAKWUUVC.js +0 -425
- package/dist/chunk-VAKWUUVC.js.map +0 -1
- package/dist/chunk-ZBQ772DU.js +0 -17
- package/dist/chunk-ZBQ772DU.js.map +0 -1
- package/dist/chunk-ZDRHCKRK.js.map +0 -1
package/dist/chunk-VAKWUUVC.js
DELETED
|
@@ -1,425 +0,0 @@
|
|
|
1
|
-
import { cn } from './chunk-OKZ6WQB3.js';
|
|
2
|
-
import * as React2 from 'react';
|
|
3
|
-
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
4
|
-
import { X, Loader2, ArrowLeft } from 'lucide-react';
|
|
5
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
|
-
import { useTranslation, useNavReferrer, routeModule, navHistoryBack } from '@fayz-ai/core';
|
|
7
|
-
import { create } from 'zustand';
|
|
8
|
-
|
|
9
|
-
var STYLE_ID = "saas-sheet-styles";
|
|
10
|
-
if (typeof document !== "undefined" && !document.getElementById(STYLE_ID)) {
|
|
11
|
-
const style = document.createElement("style");
|
|
12
|
-
style.id = STYLE_ID;
|
|
13
|
-
style.textContent = `
|
|
14
|
-
@keyframes saas-sheet-fade-in { from { opacity: 0 } to { opacity: 1 } }
|
|
15
|
-
@keyframes saas-sheet-fade-out { from { opacity: 1 } to { opacity: 0 } }
|
|
16
|
-
@keyframes saas-sheet-slide-in { from { transform: translateX(100%) } to { transform: translateX(0) } }
|
|
17
|
-
@keyframes saas-sheet-slide-out { from { transform: translateX(0) } to { transform: translateX(100%) } }
|
|
18
|
-
.saas-sheet-overlay[data-state="open"] { animation: saas-sheet-fade-in 200ms ease-out }
|
|
19
|
-
.saas-sheet-overlay[data-state="closed"] { animation: saas-sheet-fade-out 150ms ease-in }
|
|
20
|
-
.saas-sheet-content[data-state="open"] { animation: saas-sheet-slide-in 280ms cubic-bezier(0.16, 1, 0.3, 1) }
|
|
21
|
-
.saas-sheet-content[data-state="closed"] { animation: saas-sheet-slide-out 200ms ease-in }
|
|
22
|
-
`;
|
|
23
|
-
document.head.appendChild(style);
|
|
24
|
-
}
|
|
25
|
-
var Sheet = DialogPrimitive.Root;
|
|
26
|
-
var SheetTrigger = DialogPrimitive.Trigger;
|
|
27
|
-
var SheetClose = DialogPrimitive.Close;
|
|
28
|
-
var SheetPortal = DialogPrimitive.Portal;
|
|
29
|
-
var SheetOverlay = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
30
|
-
DialogPrimitive.Overlay,
|
|
31
|
-
{
|
|
32
|
-
ref,
|
|
33
|
-
className: cn(
|
|
34
|
-
"saas-sheet-overlay fixed inset-0 z-50 bg-black/40 backdrop-blur-[2px]",
|
|
35
|
-
className
|
|
36
|
-
),
|
|
37
|
-
...props
|
|
38
|
-
}
|
|
39
|
-
));
|
|
40
|
-
SheetOverlay.displayName = "SheetOverlay";
|
|
41
|
-
var SheetContent = React2.forwardRef(({ className, children, width, hideClose, overlay = "blur", ...props }, ref) => /* @__PURE__ */ jsxs(SheetPortal, { children: [
|
|
42
|
-
/* @__PURE__ */ jsx(SheetOverlay, { className: overlay === "none" ? "bg-transparent backdrop-blur-0" : overlay === "dim" ? "backdrop-blur-0" : void 0 }),
|
|
43
|
-
/* @__PURE__ */ jsxs(
|
|
44
|
-
DialogPrimitive.Content,
|
|
45
|
-
{
|
|
46
|
-
ref,
|
|
47
|
-
className: cn(
|
|
48
|
-
"fayz-glass-surface saas-sheet-content fixed inset-y-0 right-0 z-50 flex flex-col border-l bg-card shadow-2xl outline-none",
|
|
49
|
-
"w-full",
|
|
50
|
-
width ?? "max-w-md",
|
|
51
|
-
className
|
|
52
|
-
),
|
|
53
|
-
...props,
|
|
54
|
-
children: [
|
|
55
|
-
children,
|
|
56
|
-
!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: [
|
|
57
|
-
/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
|
|
58
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
59
|
-
] })
|
|
60
|
-
]
|
|
61
|
-
}
|
|
62
|
-
)
|
|
63
|
-
] }));
|
|
64
|
-
SheetContent.displayName = "SheetContent";
|
|
65
|
-
function SheetHeader({ className, ...props }) {
|
|
66
|
-
return /* @__PURE__ */ jsx(
|
|
67
|
-
"div",
|
|
68
|
-
{
|
|
69
|
-
className: cn("flex flex-col gap-1 px-5 py-4 border-b shrink-0", className),
|
|
70
|
-
...props
|
|
71
|
-
}
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
SheetHeader.displayName = "SheetHeader";
|
|
75
|
-
function SheetFooter({ className, ...props }) {
|
|
76
|
-
return /* @__PURE__ */ jsx(
|
|
77
|
-
"div",
|
|
78
|
-
{
|
|
79
|
-
className: cn("flex items-center gap-2 px-5 py-3 border-t shrink-0", className),
|
|
80
|
-
...props
|
|
81
|
-
}
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
SheetFooter.displayName = "SheetFooter";
|
|
85
|
-
var SheetTitle = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
86
|
-
DialogPrimitive.Title,
|
|
87
|
-
{
|
|
88
|
-
ref,
|
|
89
|
-
className: cn("text-sm font-semibold leading-none tracking-tight", className),
|
|
90
|
-
...props
|
|
91
|
-
}
|
|
92
|
-
));
|
|
93
|
-
SheetTitle.displayName = "SheetTitle";
|
|
94
|
-
var SheetDescription = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
95
|
-
DialogPrimitive.Description,
|
|
96
|
-
{
|
|
97
|
-
ref,
|
|
98
|
-
className: cn("text-xs text-muted-foreground", className),
|
|
99
|
-
...props
|
|
100
|
-
}
|
|
101
|
-
));
|
|
102
|
-
SheetDescription.displayName = "SheetDescription";
|
|
103
|
-
function SheetBody({ className, ...props }) {
|
|
104
|
-
return /* @__PURE__ */ jsx(
|
|
105
|
-
"div",
|
|
106
|
-
{
|
|
107
|
-
className: cn("flex-1 overflow-y-auto px-5 py-5", className),
|
|
108
|
-
...props
|
|
109
|
-
}
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
SheetBody.displayName = "SheetBody";
|
|
113
|
-
var SaveBarApiContext = React2.createContext(null);
|
|
114
|
-
var SaveBarStateContext = React2.createContext({ visible: false, saving: false });
|
|
115
|
-
var _saveBarVisible = false;
|
|
116
|
-
var _saveBarSubs = /* @__PURE__ */ new Set();
|
|
117
|
-
function setSaveBarVisibleSignal(v) {
|
|
118
|
-
if (v === _saveBarVisible) return;
|
|
119
|
-
_saveBarVisible = v;
|
|
120
|
-
_saveBarSubs.forEach((fn) => fn());
|
|
121
|
-
}
|
|
122
|
-
function useSaveBarVisible() {
|
|
123
|
-
return React2.useSyncExternalStore(
|
|
124
|
-
(cb) => {
|
|
125
|
-
_saveBarSubs.add(cb);
|
|
126
|
-
return () => {
|
|
127
|
-
_saveBarSubs.delete(cb);
|
|
128
|
-
};
|
|
129
|
-
},
|
|
130
|
-
() => _saveBarVisible,
|
|
131
|
-
() => false
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
function SaveBarProvider({ children }) {
|
|
135
|
-
const [state, setState] = React2.useState({ visible: false, saving: false });
|
|
136
|
-
const handlers = React2.useRef({});
|
|
137
|
-
const api = React2.useMemo(() => ({ setState, handlers }), []);
|
|
138
|
-
const backStack = React2.useRef([]);
|
|
139
|
-
const backApi = React2.useMemo(() => ({ stack: backStack }), []);
|
|
140
|
-
React2.useEffect(() => {
|
|
141
|
-
setSaveBarVisibleSignal(state.visible);
|
|
142
|
-
}, [state.visible]);
|
|
143
|
-
React2.useEffect(() => {
|
|
144
|
-
function onKey(e) {
|
|
145
|
-
if (state.visible && !state.saving) {
|
|
146
|
-
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
147
|
-
e.preventDefault();
|
|
148
|
-
handlers.current.onSave?.();
|
|
149
|
-
} else if (e.key === "Escape") {
|
|
150
|
-
e.preventDefault();
|
|
151
|
-
handlers.current.onDiscard?.();
|
|
152
|
-
}
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
if (e.key === "Escape" && !e.defaultPrevented && !isEditableTarget(e.target)) {
|
|
156
|
-
for (let i = backStack.current.length - 1; i >= 0; i--) {
|
|
157
|
-
const back = backStack.current[i].current;
|
|
158
|
-
if (back) {
|
|
159
|
-
e.preventDefault();
|
|
160
|
-
back();
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
window.addEventListener("keydown", onKey);
|
|
167
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
168
|
-
}, [state.visible, state.saving]);
|
|
169
|
-
return /* @__PURE__ */ jsx(SaveBarApiContext.Provider, { value: api, children: /* @__PURE__ */ jsx(BackNavApiContext.Provider, { value: backApi, children: /* @__PURE__ */ jsx(SaveBarStateContext.Provider, { value: state, children }) }) });
|
|
170
|
-
}
|
|
171
|
-
var BackNavApiContext = React2.createContext(null);
|
|
172
|
-
function isEditableTarget(target) {
|
|
173
|
-
const el = target;
|
|
174
|
-
if (!el || !el.tagName) return false;
|
|
175
|
-
const tag = el.tagName.toLowerCase();
|
|
176
|
-
return tag === "input" || tag === "textarea" || tag === "select" || el.isContentEditable;
|
|
177
|
-
}
|
|
178
|
-
function useBackHandler(onBack) {
|
|
179
|
-
const api = React2.useContext(BackNavApiContext);
|
|
180
|
-
const ref = React2.useRef(onBack);
|
|
181
|
-
React2.useEffect(() => {
|
|
182
|
-
ref.current = onBack;
|
|
183
|
-
});
|
|
184
|
-
React2.useEffect(() => {
|
|
185
|
-
if (!api) return;
|
|
186
|
-
const stack = api.stack.current;
|
|
187
|
-
stack.push(ref);
|
|
188
|
-
return () => {
|
|
189
|
-
const i = stack.indexOf(ref);
|
|
190
|
-
if (i !== -1) stack.splice(i, 1);
|
|
191
|
-
};
|
|
192
|
-
}, [api]);
|
|
193
|
-
}
|
|
194
|
-
function useSaveBar({ dirty, saving = false, onSave, onDiscard, message, saveLabel, discardLabel }) {
|
|
195
|
-
const api = React2.useContext(SaveBarApiContext);
|
|
196
|
-
React2.useEffect(() => {
|
|
197
|
-
if (api) api.handlers.current = { onSave, onDiscard };
|
|
198
|
-
});
|
|
199
|
-
React2.useEffect(() => {
|
|
200
|
-
if (!api) return;
|
|
201
|
-
api.setState({ visible: dirty, saving, message, saveLabel, discardLabel });
|
|
202
|
-
return () => api.setState((s) => ({ ...s, visible: false }));
|
|
203
|
-
}, [api, dirty, saving, message, saveLabel, discardLabel]);
|
|
204
|
-
}
|
|
205
|
-
function SaveBar({ className }) {
|
|
206
|
-
const state = React2.useContext(SaveBarStateContext);
|
|
207
|
-
const api = React2.useContext(SaveBarApiContext);
|
|
208
|
-
const t = useTranslation();
|
|
209
|
-
const [rendered, setRendered] = React2.useState(state.visible);
|
|
210
|
-
const [closing, setClosing] = React2.useState(false);
|
|
211
|
-
React2.useEffect(() => {
|
|
212
|
-
if (state.visible) {
|
|
213
|
-
setRendered(true);
|
|
214
|
-
setClosing(false);
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
if (!rendered) return;
|
|
218
|
-
setClosing(true);
|
|
219
|
-
const id = setTimeout(() => {
|
|
220
|
-
setRendered(false);
|
|
221
|
-
setClosing(false);
|
|
222
|
-
}, 200);
|
|
223
|
-
return () => clearTimeout(id);
|
|
224
|
-
}, [state.visible, rendered]);
|
|
225
|
-
if (!api || !rendered) return null;
|
|
226
|
-
const { saving, message, saveLabel, discardLabel } = state;
|
|
227
|
-
return /* @__PURE__ */ jsx("div", { className: cn("pointer-events-none fixed inset-x-0 bottom-5 z-40 flex justify-center px-4", className), children: /* @__PURE__ */ jsxs("div", { className: cn(
|
|
228
|
-
"pointer-events-auto flex items-center gap-5 rounded-full bg-foreground py-2 pl-5 pr-2 text-background shadow-xl ring-1 ring-black/5 duration-200",
|
|
229
|
-
closing ? "animate-out fade-out slide-out-to-bottom-2" : "animate-in fade-in slide-in-from-bottom-2"
|
|
230
|
-
), children: [
|
|
231
|
-
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 text-sm font-medium", children: [
|
|
232
|
-
/* @__PURE__ */ jsx("span", { className: "h-2 w-2 shrink-0 rounded-full bg-amber-400" }),
|
|
233
|
-
message ?? t("saveBar.unsaved")
|
|
234
|
-
] }),
|
|
235
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
236
|
-
/* @__PURE__ */ jsx(
|
|
237
|
-
"button",
|
|
238
|
-
{
|
|
239
|
-
type: "button",
|
|
240
|
-
disabled: saving,
|
|
241
|
-
onClick: () => api.handlers.current.onDiscard?.(),
|
|
242
|
-
className: "rounded-full px-3 py-1.5 text-sm font-medium text-background/70 transition-colors hover:bg-background/10 hover:text-background disabled:opacity-50",
|
|
243
|
-
children: discardLabel ?? t("common.discard")
|
|
244
|
-
}
|
|
245
|
-
),
|
|
246
|
-
/* @__PURE__ */ jsxs(
|
|
247
|
-
"button",
|
|
248
|
-
{
|
|
249
|
-
type: "button",
|
|
250
|
-
disabled: saving,
|
|
251
|
-
onClick: () => api.handlers.current.onSave?.(),
|
|
252
|
-
className: "inline-flex items-center rounded-full bg-background px-4 py-1.5 text-sm font-semibold text-foreground transition-colors hover:bg-background/90 disabled:opacity-60",
|
|
253
|
-
children: [
|
|
254
|
-
saving && /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-3.5 w-3.5 animate-spin" }),
|
|
255
|
-
saveLabel ?? t("common.save")
|
|
256
|
-
]
|
|
257
|
-
}
|
|
258
|
-
)
|
|
259
|
-
] })
|
|
260
|
-
] }) });
|
|
261
|
-
}
|
|
262
|
-
var usePageHeaderStore = create((set, get) => ({
|
|
263
|
-
slot: null,
|
|
264
|
-
owner: null,
|
|
265
|
-
hosts: 0,
|
|
266
|
-
outlets: 0,
|
|
267
|
-
claim: (owner, node) => set({ owner, slot: node }),
|
|
268
|
-
release: (owner) => {
|
|
269
|
-
if (get().owner === owner) set({ owner: null, slot: null });
|
|
270
|
-
},
|
|
271
|
-
addHost: () => set((s) => ({ hosts: s.hosts + 1 })),
|
|
272
|
-
removeHost: () => set((s) => ({ hosts: Math.max(0, s.hosts - 1) })),
|
|
273
|
-
addOutlet: () => set((s) => ({ outlets: s.outlets + 1 })),
|
|
274
|
-
removeOutlet: () => set((s) => ({ outlets: Math.max(0, s.outlets - 1) }))
|
|
275
|
-
}));
|
|
276
|
-
function usePageHeaderSlot() {
|
|
277
|
-
return usePageHeaderStore((s) => s.slot);
|
|
278
|
-
}
|
|
279
|
-
function usePageHeaderHost() {
|
|
280
|
-
const addHost = usePageHeaderStore((s) => s.addHost);
|
|
281
|
-
const removeHost = usePageHeaderStore((s) => s.removeHost);
|
|
282
|
-
React2.useEffect(() => {
|
|
283
|
-
addHost();
|
|
284
|
-
return removeHost;
|
|
285
|
-
}, [addHost, removeHost]);
|
|
286
|
-
}
|
|
287
|
-
function useHasPageHeaderHost() {
|
|
288
|
-
return usePageHeaderStore((s) => s.hosts > 0 || s.outlets > 0);
|
|
289
|
-
}
|
|
290
|
-
function useHasPageHeaderOutlet() {
|
|
291
|
-
return usePageHeaderStore((s) => s.outlets > 0);
|
|
292
|
-
}
|
|
293
|
-
function PageHeaderOutlet({ className }) {
|
|
294
|
-
const slot = usePageHeaderStore((s) => s.slot);
|
|
295
|
-
const addOutlet = usePageHeaderStore((s) => s.addOutlet);
|
|
296
|
-
const removeOutlet = usePageHeaderStore((s) => s.removeOutlet);
|
|
297
|
-
React2.useEffect(() => {
|
|
298
|
-
addOutlet();
|
|
299
|
-
return removeOutlet;
|
|
300
|
-
}, [addOutlet, removeOutlet]);
|
|
301
|
-
if (!slot) return null;
|
|
302
|
-
return React2.createElement("div", { className: className ?? "mb-4" }, slot);
|
|
303
|
-
}
|
|
304
|
-
function usePageHeader(node) {
|
|
305
|
-
const id = React2.useId();
|
|
306
|
-
const claim = usePageHeaderStore((s) => s.claim);
|
|
307
|
-
const release = usePageHeaderStore((s) => s.release);
|
|
308
|
-
React2.useEffect(() => {
|
|
309
|
-
if (node == null) {
|
|
310
|
-
release(id);
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
claim(id, node);
|
|
314
|
-
return () => release(id);
|
|
315
|
-
}, [id, node, claim, release]);
|
|
316
|
-
}
|
|
317
|
-
function useCrossModuleBack(onBack, parentLabel) {
|
|
318
|
-
const currentPath = typeof window !== "undefined" ? (window.location.hash ? window.location.hash.slice(1) : window.location.pathname) || "/" : "/";
|
|
319
|
-
const referrer = useNavReferrer(currentPath);
|
|
320
|
-
const cross = referrer && referrer.label && routeModule(referrer.path) !== routeModule(currentPath) ? referrer : null;
|
|
321
|
-
return {
|
|
322
|
-
onBack: cross ? () => navHistoryBack(onBack) : onBack,
|
|
323
|
-
parentLabel: cross ? cross.label : parentLabel,
|
|
324
|
-
isCrossModule: !!cross
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
function PageHeaderCrumb({
|
|
328
|
-
title,
|
|
329
|
-
parentLabel,
|
|
330
|
-
onBack
|
|
331
|
-
}) {
|
|
332
|
-
if (!onBack) {
|
|
333
|
-
return title ? /* @__PURE__ */ jsx("h2", { className: "min-w-0 truncate text-lg font-semibold", children: title }) : null;
|
|
334
|
-
}
|
|
335
|
-
return /* @__PURE__ */ jsxs("nav", { className: "flex min-w-0 items-center gap-1.5 text-sm text-muted-foreground", children: [
|
|
336
|
-
/* @__PURE__ */ jsxs(
|
|
337
|
-
"button",
|
|
338
|
-
{
|
|
339
|
-
type: "button",
|
|
340
|
-
onClick: onBack,
|
|
341
|
-
className: "inline-flex shrink-0 items-center gap-1 transition-colors hover:text-foreground",
|
|
342
|
-
children: [
|
|
343
|
-
/* @__PURE__ */ jsx(ArrowLeft, { className: "h-3.5 w-3.5" }),
|
|
344
|
-
parentLabel ?? "Voltar"
|
|
345
|
-
]
|
|
346
|
-
}
|
|
347
|
-
),
|
|
348
|
-
title != null && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
349
|
-
/* @__PURE__ */ jsx("span", { className: "shrink-0", children: "/" }),
|
|
350
|
-
title === "" ? (
|
|
351
|
-
// Title still waiting on data: a pulsing bar, otherwise the line
|
|
352
|
-
// appears from nowhere and shoves the rest when the record lands.
|
|
353
|
-
/* @__PURE__ */ jsx("span", { className: "inline-block h-4 w-24 animate-pulse rounded bg-muted align-middle" })
|
|
354
|
-
) : /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate font-medium text-foreground", children: title })
|
|
355
|
-
] })
|
|
356
|
-
] });
|
|
357
|
-
}
|
|
358
|
-
function PageHeader({ title, onBack, parentLabel, backLabel }) {
|
|
359
|
-
const hasHost = useHasPageHeaderHost();
|
|
360
|
-
const { onBack: effectiveOnBack, parentLabel: effectiveParent } = useCrossModuleBack(onBack, parentLabel);
|
|
361
|
-
useBackHandler(effectiveOnBack);
|
|
362
|
-
const node = React2.useMemo(() => /* @__PURE__ */ jsx(
|
|
363
|
-
PageHeaderCrumb,
|
|
364
|
-
{
|
|
365
|
-
title,
|
|
366
|
-
parentLabel: effectiveParent ?? backLabel,
|
|
367
|
-
onBack: effectiveOnBack
|
|
368
|
-
}
|
|
369
|
-
), [effectiveOnBack, effectiveParent, backLabel, title]);
|
|
370
|
-
usePageHeader(hasHost ? node : null);
|
|
371
|
-
if (hasHost) return null;
|
|
372
|
-
return /* @__PURE__ */ jsx("div", { className: "mb-4", children: node });
|
|
373
|
-
}
|
|
374
|
-
function HeaderTabs({
|
|
375
|
-
tabs,
|
|
376
|
-
value,
|
|
377
|
-
onChange,
|
|
378
|
-
className,
|
|
379
|
-
...rest
|
|
380
|
-
}) {
|
|
381
|
-
return /* @__PURE__ */ jsx(
|
|
382
|
-
"div",
|
|
383
|
-
{
|
|
384
|
-
role: "tablist",
|
|
385
|
-
"aria-label": rest["aria-label"],
|
|
386
|
-
className: cn(
|
|
387
|
-
"inline-flex items-center gap-0.5 rounded-lg border border-border bg-muted/40 p-1",
|
|
388
|
-
className
|
|
389
|
-
),
|
|
390
|
-
children: tabs.map((tab, i) => {
|
|
391
|
-
const active = tab.value === value;
|
|
392
|
-
const Icon = tab.icon;
|
|
393
|
-
const separated = i > 0 && !active && tabs[i - 1].value !== value;
|
|
394
|
-
return /* @__PURE__ */ jsxs(
|
|
395
|
-
"button",
|
|
396
|
-
{
|
|
397
|
-
type: "button",
|
|
398
|
-
role: "tab",
|
|
399
|
-
"aria-selected": active,
|
|
400
|
-
onClick: () => onChange(tab.value),
|
|
401
|
-
className: cn(
|
|
402
|
-
"relative flex h-8 items-center gap-1.5 rounded-md px-3 text-[13px] font-medium transition-colors",
|
|
403
|
-
active ? "bg-card text-foreground shadow-button" : "text-muted-foreground hover:text-foreground",
|
|
404
|
-
separated && "before:absolute before:left-[-3px] before:top-1.5 before:h-5 before:w-px before:bg-border"
|
|
405
|
-
),
|
|
406
|
-
children: [
|
|
407
|
-
Icon ? /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5 shrink-0" }) : null,
|
|
408
|
-
/* @__PURE__ */ jsx("span", { className: "truncate", children: tab.label }),
|
|
409
|
-
tab.count != null && /* @__PURE__ */ jsx("span", { className: cn(
|
|
410
|
-
"ml-0.5 rounded-full px-1.5 text-[11px] tabular-nums",
|
|
411
|
-
active ? "bg-muted text-muted-foreground" : "bg-muted/70 text-muted-foreground"
|
|
412
|
-
), children: tab.count }),
|
|
413
|
-
tab.badge
|
|
414
|
-
]
|
|
415
|
-
},
|
|
416
|
-
tab.value
|
|
417
|
-
);
|
|
418
|
-
})
|
|
419
|
-
}
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
export { HeaderTabs, PageHeader, PageHeaderCrumb, PageHeaderOutlet, SaveBar, SaveBarProvider, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, useBackHandler, useCrossModuleBack, useHasPageHeaderHost, useHasPageHeaderOutlet, usePageHeader, usePageHeaderHost, usePageHeaderSlot, useSaveBar, useSaveBarVisible };
|
|
424
|
-
//# sourceMappingURL=chunk-VAKWUUVC.js.map
|
|
425
|
-
//# sourceMappingURL=chunk-VAKWUUVC.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/primitives/sheet.tsx","../src/layout/SaveBar.tsx","../src/stores/page-header.store.ts","../src/layout/useCrossModuleBack.ts","../src/primitives/page-header.tsx","../src/primitives/header-tabs.tsx"],"names":["React","jsx","jsxs","React3","React4"],"mappings":"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","file":"chunk-VAKWUUVC.js","sourcesContent":["import * as React from 'react'\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { X } from 'lucide-react'\n\nimport { cn } from '../lib/cn'\n\n// ---------------------------------------------------------------------------\n// Inject sheet animations once (module-level side effect)\n// ---------------------------------------------------------------------------\n\nconst STYLE_ID = 'saas-sheet-styles'\nif (typeof document !== 'undefined' && !document.getElementById(STYLE_ID)) {\n const style = document.createElement('style')\n style.id = STYLE_ID\n style.textContent = `\n @keyframes saas-sheet-fade-in { from { opacity: 0 } to { opacity: 1 } }\n @keyframes saas-sheet-fade-out { from { opacity: 1 } to { opacity: 0 } }\n @keyframes saas-sheet-slide-in { from { transform: translateX(100%) } to { transform: translateX(0) } }\n @keyframes saas-sheet-slide-out { from { transform: translateX(0) } to { transform: translateX(100%) } }\n .saas-sheet-overlay[data-state=\"open\"] { animation: saas-sheet-fade-in 200ms ease-out }\n .saas-sheet-overlay[data-state=\"closed\"] { animation: saas-sheet-fade-out 150ms ease-in }\n .saas-sheet-content[data-state=\"open\"] { animation: saas-sheet-slide-in 280ms cubic-bezier(0.16, 1, 0.3, 1) }\n .saas-sheet-content[data-state=\"closed\"] { animation: saas-sheet-slide-out 200ms ease-in }\n `\n document.head.appendChild(style)\n}\n\n// ---------------------------------------------------------------------------\n// Root, Trigger, Close — re-exported from Radix\n// ---------------------------------------------------------------------------\n\nconst Sheet = DialogPrimitive.Root\nconst SheetTrigger = DialogPrimitive.Trigger\nconst SheetClose = DialogPrimitive.Close\nconst SheetPortal = DialogPrimitive.Portal\n\n// ---------------------------------------------------------------------------\n// Overlay\n// ---------------------------------------------------------------------------\n\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n 'saas-sheet-overlay fixed inset-0 z-50 bg-black/40 backdrop-blur-[2px]',\n className\n )}\n {...props}\n />\n))\nSheetOverlay.displayName = 'SheetOverlay'\n\n// ---------------------------------------------------------------------------\n// Content — slides in from the right\n// ---------------------------------------------------------------------------\n\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n /** Width class override — defaults to max-w-md */\n width?: string\n /** Hide the built-in close button */\n hideClose?: boolean\n /** Overlay style: \"blur\" (default), \"dim\" (no blur), \"none\" (transparent) */\n overlay?: 'blur' | 'dim' | 'none'\n }\n>(({ className, children, width, hideClose, overlay = 'blur', ...props }, ref) => (\n <SheetPortal>\n <SheetOverlay className={overlay === 'none' ? 'bg-transparent backdrop-blur-0' : overlay === 'dim' ? 'backdrop-blur-0' : undefined} />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n 'fayz-glass-surface saas-sheet-content fixed inset-y-0 right-0 z-50 flex flex-col border-l bg-card shadow-2xl outline-none',\n 'w-full',\n width ?? 'max-w-md',\n className\n )}\n {...props}\n >\n {children}\n {!hideClose && (\n <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\">\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </SheetPortal>\n))\nSheetContent.displayName = 'SheetContent'\n\n// ---------------------------------------------------------------------------\n// Header — top section with title + description\n// ---------------------------------------------------------------------------\n\nfunction SheetHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('flex flex-col gap-1 px-5 py-4 border-b shrink-0', className)}\n {...props}\n />\n )\n}\nSheetHeader.displayName = 'SheetHeader'\n\n// ---------------------------------------------------------------------------\n// Footer — bottom section for actions\n// ---------------------------------------------------------------------------\n\nfunction SheetFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('flex items-center gap-2 px-5 py-3 border-t shrink-0', className)}\n {...props}\n />\n )\n}\nSheetFooter.displayName = 'SheetFooter'\n\n// ---------------------------------------------------------------------------\n// Title\n// ---------------------------------------------------------------------------\n\nconst SheetTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn('text-sm font-semibold leading-none tracking-tight', className)}\n {...props}\n />\n))\nSheetTitle.displayName = 'SheetTitle'\n\n// ---------------------------------------------------------------------------\n// Description\n// ---------------------------------------------------------------------------\n\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn('text-xs text-muted-foreground', className)}\n {...props}\n />\n))\nSheetDescription.displayName = 'SheetDescription'\n\n// ---------------------------------------------------------------------------\n// Body — scrollable content area\n// ---------------------------------------------------------------------------\n\nfunction SheetBody({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('flex-1 overflow-y-auto px-5 py-5', className)}\n {...props}\n />\n )\n}\nSheetBody.displayName = 'SheetBody'\n\nexport {\n Sheet,\n SheetPortal,\n SheetOverlay,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetBody,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n}\n","import * as React from 'react'\nimport { Loader2 } from 'lucide-react'\nimport { useTranslation } from '@fayz-ai/core'\nimport { cn } from '../lib/cn'\n\n// ---------------------------------------------------------------------------\n// SaveBar — the single, app-wide \"Unsaved changes\" floating island. A form\n// declares its state via useSaveBar({ dirty, saving, onSave, onDiscard }); the\n// shell renders ONE <SaveBar/> (centered, floating above the content area) that\n// appears whenever the active form is dirty. Mirrors the BackStyleProvider /\n// PageHeaderActions idiom: decide-once at the shell, hook-in at the page.\n//\n// Handlers live in a ref (not state) so per-render closure changes never cause\n// re-render loops; only the primitive `dirty`/`saving` flags drive visibility.\n// ---------------------------------------------------------------------------\n\nexport interface SaveBarRegistration {\n /** Show the bar when true (form has unsaved changes). */\n dirty: boolean\n /** Save in progress — disables buttons and shows a spinner. */\n saving?: boolean\n onSave: () => void\n onDiscard?: () => void\n /** Override the \"Unsaved changes\" message. */\n message?: string\n /** Override the Save / Discard button labels. */\n saveLabel?: string\n discardLabel?: string\n}\n\ninterface SaveBarState {\n visible: boolean\n saving: boolean\n message?: string\n saveLabel?: string\n discardLabel?: string\n}\n\ninterface SaveBarApi {\n setState: React.Dispatch<React.SetStateAction<SaveBarState>>\n handlers: React.MutableRefObject<{ onSave?: () => void; onDiscard?: () => void }>\n}\n\n// Two contexts on purpose: the API context is STABLE (so useSaveBar's effect\n// deps don't change every render → no loop), the state context changes to\n// re-render only <SaveBar/>.\nconst SaveBarApiContext = React.createContext<SaveBarApi | null>(null)\nconst SaveBarStateContext = React.createContext<SaveBarState>({ visible: false, saving: false })\n\n// Module-level \"is the SaveBar showing\" signal so sibling UI that isn't a\n// descendant of SaveBarProvider (e.g. the ToastProvider) can react to it —\n// used to lift toasts above the bar so they stack instead of overlapping.\nlet _saveBarVisible = false\nconst _saveBarSubs = new Set<() => void>()\nfunction setSaveBarVisibleSignal(v: boolean) {\n if (v === _saveBarVisible) return\n _saveBarVisible = v\n _saveBarSubs.forEach((fn) => fn())\n}\n\n/** Subscribe to whether the floating SaveBar is currently on screen. */\nexport function useSaveBarVisible(): boolean {\n return React.useSyncExternalStore(\n (cb) => { _saveBarSubs.add(cb); return () => { _saveBarSubs.delete(cb) } },\n () => _saveBarVisible,\n () => false,\n )\n}\n\nexport function SaveBarProvider({ children }: { children: React.ReactNode }) {\n const [state, setState] = React.useState<SaveBarState>({ visible: false, saving: false })\n const handlers = React.useRef<{ onSave?: () => void; onDiscard?: () => void }>({})\n const api = React.useMemo<SaveBarApi>(() => ({ setState, handlers }), [])\n\n // Stack of registered back-navigation handlers (latest-mounted wins) so the\n // app-wide Escape key can navigate \"up\" to the parent route. Lives here, next\n // to the SaveBar handlers, so ONE keydown listener arbitrates both — Escape\n // discards a dirty form first, and only navigates back when none is open.\n const backStack = React.useRef<React.MutableRefObject<(() => void) | undefined>[]>([])\n const backApi = React.useMemo<BackNavApi>(() => ({ stack: backStack }), [])\n\n // Broadcast visibility to the module-level signal (for the ToastProvider).\n React.useEffect(() => { setSaveBarVisibleSignal(state.visible) }, [state.visible])\n\n // App-wide keyboard shortcuts, arbitrated in one place:\n // • Cmd/Ctrl+Enter → save the active (dirty) form\n // • Escape (form dirty) → discard the form\n // • Escape (no dirty form) → navigate back to the parent route\n React.useEffect(() => {\n function onKey(e: KeyboardEvent) {\n if (state.visible && !state.saving) {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault()\n handlers.current.onSave?.()\n } else if (e.key === 'Escape') {\n e.preventDefault()\n handlers.current.onDiscard?.()\n }\n return\n }\n // No open/dirty form — Escape walks \"up\" via the topmost back handler.\n if (e.key === 'Escape' && !e.defaultPrevented && !isEditableTarget(e.target)) {\n for (let i = backStack.current.length - 1; i >= 0; i--) {\n const back = backStack.current[i].current\n if (back) { e.preventDefault(); back(); return }\n }\n }\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [state.visible, state.saving])\n\n return (\n <SaveBarApiContext.Provider value={api}>\n <BackNavApiContext.Provider value={backApi}>\n <SaveBarStateContext.Provider value={state}>\n {children}\n </SaveBarStateContext.Provider>\n </BackNavApiContext.Provider>\n </SaveBarApiContext.Provider>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Back-navigation registry — lets any subpage register its \"go to parent\" action\n// so the shell's single Escape handler can drive it (see SaveBarProvider above).\n// SubpageHeader already receives onBack, so wiring it there gives every plugin\n// detail page Escape-to-parent for free, with zero per-plugin code.\n// ---------------------------------------------------------------------------\n\ninterface BackNavApi {\n stack: React.MutableRefObject<React.MutableRefObject<(() => void) | undefined>[]>\n}\nconst BackNavApiContext = React.createContext<BackNavApi | null>(null)\n\n/** True when the keyboard event originates from a field where Escape has its\n * own meaning (clear/close), so we shouldn't hijack it for back-navigation. */\nfunction isEditableTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null\n if (!el || !el.tagName) return false\n const tag = el.tagName.toLowerCase()\n return tag === 'input' || tag === 'textarea' || tag === 'select' || el.isContentEditable\n}\n\n/**\n * Register a back-navigation handler with the app-wide Escape key. Call it in a\n * subpage (or pass through SubpageHeader's onBack); while mounted, pressing\n * Escape with no dirty form open invokes the most-recently-registered handler.\n * Pass `undefined` to opt out (e.g. a top-level page with nothing to go back to).\n */\nexport function useBackHandler(onBack?: () => void): void {\n const api = React.useContext(BackNavApiContext)\n // Hold the latest closure in a ref so re-renders don't churn the stack.\n const ref = React.useRef(onBack)\n React.useEffect(() => { ref.current = onBack })\n React.useEffect(() => {\n if (!api) return\n const stack = api.stack.current\n stack.push(ref)\n return () => {\n const i = stack.indexOf(ref)\n if (i !== -1) stack.splice(i, 1)\n }\n }, [api])\n}\n\n/**\n * Register the current form with the app-wide SaveBar. Call it unconditionally\n * in a form view; it shows the island while `dirty`, keeps handlers current, and\n * hides the island automatically when the form unmounts (e.g. on navigation).\n */\nexport function useSaveBar({ dirty, saving = false, onSave, onDiscard, message, saveLabel, discardLabel }: SaveBarRegistration): void {\n const api = React.useContext(SaveBarApiContext)\n\n // Keep latest handlers in the shared ref (no state churn from new closures).\n React.useEffect(() => {\n if (api) api.handlers.current = { onSave, onDiscard }\n })\n\n // Drive visibility from primitives only; `api` is stable → no render loops.\n React.useEffect(() => {\n if (!api) return\n api.setState({ visible: dirty, saving, message, saveLabel, discardLabel })\n return () => api.setState((s) => ({ ...s, visible: false }))\n }, [api, dirty, saving, message, saveLabel, discardLabel])\n}\n\n/** The floating island. Rendered once by the shell inside the content column. */\nexport function SaveBar({ className }: { className?: string }) {\n const state = React.useContext(SaveBarStateContext)\n const api = React.useContext(SaveBarApiContext)\n const t = useTranslation()\n\n // Keep the island mounted through its exit animation: `rendered` lags behind\n // `visible` so we can play fade-out before unmounting.\n const [rendered, setRendered] = React.useState(state.visible)\n const [closing, setClosing] = React.useState(false)\n\n React.useEffect(() => {\n if (state.visible) {\n setRendered(true)\n setClosing(false)\n return\n }\n if (!rendered) return\n setClosing(true)\n const id = setTimeout(() => { setRendered(false); setClosing(false) }, 200)\n return () => clearTimeout(id)\n }, [state.visible, rendered])\n\n if (!api || !rendered) return null\n const { saving, message, saveLabel, discardLabel } = state\n\n return (\n <div className={cn('pointer-events-none fixed inset-x-0 bottom-5 z-40 flex justify-center px-4', className)}>\n {/* Dark island for strong contrast against the light page (auto-inverts in dark mode). */}\n <div className={cn(\n 'pointer-events-auto flex items-center gap-5 rounded-full bg-foreground py-2 pl-5 pr-2 text-background shadow-xl ring-1 ring-black/5 duration-200',\n closing ? 'animate-out fade-out slide-out-to-bottom-2' : 'animate-in fade-in slide-in-from-bottom-2',\n )}>\n <span className=\"flex items-center gap-2 text-sm font-medium\">\n <span className=\"h-2 w-2 shrink-0 rounded-full bg-amber-400\" />\n {message ?? t('saveBar.unsaved')}\n </span>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n disabled={saving}\n onClick={() => api.handlers.current.onDiscard?.()}\n className=\"rounded-full px-3 py-1.5 text-sm font-medium text-background/70 transition-colors hover:bg-background/10 hover:text-background disabled:opacity-50\"\n >\n {discardLabel ?? t('common.discard')}\n </button>\n <button\n type=\"button\"\n disabled={saving}\n onClick={() => api.handlers.current.onSave?.()}\n className=\"inline-flex items-center rounded-full bg-background px-4 py-1.5 text-sm font-semibold text-foreground transition-colors hover:bg-background/90 disabled:opacity-60\"\n >\n {saving && <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" />}\n {saveLabel ?? t('common.save')}\n </button>\n </div>\n </div>\n </div>\n )\n}\n","import * as React from 'react'\nimport { create } from 'zustand'\n\ninterface PageHeaderState {\n /** What the shell's top bar shows INSTEAD of the page title, or null. */\n slot: React.ReactNode | null\n /** Identity of whoever owns the slot, so a late unmount can't clear a newer\n * owner's content — the exact race you get navigating form → form. */\n owner: string | null\n /** How many shells are currently rendering the slot. A page needs to know:\n * with no host (minimal layout, an embedded form, a modal) its header would\n * be claimed into the void, and the page must draw it inline instead. */\n hosts: number\n /**\n * Quantos OUTLETS internos estão mostrando o slot. Um outlet é um container\n * mais fundo que a shell — a coluna de conteúdo de um módulo com trilha\n * lateral — que fica em melhor posição para desenhar o cabeçalho.\n *\n * Quando existe um, a barra da shell se cala: as duas juntas desenhariam a\n * mesma migalha duas vezes, e a da shell atravessa a largura inteira,\n * empurrando a trilha do módulo para baixo do topo.\n */\n outlets: number\n claim: (owner: string, node: React.ReactNode) => void\n release: (owner: string) => void\n addHost: () => void\n removeHost: () => void\n addOutlet: () => void\n removeOutlet: () => void\n}\n\nconst usePageHeaderStore = create<PageHeaderState>((set, get) => ({\n slot: null,\n owner: null,\n hosts: 0,\n outlets: 0,\n claim: (owner, node) => set({ owner, slot: node }),\n release: (owner) => {\n if (get().owner === owner) set({ owner: null, slot: null })\n },\n addHost: () => set((s) => ({ hosts: s.hosts + 1 })),\n removeHost: () => set((s) => ({ hosts: Math.max(0, s.hosts - 1) })),\n addOutlet: () => set((s) => ({ outlets: s.outlets + 1 })),\n removeOutlet: () => set((s) => ({ outlets: Math.max(0, s.outlets - 1) })),\n}))\n\n/** Read the current override. The shell calls this; pages should not. */\nexport function usePageHeaderSlot(): React.ReactNode | null {\n return usePageHeaderStore((s) => s.slot)\n}\n\n/**\n * Declare that this shell renders the page-header slot. Called by the layout,\n * never by a page. Without it `PageHeader` cannot tell \"nobody claimed the bar\"\n * from \"there is no bar\", and a header would vanish instead of falling back.\n */\nexport function usePageHeaderHost(): void {\n const addHost = usePageHeaderStore((s) => s.addHost)\n const removeHost = usePageHeaderStore((s) => s.removeHost)\n React.useEffect(() => {\n addHost()\n return removeHost\n }, [addHost, removeHost])\n}\n\n/** Whether any shell OR inner outlet is showing the slot right now. */\nexport function useHasPageHeaderHost(): boolean {\n return usePageHeaderStore((s) => s.hosts > 0 || s.outlets > 0)\n}\n\n/** True when a deeper container took over drawing the header. The shell bar\n * uses this to stand down. */\nexport function useHasPageHeaderOutlet(): boolean {\n return usePageHeaderStore((s) => s.outlets > 0)\n}\n\n/**\n * Desenha o cabeçalho AQUI em vez de na barra da shell.\n *\n * Para quem tem uma coluna própria de conteúdo — um módulo com trilha lateral —,\n * onde a barra da shell, larga demais, passaria por cima da trilha.\n */\nexport function PageHeaderOutlet({ className }: { className?: string }): React.ReactElement | null {\n const slot = usePageHeaderStore((s) => s.slot)\n const addOutlet = usePageHeaderStore((s) => s.addOutlet)\n const removeOutlet = usePageHeaderStore((s) => s.removeOutlet)\n\n React.useEffect(() => {\n addOutlet()\n return removeOutlet\n }, [addOutlet, removeOutlet])\n\n if (!slot) return null\n return React.createElement('div', { className: className ?? 'mb-4' }, slot)\n}\n\n/**\n * Put this page's own header — a back link, a breadcrumb — into the shell's top\n * bar, replacing the page title for as long as the page is mounted.\n *\n * Prefer the `PageHeader` component: it is this hook plus the one agreed layout\n * (← + title), so every screen in every app reads the same. Reach for the hook\n * directly only for a header that genuinely is not \"back + title\".\n *\n * A form or detail screen already says where it is (\"← Novo produto\") and the\n * bar above it was saying \"Produtos\" again, one line up. Two headers stacked is\n * a whole row of vertical space spent repeating a word.\n *\n * The node is re-claimed on every change so a breadcrumb whose label depends on\n * loaded data (a record's name) updates once it arrives.\n */\nexport function usePageHeader(node: React.ReactNode | null): void {\n const id = React.useId()\n const claim = usePageHeaderStore((s) => s.claim)\n const release = usePageHeaderStore((s) => s.release)\n\n React.useEffect(() => {\n if (node == null) {\n release(id)\n return\n }\n claim(id, node)\n return () => release(id)\n }, [id, node, claim, release])\n}\n\nexport { usePageHeaderStore }\n","import { useNavReferrer, navHistoryBack, routeModule } from '@fayz-ai/core'\n\n/**\n * Context-aware back target shared by all header/breadcrumb components.\n *\n * When the user arrived from a *different* module (tracked in the global\n * navigation history), a page's own onBack/parentLabel point at its local\n * parent — wrong for the referrer. In that case we return the referrer's label\n * and a back action that pops the browser history to the actual previous page.\n * Within the same module the page's own (more specific) values pass through\n * unchanged, so existing behavior is preserved.\n */\nexport function useCrossModuleBack(onBack?: () => void, parentLabel?: string): {\n onBack?: () => void\n parentLabel?: string\n isCrossModule: boolean\n} {\n const currentPath = typeof window !== 'undefined'\n ? ((window.location.hash ? window.location.hash.slice(1) : window.location.pathname) || '/')\n : '/'\n const referrer = useNavReferrer(currentPath)\n const cross = referrer && referrer.label && routeModule(referrer.path) !== routeModule(currentPath)\n ? referrer\n : null\n return {\n onBack: cross ? () => navHistoryBack(onBack) : onBack,\n parentLabel: cross ? cross.label : parentLabel,\n isCrossModule: !!cross,\n }\n}\n","import * as React from 'react'\nimport { ArrowLeft } from 'lucide-react'\nimport { usePageHeader, useHasPageHeaderHost } from '../stores/page-header.store'\nimport { useBackHandler } from '../layout/SaveBar'\nimport { useCrossModuleBack } from '../layout/useCrossModuleBack'\n\n// ---------------------------------------------------------------------------\n// PageHeader — the header of ANY inner page, in one place.\n//\n// ← Orders / Order #1138 in the shell bar\n// ──────────────────────────\n// content, without repeating the title\n//\n// In the bar and not in the body because the bar exists anyway and already owns\n// the height: a header in the body spends a whole extra row saying what the bar\n// says for free — which is how screens ended up titled twice, \"Financial\" in the\n// bar and \"Payables\" right below it.\n//\n// With no bar (minimal layout, embedded form, modal) it draws inline, otherwise\n// the header would simply vanish.\n// ---------------------------------------------------------------------------\n\n/**\n * The header's markup, hook-free, so the shell can draw the SAME thing when the\n * title comes from the route instead of the page. Two copies of this markup is\n * how the app grew two different back arrows.\n */\nexport function PageHeaderCrumb({\n title,\n parentLabel,\n onBack,\n}: {\n title?: React.ReactNode\n parentLabel?: string\n onBack?: () => void\n}) {\n // No back path means a top-level page: just the title, at title size. No\n // point demoting it to a breadcrumb.\n if (!onBack) {\n return title ? <h2 className=\"min-w-0 truncate text-lg font-semibold\">{title}</h2> : null\n }\n\n return (\n <nav className=\"flex min-w-0 items-center gap-1.5 text-sm text-muted-foreground\">\n <button\n type=\"button\"\n onClick={onBack}\n className=\"inline-flex shrink-0 items-center gap-1 transition-colors hover:text-foreground\"\n >\n <ArrowLeft className=\"h-3.5 w-3.5\" />\n {parentLabel ?? 'Voltar'}\n </button>\n {title != null && (\n <>\n <span className=\"shrink-0\">/</span>\n {title === '' ? (\n // Title still waiting on data: a pulsing bar, otherwise the line\n // appears from nowhere and shoves the rest when the record lands.\n <span className=\"inline-block h-4 w-24 animate-pulse rounded bg-muted align-middle\" />\n ) : (\n <span className=\"min-w-0 truncate font-medium text-foreground\">{title}</span>\n )}\n </>\n )}\n </nav>\n )\n}\n\nexport interface PageHeaderProps {\n /** What THIS page is. Empty while loading → pulsing placeholder. */\n title: React.ReactNode\n /** Where the arrow goes back to. Without it there is no crumb, just the title. */\n onBack?: () => void\n /** Name of the arrow's destination (\"Orders\"), written before the slash. */\n parentLabel?: string\n /** Link text when there is no `parentLabel`. */\n backLabel?: string\n}\n\nexport function PageHeader({ title, onBack, parentLabel, backLabel }: PageHeaderProps) {\n const hasHost = useHasPageHeaderHost()\n\n // Arriving from another module goes back where you came from, not to this\n // screen's theoretical parent.\n const { onBack: effectiveOnBack, parentLabel: effectiveParent } = useCrossModuleBack(onBack, parentLabel)\n // The same action becomes the app's Escape, with no per-plugin code.\n useBackHandler(effectiveOnBack)\n\n const node = React.useMemo(() => (\n <PageHeaderCrumb\n title={title}\n parentLabel={effectiveParent ?? backLabel}\n onBack={effectiveOnBack}\n />\n ), [effectiveOnBack, effectiveParent, backLabel, title])\n\n // The claim is unconditional (hook order cannot change); what varies is\n // whether ANYONE is showing the bar.\n usePageHeader(hasHost ? node : null)\n\n if (hasHost) return null\n return <div className=\"mb-4\">{node}</div>\n}\n","import * as React from 'react'\nimport { cn } from '../lib/cn'\n\nexport interface HeaderTab<T extends string = string> {\n value: T\n label: React.ReactNode\n /** Rendered before the label (already-sized lucide component or node). */\n icon?: React.ComponentType<{ className?: string }>\n /** Small trailing count chip — omit for none (0 still renders). */\n count?: number\n /** Trailing adornment (e.g. a plan-gate badge). Rendered after the count. */\n badge?: React.ReactNode\n}\n\nexport interface HeaderTabsProps<T extends string = string> {\n tabs: ReadonlyArray<HeaderTab<T>>\n value: T\n onChange: (value: T) => void\n className?: string\n 'aria-label'?: string\n}\n\n/**\n * The list-header tab strip: a bordered group whose active item lifts onto a\n * card surface, with hairline separators between the resting ones.\n *\n * Distinct from SegmentedControl on purpose. SegmentedControl is a compact\n * inline toggle (7d/30d) that inverts to a solid foreground pill; this is the\n * primary view switch at the top of a list — taller, icon-capable, and quiet\n * enough that the page's action buttons still read as the loudest thing in the\n * row.\n */\nexport function HeaderTabs<T extends string = string>({\n tabs, value, onChange, className, ...rest\n}: HeaderTabsProps<T>) {\n return (\n <div\n role=\"tablist\"\n aria-label={rest['aria-label']}\n className={cn(\n 'inline-flex items-center gap-0.5 rounded-lg border border-border bg-muted/40 p-1',\n className,\n )}\n >\n {tabs.map((tab, i) => {\n const active = tab.value === value\n const Icon = tab.icon\n // Separators sit between two resting tabs only — next to the raised\n // active tab its own edge already does the dividing, and drawing both\n // reads as a double rule.\n const separated = i > 0 && !active && tabs[i - 1]!.value !== value\n return (\n <button\n key={tab.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n onClick={() => onChange(tab.value)}\n className={cn(\n 'relative flex h-8 items-center gap-1.5 rounded-md px-3 text-[13px] font-medium transition-colors',\n active\n ? 'bg-card text-foreground shadow-button'\n : 'text-muted-foreground hover:text-foreground',\n separated && 'before:absolute before:left-[-3px] before:top-1.5 before:h-5 before:w-px before:bg-border',\n )}\n >\n {Icon ? <Icon className=\"h-3.5 w-3.5 shrink-0\" /> : null}\n <span className=\"truncate\">{tab.label}</span>\n {tab.count != null && (\n <span className={cn(\n 'ml-0.5 rounded-full px-1.5 text-[11px] tabular-nums',\n active ? 'bg-muted text-muted-foreground' : 'bg-muted/70 text-muted-foreground',\n )}>\n {tab.count}\n </span>\n )}\n {tab.badge}\n </button>\n )\n })}\n </div>\n )\n}\n"]}
|
package/dist/chunk-ZBQ772DU.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { create } from 'zustand';
|
|
2
|
-
|
|
3
|
-
// src/stores/layout.store.ts
|
|
4
|
-
var useLayoutStore = create((set) => ({
|
|
5
|
-
sidebarOpen: true,
|
|
6
|
-
sidebarCollapsed: false,
|
|
7
|
-
mobileDrawerOpen: false,
|
|
8
|
-
commandPaletteOpen: false,
|
|
9
|
-
toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })),
|
|
10
|
-
setSidebarCollapsed: (collapsed) => set({ sidebarCollapsed: collapsed }),
|
|
11
|
-
toggleMobileDrawer: () => set((state) => ({ mobileDrawerOpen: !state.mobileDrawerOpen })),
|
|
12
|
-
setCommandPaletteOpen: (open) => set({ commandPaletteOpen: open })
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
|
-
export { useLayoutStore };
|
|
16
|
-
//# sourceMappingURL=chunk-ZBQ772DU.js.map
|
|
17
|
-
//# sourceMappingURL=chunk-ZBQ772DU.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/stores/layout.store.ts"],"names":[],"mappings":";;;AAaO,IAAM,cAAA,GAAiB,MAAA,CAAoB,CAAC,GAAA,MAAS;AAAA,EAC1D,WAAA,EAAa,IAAA;AAAA,EACb,gBAAA,EAAkB,KAAA;AAAA,EAClB,gBAAA,EAAkB,KAAA;AAAA,EAClB,kBAAA,EAAoB,KAAA;AAAA,EAEpB,aAAA,EAAe,MACb,GAAA,CAAI,CAAC,KAAA,MAAW,EAAE,WAAA,EAAa,CAAC,KAAA,CAAM,WAAA,EAAY,CAAE,CAAA;AAAA,EAEtD,qBAAqB,CAAC,SAAA,KACpB,IAAI,EAAE,gBAAA,EAAkB,WAAW,CAAA;AAAA,EAErC,kBAAA,EAAoB,MAClB,GAAA,CAAI,CAAC,KAAA,MAAW,EAAE,gBAAA,EAAkB,CAAC,KAAA,CAAM,gBAAA,EAAiB,CAAE,CAAA;AAAA,EAEhE,uBAAuB,CAAC,IAAA,KACtB,IAAI,EAAE,kBAAA,EAAoB,MAAM;AACpC,CAAA,CAAE","file":"chunk-ZBQ772DU.js","sourcesContent":["import { create } from 'zustand'\n\ninterface LayoutState {\n sidebarOpen: boolean\n sidebarCollapsed: boolean\n mobileDrawerOpen: boolean\n commandPaletteOpen: boolean\n toggleSidebar: () => void\n setSidebarCollapsed: (collapsed: boolean) => void\n toggleMobileDrawer: () => void\n setCommandPaletteOpen: (open: boolean) => void\n}\n\nexport const useLayoutStore = create<LayoutState>((set) => ({\n sidebarOpen: true,\n sidebarCollapsed: false,\n mobileDrawerOpen: false,\n commandPaletteOpen: false,\n\n toggleSidebar: () =>\n set((state) => ({ sidebarOpen: !state.sidebarOpen })),\n\n setSidebarCollapsed: (collapsed) =>\n set({ sidebarCollapsed: collapsed }),\n\n toggleMobileDrawer: () =>\n set((state) => ({ mobileDrawerOpen: !state.mobileDrawerOpen })),\n\n setCommandPaletteOpen: (open) =>\n set({ commandPaletteOpen: open }),\n}))\n"]}
|