@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
@@ -1,12 +1,16 @@
1
+ import { useModuleHeaderActionsSlot, useModuleHeaderSlot } from './chunk-RRNMNFLF.js';
1
2
  import { cn, Button } from './chunk-OKZ6WQB3.js';
2
- import * as React6 from 'react';
3
- import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import * as React10 from 'react';
4
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
5
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
5
- import { ChevronRight, Check, Circle, Minus, ChevronDown, ArrowDown, ArrowUp, ArrowUpDown, Calendar, GripVertical, RefreshCw } from 'lucide-react';
6
+ import { ChevronRight, Check, Circle, Minus, ChevronDown, ArrowDown, ArrowUp, ArrowUpDown, MoreHorizontal, Plus, MoreVertical, Calendar, X, SlidersHorizontal, GripVertical, RefreshCw } from 'lucide-react';
6
7
  import { useReactTable, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
7
8
  import { useTranslation } from '@fayz-ai/core';
9
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
10
+ import { createPortal } from 'react-dom';
11
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
8
12
 
9
- var Card = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
13
+ var Card = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
10
14
  "div",
11
15
  {
12
16
  ref,
@@ -18,7 +22,7 @@ var Card = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ j
18
22
  }
19
23
  ));
20
24
  Card.displayName = "Card";
21
- var CardHeader = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
25
+ var CardHeader = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
22
26
  "div",
23
27
  {
24
28
  ref,
@@ -27,7 +31,7 @@ var CardHeader = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE_
27
31
  }
28
32
  ));
29
33
  CardHeader.displayName = "CardHeader";
30
- var CardTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
34
+ var CardTitle = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
31
35
  "h3",
32
36
  {
33
37
  ref,
@@ -39,7 +43,7 @@ var CardTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__
39
43
  }
40
44
  ));
41
45
  CardTitle.displayName = "CardTitle";
42
- var CardDescription = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
46
+ var CardDescription = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
43
47
  "p",
44
48
  {
45
49
  ref,
@@ -48,9 +52,9 @@ var CardDescription = React6.forwardRef(({ className, ...props }, ref) => /* @__
48
52
  }
49
53
  ));
50
54
  CardDescription.displayName = "CardDescription";
51
- var CardContent = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-4 pt-0", className), ...props }));
55
+ var CardContent = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-4 pt-0", className), ...props }));
52
56
  CardContent.displayName = "CardContent";
53
- var CardFooter = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
57
+ var CardFooter = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
54
58
  "div",
55
59
  {
56
60
  ref,
@@ -65,7 +69,7 @@ var DropdownGroup = DropdownMenuPrimitive.Group;
65
69
  var DropdownPortal = DropdownMenuPrimitive.Portal;
66
70
  var DropdownSub = DropdownMenuPrimitive.Sub;
67
71
  var DropdownRadioGroup = DropdownMenuPrimitive.RadioGroup;
68
- var DropdownSubTrigger = React6.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs(
72
+ var DropdownSubTrigger = React10.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs(
69
73
  DropdownMenuPrimitive.SubTrigger,
70
74
  {
71
75
  ref,
@@ -82,7 +86,7 @@ var DropdownSubTrigger = React6.forwardRef(({ className, inset, children, ...pro
82
86
  }
83
87
  ));
84
88
  DropdownSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
85
- var DropdownSubContent = React6.forwardRef(({ className, ...props }, ref) => (
89
+ var DropdownSubContent = React10.forwardRef(({ className, ...props }, ref) => (
86
90
  // Portaled, like DropdownContent. Without it the submenu renders inside the
87
91
  // parent panel's DOM — and that panel is `overflow-hidden`, so the submenu
88
92
  // was clipped to its box: a flyout you could open and never reach.
@@ -99,7 +103,7 @@ var DropdownSubContent = React6.forwardRef(({ className, ...props }, ref) => (
99
103
  ) })
100
104
  ));
101
105
  DropdownSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
102
- var DropdownContent = React6.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
106
+ var DropdownContent = React10.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(
103
107
  DropdownMenuPrimitive.Content,
104
108
  {
105
109
  ref,
@@ -112,7 +116,7 @@ var DropdownContent = React6.forwardRef(({ className, sideOffset = 4, ...props }
112
116
  }
113
117
  ) }));
114
118
  DropdownContent.displayName = DropdownMenuPrimitive.Content.displayName;
115
- var DropdownItem = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
119
+ var DropdownItem = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
116
120
  DropdownMenuPrimitive.Item,
117
121
  {
118
122
  ref,
@@ -125,7 +129,7 @@ var DropdownItem = React6.forwardRef(({ className, inset, ...props }, ref) => /*
125
129
  }
126
130
  ));
127
131
  DropdownItem.displayName = DropdownMenuPrimitive.Item.displayName;
128
- var DropdownCheckboxItem = React6.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs(
132
+ var DropdownCheckboxItem = React10.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs(
129
133
  DropdownMenuPrimitive.CheckboxItem,
130
134
  {
131
135
  ref,
@@ -142,7 +146,7 @@ var DropdownCheckboxItem = React6.forwardRef(({ className, children, checked, ..
142
146
  }
143
147
  ));
144
148
  DropdownCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
145
- var DropdownRadioItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
149
+ var DropdownRadioItem = React10.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
146
150
  DropdownMenuPrimitive.RadioItem,
147
151
  {
148
152
  ref,
@@ -158,7 +162,7 @@ var DropdownRadioItem = React6.forwardRef(({ className, children, ...props }, re
158
162
  }
159
163
  ));
160
164
  DropdownRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
161
- var DropdownLabel = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
165
+ var DropdownLabel = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(
162
166
  DropdownMenuPrimitive.Label,
163
167
  {
164
168
  ref,
@@ -171,7 +175,7 @@ var DropdownLabel = React6.forwardRef(({ className, inset, ...props }, ref) => /
171
175
  }
172
176
  ));
173
177
  DropdownLabel.displayName = DropdownMenuPrimitive.Label.displayName;
174
- var DropdownSeparator = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
178
+ var DropdownSeparator = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
175
179
  DropdownMenuPrimitive.Separator,
176
180
  {
177
181
  ref,
@@ -199,7 +203,7 @@ var COLOR_CLASSES = {
199
203
  warning: "border-warning bg-warning text-white",
200
204
  destructive: "border-destructive bg-destructive text-destructive-foreground"
201
205
  };
202
- var Checkbox = React6.forwardRef(
206
+ var Checkbox = React10.forwardRef(
203
207
  ({ checked = false, onChange, disabled, className, color = "primary", id, indeterminate = false, ...props }, ref) => {
204
208
  const filled = checked || indeterminate;
205
209
  return /* @__PURE__ */ jsx(
@@ -249,28 +253,28 @@ function DataTable({
249
253
  const tdCls = compact ? "px-3 py-1.5 align-middle text-xs" : "px-4 py-3 align-middle";
250
254
  const tableCls = compact ? "w-full text-xs min-w-max" : "w-full text-sm min-w-max";
251
255
  const rowHoverCls = isCard ? "hover:bg-muted/30" : "hover:bg-muted/20";
252
- const [sorting, setSorting] = React6.useState([]);
253
- const rowId = React6.useCallback(
256
+ const [sorting, setSorting] = React10.useState([]);
257
+ const rowId = React10.useCallback(
254
258
  (row) => getRowId ? getRowId(row) : String(row.id ?? ""),
255
259
  [getRowId]
256
260
  );
257
- const selected = React6.useMemo(() => new Set(selectedIds ?? []), [selectedIds]);
258
- const pageIds = React6.useMemo(() => data.map(rowId), [data, rowId]);
261
+ const selected = React10.useMemo(() => new Set(selectedIds ?? []), [selectedIds]);
262
+ const pageIds = React10.useMemo(() => data.map(rowId), [data, rowId]);
259
263
  const selectedOnPage = pageIds.filter((id) => selected.has(id)).length;
260
264
  const allOnPageSelected = pageIds.length > 0 && selectedOnPage === pageIds.length;
261
- const toggleRow = React6.useCallback((id) => {
265
+ const toggleRow = React10.useCallback((id) => {
262
266
  const next = new Set(selected);
263
267
  if (next.has(id)) next.delete(id);
264
268
  else next.add(id);
265
269
  onSelectedIdsChange?.([...next]);
266
270
  }, [selected, onSelectedIdsChange]);
267
- const toggleAllOnPage = React6.useCallback(() => {
271
+ const toggleAllOnPage = React10.useCallback(() => {
268
272
  const next = new Set(selected);
269
273
  if (allOnPageSelected) pageIds.forEach((id) => next.delete(id));
270
274
  else pageIds.forEach((id) => next.add(id));
271
275
  onSelectedIdsChange?.([...next]);
272
276
  }, [selected, allOnPageSelected, pageIds, onSelectedIdsChange]);
273
- const selectionColumn = React6.useMemo(() => ({
277
+ const selectionColumn = React10.useMemo(() => ({
274
278
  id: "__select__",
275
279
  enableSorting: false,
276
280
  header: () => /* @__PURE__ */ jsx(
@@ -297,7 +301,7 @@ function DataTable({
297
301
  // ids: turning the page with nothing selected changes no other dep, and the
298
302
  // memo would hand the header a button that ticks the previous page's rows.
299
303
  }), [allOnPageSelected, selectedOnPage, selected, rowId, toggleRow, toggleAllOnPage, t]);
300
- const allColumns = React6.useMemo(
304
+ const allColumns = React10.useMemo(
301
305
  () => selectable ? [selectionColumn, ...columns] : columns,
302
306
  [selectable, selectionColumn, columns]
303
307
  );
@@ -315,6 +319,10 @@ function DataTable({
315
319
  /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: skeletonRows }).map((_, i) => /* @__PURE__ */ jsx("tr", { className: "border-b last:border-0", children: allColumns.map((_2, j) => /* @__PURE__ */ jsx("td", { className: tdCls, children: /* @__PURE__ */ jsx("div", { className: "h-3.5 w-full animate-pulse rounded bg-muted" }) }, j)) }, i)) })
316
320
  ] }) }) });
317
321
  }
322
+ const showEmptyBlock = !loading && table.getRowModel().rows.length === 0;
323
+ if (showEmptyBlock) {
324
+ return /* @__PURE__ */ jsx("div", { className: wrapperCls, children: /* @__PURE__ */ jsx("div", { className: "flex min-h-64 w-full items-center justify-center px-4 py-10 text-center text-muted-foreground", children: emptyMessage }) });
325
+ }
318
326
  return /* @__PURE__ */ jsx("div", { className: wrapperCls, children: /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: tableCls, children: [
319
327
  /* @__PURE__ */ jsx("thead", { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx("tr", { className: headerCls, children: headerGroup.headers.map((header) => {
320
328
  const sorted = header.column.getIsSorted();
@@ -370,12 +378,28 @@ function DataTable({
370
378
  }) : /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: allColumns.length, className: "h-64 px-6 text-center align-middle text-muted-foreground", children: emptyMessage }) }) })
371
379
  ] }) }) });
372
380
  }
381
+ var TooltipProvider = TooltipPrimitive.Provider;
382
+ var Tooltip = TooltipPrimitive.Root;
383
+ var TooltipTrigger = TooltipPrimitive.Trigger;
384
+ var TooltipContent = React10.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
385
+ TooltipPrimitive.Content,
386
+ {
387
+ ref,
388
+ sideOffset,
389
+ className: cn(
390
+ "fayz-glass-surface z-[120] overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
391
+ className
392
+ ),
393
+ ...props
394
+ }
395
+ ));
396
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
373
397
  var WIDE_QUERY = "(min-width: 768px)";
374
398
  function useIsWide(query = WIDE_QUERY) {
375
- const [wide, setWide] = React6.useState(
399
+ const [wide, setWide] = React10.useState(
376
400
  () => typeof window === "undefined" ? true : window.matchMedia(query).matches
377
401
  );
378
- React6.useEffect(() => {
402
+ React10.useEffect(() => {
379
403
  const mq = window.matchMedia(query);
380
404
  const onChange = () => setWide(mq.matches);
381
405
  mq.addEventListener("change", onChange);
@@ -383,6 +407,219 @@ function useIsWide(query = WIDE_QUERY) {
383
407
  }, [query]);
384
408
  return wide;
385
409
  }
410
+ var Hint = React10.forwardRef(function Hint2({ label, children, side = "top", delayDuration = 0, ...rest }, ref) {
411
+ if (!label) return React10.cloneElement(children, { ...rest, ref });
412
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Provider, { delayDuration, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
413
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, ...rest, ref, children }),
414
+ /* @__PURE__ */ jsx(TooltipContent, { side, className: "px-2 py-1 text-xs font-medium", children: label })
415
+ ] }) });
416
+ });
417
+ function iconOf(action, className) {
418
+ const Icon = action.icon;
419
+ return Icon ? /* @__PURE__ */ jsx(Icon, { className }) : null;
420
+ }
421
+ function PageActionBar({ actions, className }) {
422
+ const wide = useIsWide();
423
+ const visible = actions.filter((a) => !a.hidden);
424
+ if (visible.length === 0) return null;
425
+ if (!wide) {
426
+ const usable = visible.filter((a) => !a.desktopOnly);
427
+ return usable.length > 0 ? /* @__PURE__ */ jsx(PageActionFab, { actions: usable }) : null;
428
+ }
429
+ let seenPrimary = false;
430
+ const primary = [];
431
+ const secondary = [];
432
+ const utility = [];
433
+ const danger = [];
434
+ for (const a of visible) {
435
+ const intent = a.intent ?? "secondary";
436
+ if (intent === "primary" && !seenPrimary) {
437
+ seenPrimary = true;
438
+ primary.push(a);
439
+ continue;
440
+ }
441
+ if (intent === "danger") {
442
+ danger.push(a);
443
+ continue;
444
+ }
445
+ if (intent === "utility") {
446
+ utility.push(a);
447
+ continue;
448
+ }
449
+ secondary.push(a);
450
+ }
451
+ const head = primary[0];
452
+ const menu = [...secondary, ...danger];
453
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex shrink-0 items-center gap-2", className), children: [
454
+ utility.map((a) => (
455
+ // Um botão só de ícone não diz o que faz. `title=` parecia resolver e
456
+ // não resolve: espera ~1s que ninguém controla, sai na pintura do
457
+ // sistema operacional, nunca aparece no toque e vários leitores de tela
458
+ // pulam. Hint é o tooltip do design system, e o texto é ANUNCIADO.
459
+ /* @__PURE__ */ jsx(Hint, { label: a.label, children: /* @__PURE__ */ jsx(
460
+ Button,
461
+ {
462
+ variant: "ghost",
463
+ size: "icon",
464
+ onClick: () => void a.onSelect(),
465
+ disabled: a.disabled,
466
+ "aria-label": a.label,
467
+ "data-testid": a.testId,
468
+ "data-tour": `action.${a.id}`,
469
+ children: iconOf(a, "h-4 w-4")
470
+ }
471
+ ) }, a.id)
472
+ )),
473
+ head && menu.length === 0 && /* @__PURE__ */ jsxs(Button, { onClick: () => void head.onSelect(), disabled: head.disabled, "data-testid": head.testId, "data-tour": `action.${head.id}`, children: [
474
+ iconOf(head, "mr-1.5 h-4 w-4"),
475
+ head.label
476
+ ] }),
477
+ head && menu.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
478
+ /* @__PURE__ */ jsxs(Button, { className: "rounded-r-none", onClick: () => void head.onSelect(), disabled: head.disabled, "data-testid": head.testId, "data-tour": `action.${head.id}`, children: [
479
+ iconOf(head, "mr-1.5 h-4 w-4"),
480
+ head.label
481
+ ] }),
482
+ /* @__PURE__ */ jsxs(Dropdown, { children: [
483
+ /* @__PURE__ */ jsx(DropdownTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Hint, { label: `${head.label}\u2026`, children: /* @__PURE__ */ jsx(
484
+ Button,
485
+ {
486
+ className: "-ml-px rounded-l-none px-2",
487
+ "aria-label": `${head.label}\u2026`,
488
+ "data-tour": menu.map((a) => `action.${a.id}`).join(" "),
489
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
490
+ }
491
+ ) }) }),
492
+ /* @__PURE__ */ jsx(DropdownContent, { align: "end", className: "w-56", children: /* @__PURE__ */ jsx(ActionItems, { actions: menu }) })
493
+ ] })
494
+ ] }),
495
+ !head && menu.length > 0 && /* @__PURE__ */ jsxs(Dropdown, { children: [
496
+ /* @__PURE__ */ jsx(DropdownTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Hint, { label: "A\xE7\xF5es", children: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "icon", "aria-label": "A\xE7\xF5es", children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "h-4 w-4" }) }) }) }),
497
+ /* @__PURE__ */ jsx(DropdownContent, { align: "end", className: "w-56", children: /* @__PURE__ */ jsx(ActionItems, { actions: menu }) })
498
+ ] })
499
+ ] });
500
+ }
501
+ function ActionItems({ actions, stagger }) {
502
+ const out = [];
503
+ actions.forEach((a, i) => {
504
+ const isDanger = a.intent === "danger";
505
+ const prevSafe = i > 0 && actions[i - 1].intent !== "danger";
506
+ if (isDanger && prevSafe) out.push(/* @__PURE__ */ jsx(DropdownSeparator, {}, `${a.id}-sep`));
507
+ out.push(
508
+ /* @__PURE__ */ jsxs(
509
+ DropdownItem,
510
+ {
511
+ disabled: a.disabled,
512
+ onSelect: () => void a.onSelect(),
513
+ "data-testid": a.testId,
514
+ style: stagger ? { ["--i"]: i } : void 0,
515
+ className: cn("gap-2", stagger && "fz-fab-item", isDanger && "text-destructive focus:text-destructive"),
516
+ children: [
517
+ iconOf(a, "h-4 w-4 shrink-0"),
518
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
519
+ /* @__PURE__ */ jsx("span", { className: "block truncate", children: a.label }),
520
+ a.description && /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-muted-foreground", children: a.description })
521
+ ] })
522
+ ]
523
+ },
524
+ a.id
525
+ )
526
+ );
527
+ });
528
+ return /* @__PURE__ */ jsx(Fragment, { children: out });
529
+ }
530
+ function PageActionFab({ actions }) {
531
+ const byIntent = (i) => actions.filter((a) => (a.intent ?? "secondary") === i);
532
+ const utility = byIntent("utility");
533
+ const main = [...byIntent("primary"), ...byIntent("secondary"), ...byIntent("danger")];
534
+ if (main.length === 0) return /* @__PURE__ */ jsx(FabButton, { actions: utility, tone: "neutral" });
535
+ const isCreate = main.every((a) => a.creates ?? a.icon === Plus);
536
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
537
+ utility.length > 0 && /* @__PURE__ */ jsx(FabButton, { actions: utility, tone: "neutral", mini: true }),
538
+ /* @__PURE__ */ jsx(FabButton, { actions: main, tone: isCreate ? "primary" : "neutral" })
539
+ ] });
540
+ }
541
+ function useScrim(open) {
542
+ const [mounted, setMounted] = React10.useState(open);
543
+ const [visible, setVisible] = React10.useState(open);
544
+ React10.useEffect(() => {
545
+ if (open) {
546
+ setMounted(true);
547
+ const frame = requestAnimationFrame(() => setVisible(true));
548
+ return () => cancelAnimationFrame(frame);
549
+ }
550
+ setVisible(false);
551
+ const timer = window.setTimeout(() => setMounted(false), SCRIM_MS);
552
+ return () => window.clearTimeout(timer);
553
+ }, [open]);
554
+ return { mounted, visible };
555
+ }
556
+ var SCRIM_MS = 200;
557
+ function FabButton({ actions, tone, mini }) {
558
+ const [open, setOpen] = React10.useState(false);
559
+ const scrim = useScrim(open);
560
+ if (actions.length === 0) return null;
561
+ const isCreate = tone === "primary";
562
+ const FabIcon = isCreate ? Plus : MoreVertical;
563
+ const style = {
564
+ bottom: mini ? "calc(var(--fz-bottom-bar, 0px) + 4.75rem)" : "calc(var(--fz-bottom-bar, 0px) + 1rem)"
565
+ };
566
+ const shell = cn(
567
+ "fz-tap fixed z-40 flex items-center justify-center rounded-full",
568
+ "transition-transform active:scale-95 md:hidden",
569
+ // Centred on the main circle's column, so the two read as one stack.
570
+ mini ? "right-5 h-12 w-12" : "right-4 h-14 w-14",
571
+ isCreate ? "bg-primary text-primary-foreground shadow-lg shadow-primary/30 ring-4 ring-background" : "bg-card text-foreground shadow-lg ring-1 ring-border"
572
+ );
573
+ if (actions.length === 1) {
574
+ const only = actions[0];
575
+ const Icon = only.icon ?? FabIcon;
576
+ return /* @__PURE__ */ jsx(
577
+ "button",
578
+ {
579
+ type: "button",
580
+ style,
581
+ className: shell,
582
+ onClick: () => void only.onSelect(),
583
+ disabled: only.disabled,
584
+ "aria-label": only.label,
585
+ "data-testid": only.testId,
586
+ children: /* @__PURE__ */ jsx(Icon, { className: mini ? "h-5 w-5" : "h-6 w-6" })
587
+ }
588
+ );
589
+ }
590
+ return /* @__PURE__ */ jsxs(Dropdown, { open, onOpenChange: setOpen, children: [
591
+ scrim.mounted && typeof document !== "undefined" && createPortal(
592
+ /* @__PURE__ */ jsx(
593
+ "div",
594
+ {
595
+ "aria-hidden": true,
596
+ onClick: () => setOpen(false),
597
+ className: cn(
598
+ "fixed inset-0 z-[100] bg-foreground/40 transition-opacity duration-200 md:hidden",
599
+ "motion-reduce:transition-none",
600
+ scrim.visible ? "opacity-100" : "opacity-0"
601
+ )
602
+ }
603
+ ),
604
+ document.body
605
+ ),
606
+ /* @__PURE__ */ jsx(DropdownTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
607
+ "button",
608
+ {
609
+ type: "button",
610
+ style,
611
+ className: cn(shell, open && "z-[105]", isCreate && "fz-fab-trigger"),
612
+ "aria-label": actionsMenuLabel,
613
+ children: /* @__PURE__ */ jsx(FabIcon, { className: mini ? "h-5 w-5" : "h-6 w-6" })
614
+ }
615
+ ) }),
616
+ /* @__PURE__ */ jsx(DropdownContent, { side: "top", align: "end", sideOffset: 12, className: "fz-fab-menu w-60 md:hidden", children: /* @__PURE__ */ jsx(ActionItems, { actions, stagger: true }) })
617
+ ] });
618
+ }
619
+ var actionsMenuLabel = "A\xE7\xF5es";
620
+ function setActionsMenuLabel(label) {
621
+ actionsMenuLabel = label;
622
+ }
386
623
  function Skeleton({
387
624
  className,
388
625
  ...props
@@ -410,7 +647,55 @@ function TableSkeleton({ columns = 4, rows = 2 }) {
410
647
  )) }, r)) })
411
648
  ] });
412
649
  }
413
- var ToolbarButton = React6.forwardRef(function ToolbarButton2({ icon: Icon, caret = true, children, className, ...props }, ref) {
650
+ var Popover = PopoverPrimitive.Root;
651
+ var PopoverTrigger = PopoverPrimitive.Trigger;
652
+ var PopoverAnchor = PopoverPrimitive.Anchor;
653
+ var PopoverContent = React10.forwardRef(({ className, align = "start", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
654
+ PopoverPrimitive.Content,
655
+ {
656
+ ref,
657
+ align,
658
+ sideOffset,
659
+ className: cn(
660
+ "fayz-glass-surface z-[110] w-72 rounded-xl border bg-popover p-0 text-popover-foreground shadow-lg outline-none",
661
+ "data-[state=open]:animate-zoom-in data-[state=closed]:animate-zoom-out",
662
+ className
663
+ ),
664
+ ...props
665
+ }
666
+ ) }));
667
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
668
+ var ToolbarSurfaceContext = React10.createContext({
669
+ surface: "bar",
670
+ close: () => {
671
+ }
672
+ });
673
+ function useToolbarSurface() {
674
+ return React10.useContext(ToolbarSurfaceContext).surface;
675
+ }
676
+ function useToolbarPanelClose() {
677
+ return React10.useContext(ToolbarSurfaceContext).close;
678
+ }
679
+ var ToolbarButton = React10.forwardRef(function ToolbarButton2({ icon: Icon, caret = true, children, className, ...props }, ref) {
680
+ const panel = useToolbarSurface() === "panel";
681
+ if (panel) {
682
+ return /* @__PURE__ */ jsxs(
683
+ Button,
684
+ {
685
+ ref,
686
+ variant: "outline",
687
+ className: cn("h-10 w-full justify-between gap-2 px-3 font-normal", className),
688
+ ...props,
689
+ children: [
690
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [
691
+ Icon ? /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }) : null,
692
+ /* @__PURE__ */ jsx("span", { className: "truncate", children })
693
+ ] }),
694
+ caret ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 shrink-0 text-muted-foreground" }) : null
695
+ ]
696
+ }
697
+ );
698
+ }
414
699
  return /* @__PURE__ */ jsxs(
415
700
  Button,
416
701
  {
@@ -435,7 +720,23 @@ var ToolbarButton = React6.forwardRef(function ToolbarButton2({ icon: Icon, care
435
720
  }
436
721
  );
437
722
  });
438
- var ToolbarAction = React6.forwardRef(function ToolbarAction2({ icon: Icon, caret = false, children, className, ...props }, ref) {
723
+ var ToolbarAction = React10.forwardRef(function ToolbarAction2({ icon: Icon, caret = false, children, className, ...props }, ref) {
724
+ const panel = useToolbarSurface() === "panel";
725
+ if (panel) {
726
+ return /* @__PURE__ */ jsxs(
727
+ Button,
728
+ {
729
+ ref,
730
+ variant: "outline",
731
+ className: cn("h-10 w-full justify-center gap-2 px-3 font-normal", className),
732
+ ...props,
733
+ children: [
734
+ Icon ? /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }) : null,
735
+ /* @__PURE__ */ jsx("span", { className: "truncate", children })
736
+ ]
737
+ }
738
+ );
739
+ }
439
740
  return /* @__PURE__ */ jsxs(
440
741
  Button,
441
742
  {
@@ -511,13 +812,13 @@ function writeOffset(key, offset) {
511
812
  }
512
813
  function useToolbarOffset(storageKey, enabled) {
513
814
  const key = OFFSET_KEY(storageKey);
514
- const barRef = React6.useRef(null);
515
- const [offset, setOffset] = React6.useState(() => enabled ? readOffset(key) : { x: 0, y: 0 });
516
- const [dragging, setDragging] = React6.useState(false);
517
- const latest = React6.useRef(offset);
815
+ const barRef = React10.useRef(null);
816
+ const [offset, setOffset] = React10.useState(() => enabled ? readOffset(key) : { x: 0, y: 0 });
817
+ const [dragging, setDragging] = React10.useState(false);
818
+ const latest = React10.useRef(offset);
518
819
  latest.current = offset;
519
- const origin = React6.useRef(null);
520
- const clamp = React6.useCallback((next) => {
820
+ const origin = React10.useRef(null);
821
+ const clamp = React10.useCallback((next) => {
521
822
  const el = barRef.current;
522
823
  if (!el || typeof window === "undefined") return next;
523
824
  const rect = el.getBoundingClientRect();
@@ -534,7 +835,7 @@ function useToolbarOffset(storageKey, enabled) {
534
835
  )
535
836
  };
536
837
  }, []);
537
- const move = React6.useCallback((next, persist) => {
838
+ const move = React10.useCallback((next, persist) => {
538
839
  const clamped = clamp(next);
539
840
  setOffset(clamped);
540
841
  if (persist) writeOffset(key, clamped);
@@ -579,8 +880,8 @@ function useToolbarOffset(storageKey, enabled) {
579
880
  event.preventDefault();
580
881
  move({ x: latest.current.x + d.x, y: latest.current.y + d.y }, true);
581
882
  };
582
- const reset = React6.useCallback(() => move({ x: 0, y: 0 }, true), [move]);
583
- React6.useEffect(() => {
883
+ const reset = React10.useCallback(() => move({ x: 0, y: 0 }, true), [move]);
884
+ React10.useEffect(() => {
584
885
  if (!enabled) return;
585
886
  const onResize = () => move(latest.current, false);
586
887
  window.addEventListener("resize", onResize);
@@ -600,11 +901,94 @@ function PageToolbar({
600
901
  movable = true,
601
902
  storageKey = "shared",
602
903
  moveLabel,
904
+ filtersTitle,
603
905
  className
604
906
  }) {
605
907
  const floating = useIsWide();
606
908
  const { barRef, offset, dragging, reset, handlers } = useToolbarOffset(storageKey, movable && floating);
909
+ const actionsSlot = useModuleHeaderActionsSlot();
910
+ const moduleSlot = useModuleHeaderSlot();
911
+ const headerSlot = actionsSlot ?? moduleSlot;
912
+ const [openOnPhone, setOpenOnPhone] = React10.useState(false);
913
+ const scrim = useScrim(openOnPhone);
914
+ const panelSurface = React10.useMemo(
915
+ () => ({ surface: "panel", close: () => setOpenOnPhone(false) }),
916
+ []
917
+ );
607
918
  if (!range && !filters && !chips && !customize && !actions && !onRefresh) return null;
919
+ const controlsFor = ({ withChips, withRefresh = true }) => /* @__PURE__ */ jsxs(Fragment, { children: [
920
+ range,
921
+ filters,
922
+ withChips ? chips : null,
923
+ customize,
924
+ actions,
925
+ withRefresh && onRefresh ? /* @__PURE__ */ jsx(
926
+ Button,
927
+ {
928
+ variant: "ghost",
929
+ size: "sm",
930
+ onClick: onRefresh,
931
+ "aria-label": refreshLabel,
932
+ className: "w-[26px] shrink-0 border-0 bg-transparent p-0 text-muted-foreground shadow-none hover:bg-transparent hover:text-foreground",
933
+ children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-3 w-3" })
934
+ }
935
+ ) : null
936
+ ] });
937
+ if (!floating && headerSlot) {
938
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
939
+ scrim.mounted && typeof document !== "undefined" && createPortal(
940
+ // O MESMO escurecer do FAB (ver useScrim em page-actions): enquanto o
941
+ // painel está aberto ele é a única coisa a responder, e a página atrás
942
+ // continuava lendo como um lugar onde ainda dava para tocar.
943
+ /* @__PURE__ */ jsx(
944
+ "div",
945
+ {
946
+ "aria-hidden": true,
947
+ onClick: () => setOpenOnPhone(false),
948
+ className: cn(
949
+ "fixed inset-0 z-[100] bg-foreground/40 transition-opacity duration-200 md:hidden",
950
+ "motion-reduce:transition-none",
951
+ scrim.visible ? "opacity-100" : "opacity-0"
952
+ )
953
+ }
954
+ ),
955
+ document.body
956
+ ),
957
+ createPortal(
958
+ // `w-full justify-end`: o slot do header é um flex de largura livre,
959
+ // então `ml-auto` sozinho encostava o botão no TÍTULO, não na borda
960
+ // da tela. Esticar o contêiner é o que dá uma direita para encostar.
961
+ /* @__PURE__ */ jsxs("div", { className: "flex w-full min-w-0 items-center justify-end gap-1", children: [
962
+ chips ? /* @__PURE__ */ jsx("div", { className: "scrollbar-none flex min-w-0 items-center gap-1 overflow-x-auto", children: chips }) : null,
963
+ /* @__PURE__ */ jsxs(Popover, { open: openOnPhone, onOpenChange: setOpenOnPhone, children: [
964
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
965
+ Button,
966
+ {
967
+ variant: "ghost",
968
+ size: "sm",
969
+ "aria-label": openOnPhone ? "Fechar filtros" : filtersTitle ?? "Filtros",
970
+ className: cn(
971
+ "h-8 w-8 shrink-0 p-0 text-muted-foreground hover:text-foreground",
972
+ openOnPhone && "z-[105]"
973
+ ),
974
+ children: openOnPhone ? /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-4 w-4" })
975
+ }
976
+ ) }),
977
+ /* @__PURE__ */ jsx(
978
+ PopoverContent,
979
+ {
980
+ align: "end",
981
+ sideOffset: 8,
982
+ className: "z-[101] flex max-h-[70vh] w-[min(22rem,calc(100vw-1.5rem))] flex-col gap-3 overflow-y-auto p-3 md:hidden",
983
+ children: /* @__PURE__ */ jsx(ToolbarSurfaceContext.Provider, { value: panelSurface, children: controlsFor({ withChips: false, withRefresh: false }) })
984
+ }
985
+ )
986
+ ] })
987
+ ] }),
988
+ headerSlot
989
+ )
990
+ ] });
991
+ }
608
992
  return (
609
993
  // Caixa de altura ZERO: a barra flutua sobre os cartões em vez de abrir uma
610
994
  // linha só para ela. Ocupando espaço, ela empurrava a grade inteira para
@@ -618,6 +1002,7 @@ function PageToolbar({
618
1002
  /* @__PURE__ */ jsx(
619
1003
  "div",
620
1004
  {
1005
+ "data-print": "hide",
621
1006
  className: cn(
622
1007
  "z-20 flex",
623
1008
  // `items-start` não é enfeite: num flex de altura 0, o alinhamento
@@ -654,22 +1039,7 @@ function PageToolbar({
654
1039
  children: /* @__PURE__ */ jsx(GripVertical, { className: "h-3.5 w-3.5" })
655
1040
  }
656
1041
  ) : null,
657
- range,
658
- filters,
659
- chips,
660
- customize,
661
- actions,
662
- onRefresh ? /* @__PURE__ */ jsx(
663
- Button,
664
- {
665
- variant: "ghost",
666
- size: "sm",
667
- onClick: onRefresh,
668
- "aria-label": refreshLabel,
669
- className: "w-[26px] border-0 bg-transparent p-0 text-muted-foreground shadow-none hover:bg-transparent hover:text-foreground",
670
- children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-3 w-3" })
671
- }
672
- ) : null
1042
+ controlsFor({ withChips: true })
673
1043
  ]
674
1044
  }
675
1045
  )
@@ -678,6 +1048,6 @@ function PageToolbar({
678
1048
  );
679
1049
  }
680
1050
 
681
- export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, DataTable, Dropdown, DropdownCheckboxItem, DropdownContent, DropdownGroup, DropdownItem, DropdownLabel, DropdownPortal, DropdownRadioGroup, DropdownRadioItem, DropdownSeparator, DropdownShortcut, DropdownSub, DropdownSubContent, DropdownSubTrigger, DropdownTrigger, PageToolbar, RangeControl, Skeleton, TableSkeleton, ToolbarAction, ToolbarButton, WIDE_QUERY, useIsWide };
682
- //# sourceMappingURL=chunk-E44WOPCR.js.map
683
- //# sourceMappingURL=chunk-E44WOPCR.js.map
1051
+ export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, DataTable, Dropdown, DropdownCheckboxItem, DropdownContent, DropdownGroup, DropdownItem, DropdownLabel, DropdownPortal, DropdownRadioGroup, DropdownRadioItem, DropdownSeparator, DropdownShortcut, DropdownSub, DropdownSubContent, DropdownSubTrigger, DropdownTrigger, Hint, PageActionBar, PageToolbar, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, RangeControl, Skeleton, TableSkeleton, ToolbarAction, ToolbarButton, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, WIDE_QUERY, setActionsMenuLabel, useIsWide, useToolbarPanelClose, useToolbarSurface };
1052
+ //# sourceMappingURL=chunk-HO2P2XB4.js.map
1053
+ //# sourceMappingURL=chunk-HO2P2XB4.js.map