@fayz-ai/ui 0.15.0 → 0.16.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 (65) hide show
  1. package/dist/analytics/context.d.ts +15 -1
  2. package/dist/analytics/context.d.ts.map +1 -1
  3. package/dist/analytics/index.d.ts +1 -1
  4. package/dist/analytics/index.d.ts.map +1 -1
  5. package/dist/{chunk-5KMAEQA3.js → chunk-5VF45NLE.js} +4 -4
  6. package/dist/{chunk-5KMAEQA3.js.map → chunk-5VF45NLE.js.map} +1 -1
  7. package/dist/{chunk-J7F3Z52K.js → chunk-6BJTH3L6.js} +4 -4
  8. package/dist/chunk-6BJTH3L6.js.map +1 -0
  9. package/dist/{chunk-KD2V3TAX.js → chunk-E44WOPCR.js} +61 -49
  10. package/dist/chunk-E44WOPCR.js.map +1 -0
  11. package/dist/{chunk-FFJ2C5YH.js → chunk-HKGTF2YA.js} +41 -16
  12. package/dist/chunk-HKGTF2YA.js.map +1 -0
  13. package/dist/{chunk-NA3GE4H3.js → chunk-PZU7XC2M.js} +362 -252
  14. package/dist/chunk-PZU7XC2M.js.map +1 -0
  15. package/dist/{chunk-SLWTKHNY.js → chunk-SDPYDWWV.js} +371 -83
  16. package/dist/chunk-SDPYDWWV.js.map +1 -0
  17. package/dist/dashboard/index.js +3 -3
  18. package/dist/hooks/useIsWide.d.ts +16 -0
  19. package/dist/hooks/useIsWide.d.ts.map +1 -0
  20. package/dist/index.d.ts +4 -3
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +30 -10
  23. package/dist/index.js.map +1 -1
  24. package/dist/layout/AppShell.d.ts +25 -2
  25. package/dist/layout/AppShell.d.ts.map +1 -1
  26. package/dist/layout/ModulePage.d.ts +4 -0
  27. package/dist/layout/ModulePage.d.ts.map +1 -1
  28. package/dist/layout/SaveBar.d.ts.map +1 -1
  29. package/dist/layout/Sidebar.d.ts.map +1 -1
  30. package/dist/layout/Topbar.d.ts +5 -1
  31. package/dist/layout/Topbar.d.ts.map +1 -1
  32. package/dist/layout/index.d.ts +1 -1
  33. package/dist/layout/index.d.ts.map +1 -1
  34. package/dist/layout/index.js +3 -3
  35. package/dist/primitives/checkbox.d.ts +4 -0
  36. package/dist/primitives/checkbox.d.ts.map +1 -1
  37. package/dist/primitives/index.d.ts +3 -0
  38. package/dist/primitives/index.d.ts.map +1 -1
  39. package/dist/primitives/index.js +4 -4
  40. package/dist/primitives/list-view.d.ts +5 -1
  41. package/dist/primitives/list-view.d.ts.map +1 -1
  42. package/dist/primitives/modal.d.ts.map +1 -1
  43. package/dist/primitives/page-actions.d.ts +55 -0
  44. package/dist/primitives/page-actions.d.ts.map +1 -0
  45. package/dist/primitives/page-header.d.ts +5 -2
  46. package/dist/primitives/page-header.d.ts.map +1 -1
  47. package/dist/primitives/page-toolbar.d.ts.map +1 -1
  48. package/dist/primitives/refresh-button.d.ts.map +1 -1
  49. package/dist/primitives/row-actions.d.ts +11 -0
  50. package/dist/primitives/row-actions.d.ts.map +1 -0
  51. package/dist/primitives/whatsapp-icon.d.ts +7 -0
  52. package/dist/primitives/whatsapp-icon.d.ts.map +1 -0
  53. package/dist/stores/index.d.ts +1 -1
  54. package/dist/stores/index.d.ts.map +1 -1
  55. package/dist/stores/layout.store.d.ts +1 -0
  56. package/dist/stores/layout.store.d.ts.map +1 -1
  57. package/dist/stores/page-header.store.d.ts +39 -5
  58. package/dist/stores/page-header.store.d.ts.map +1 -1
  59. package/dist/styles.css +166 -3
  60. package/package.json +2 -2
  61. package/dist/chunk-FFJ2C5YH.js.map +0 -1
  62. package/dist/chunk-J7F3Z52K.js.map +0 -1
  63. package/dist/chunk-KD2V3TAX.js.map +0 -1
  64. package/dist/chunk-NA3GE4H3.js.map +0 -1
  65. package/dist/chunk-SLWTKHNY.js.map +0 -1
package/dist/styles.css CHANGED
@@ -618,12 +618,33 @@ select.bg-card,
618
618
  to { opacity: 0; transform: translateX(-100%); }
619
619
  }
620
620
 
621
- /* Command palette animation */
621
+ /* Command palette animation.
622
+ The desktop card is centred with translateX(-50%), so its keyframes have to
623
+ carry that translate or the animation snaps it back to the left edge. On a
624
+ phone the palette is full-bleed and centres nothing — the same keyframes
625
+ dragged it half a screen off. Two animations, split at the same breakpoint
626
+ the layout is. */
622
627
  .saas-cmd-palette[data-state="open"] {
623
- animation: saas-cmd-in 200ms ease-out both;
628
+ animation: saas-cmd-in-sheet 200ms ease-out both;
624
629
  }
625
630
  .saas-cmd-palette[data-state="closed"] {
626
- animation: saas-cmd-out 150ms ease-in both;
631
+ animation: saas-cmd-out-sheet 150ms ease-in both;
632
+ }
633
+ @keyframes saas-cmd-in-sheet {
634
+ from { opacity: 0; transform: translateY(8px); }
635
+ to { opacity: 1; transform: translateY(0); }
636
+ }
637
+ @keyframes saas-cmd-out-sheet {
638
+ from { opacity: 1; transform: translateY(0); }
639
+ to { opacity: 0; transform: translateY(8px); }
640
+ }
641
+ @media (min-width: 640px) {
642
+ .saas-cmd-palette[data-state="open"] {
643
+ animation: saas-cmd-in 200ms ease-out both;
644
+ }
645
+ .saas-cmd-palette[data-state="closed"] {
646
+ animation: saas-cmd-out 150ms ease-in both;
647
+ }
627
648
  }
628
649
  @keyframes saas-cmd-in {
629
650
  from { opacity: 0; transform: translateX(-50%) scale(0.96) translateY(-8px); }
@@ -766,6 +787,18 @@ select.bg-card,
766
787
  /* A field that spans the row it is on, whatever the column count is. */
767
788
  .fz-field-wide { grid-column: 1 / -1; }
768
789
 
790
+ /* A required field that was empty when somebody pressed save.
791
+ *
792
+ * One rule here rather than a Tailwind string at each of the six form layouts —
793
+ * the marker travels with the field, and a layout added tomorrow gets it free.
794
+ * The ring is on the CONTROL, not the wrapper, so the label and the message
795
+ * either side of it stay legible. */
796
+ .fz-field-invalid :is(input, textarea, select, [role='combobox'], [contenteditable='true']) {
797
+ border-color: hsl(var(--destructive));
798
+ box-shadow: 0 0 0 1px hsl(var(--destructive) / 0.35);
799
+ }
800
+ .fz-field-invalid > label { color: hsl(var(--destructive)); }
801
+
769
802
  /* Rows separated by a rule while they are stacked; side by side the rule is
770
803
  drawn between unrelated neighbours, so it goes. */
771
804
  @container (min-width: 30rem) {
@@ -813,3 +846,133 @@ select.bg-card,
813
846
  @media (pointer: coarse) {
814
847
  .fz-tap { min-height: 2.75rem; min-width: 2.75rem; }
815
848
  }
849
+
850
+ /* ---------------------------------------------------------------------------
851
+ Mobile platform baseline
852
+ The shell renders inside Safari and Chrome on a phone, not just inside a
853
+ desktop viewport that happens to be narrow. These rules cover the platform
854
+ behaviours the browser applies on its own unless told otherwise.
855
+ --------------------------------------------------------------------------- */
856
+
857
+ /* Double-tap-to-zoom costs every tap a 300ms wait while the browser decides
858
+ whether a second tap is coming. `manipulation` opts out of that gesture and
859
+ keeps pinch-to-zoom, which is an accessibility guarantee we do not take away. */
860
+ html {
861
+ touch-action: manipulation;
862
+ }
863
+
864
+ /* iOS zooms the whole page when a field smaller than 16px takes focus, and
865
+ never zooms back. Anything a finger can focus gets 16px, on touch INPUT
866
+ rather than screen width — an iPad zooms exactly like a phone. Fields that
867
+ are deliberately larger keep their size. */
868
+ @media (pointer: coarse) {
869
+ input:not([type='checkbox'], [type='radio']),
870
+ textarea:not([hidden]),
871
+ select:not([hidden]) {
872
+ font-size: max(16px, 1em);
873
+ }
874
+ }
875
+
876
+ /* WebKit paints a grey flash over any tapped element. Suppress it and let the
877
+ component's own :active state be the feedback, so a tap never looks like it
878
+ selected a block of the page. */
879
+ * {
880
+ -webkit-tap-highlight-color: transparent;
881
+ }
882
+
883
+ /* A scroller that reaches its end hands the gesture to the page behind it —
884
+ which on mobile means a drawer, sheet or chat transcript can rubber-band the
885
+ whole app or trigger pull-to-refresh mid-scroll. */
886
+ .fz-scroll-contain {
887
+ overscroll-behavior: contain;
888
+ -webkit-overflow-scrolling: touch;
889
+ }
890
+
891
+ /* The notch, the Dynamic Island and the home indicator all sit inside the
892
+ viewport once `viewport-fit=cover` is set. Fixed chrome has to pad itself out
893
+ of them; env() resolves to 0 everywhere else, so these are safe on desktop. */
894
+ .fz-safe-b { padding-bottom: env(safe-area-inset-bottom); }
895
+ .fz-safe-t { padding-top: env(safe-area-inset-top); }
896
+ .fz-safe-x {
897
+ padding-left: env(safe-area-inset-left);
898
+ padding-right: env(safe-area-inset-right);
899
+ }
900
+
901
+ /* `100vh` on mobile means the viewport with the browser chrome hidden, which is
902
+ taller than what the user can actually see — the bottom of a vh-sized shell
903
+ sits under the address bar. `dvh` tracks the visible height instead; the vh
904
+ line stays as the fallback for browsers without it. */
905
+ .fz-viewport-h {
906
+ height: 100vh;
907
+ height: 100dvh;
908
+ }
909
+
910
+ /* How much of the bottom of the screen the tab bar owns. Anything that floats
911
+ above the fold — the save bar, toasts, a sheet handle — offsets by this
912
+ instead of hardcoding the bar's height, so it still sits right on a layout
913
+ that has no bar. Zero unless the shell says otherwise. */
914
+ :root { --fz-bottom-bar: 0px; }
915
+ @media (max-width: 767px) {
916
+ .fz-has-bottom-bar { --fz-bottom-bar: calc(4rem + env(safe-area-inset-bottom)); }
917
+ }
918
+
919
+ /* ---------------------------------------------------------------------------
920
+ Stacking order
921
+ Transient surfaces have to clear the shell's own fixed chrome. The mobile
922
+ navigation drawer sits at 60, so a menu at the Tailwind default of 50 opens
923
+ BEHIND it and reads as a dead control — which is exactly what happened to the
924
+ tenant switcher, the user menu and notifications inside the drawer.
925
+
926
+ 50 bottom tab bar
927
+ 55 save bar (above the tab bar, below anything modal)
928
+ 60 nav drawer, right rail
929
+ 100 modal, sheet (covers the drawer that opened it)
930
+ 110 dropdown, select, popover
931
+ 120 tooltip (above a modal it is anchored inside)
932
+ --------------------------------------------------------------------------- */
933
+
934
+ /* ---------------------------------------------------------------------------
935
+ FAB speed-dial
936
+ A menu opening from a thumb-corner button wants to look like it came OUT of
937
+ that button. The shared dropdown enter (fade + 2px slide) is right for a menu
938
+ anchored to a toolbar and reads as instant from a 56px circle in the corner.
939
+ --------------------------------------------------------------------------- */
940
+
941
+ .fz-fab-menu[data-state='open'] {
942
+ animation: fz-fab-menu-in 220ms cubic-bezier(0.16, 1, 0.3, 1) both;
943
+ transform-origin: bottom right;
944
+ }
945
+ .fz-fab-menu[data-state='closed'] {
946
+ animation: fz-fab-menu-out 130ms ease-in both;
947
+ transform-origin: bottom right;
948
+ }
949
+ @keyframes fz-fab-menu-in {
950
+ from { opacity: 0; transform: translateY(12px) scale(0.92); }
951
+ to { opacity: 1; transform: translateY(0) scale(1); }
952
+ }
953
+ @keyframes fz-fab-menu-out {
954
+ from { opacity: 1; transform: translateY(0) scale(1); }
955
+ to { opacity: 0; transform: translateY(8px) scale(0.96); }
956
+ }
957
+
958
+ /* Items arrive in the order they are read, just behind the panel. */
959
+ .fz-fab-menu[data-state='open'] .fz-fab-item {
960
+ animation: fz-fab-item-in 200ms ease-out both;
961
+ animation-delay: calc(60ms + var(--i, 0) * 40ms);
962
+ }
963
+ @keyframes fz-fab-item-in {
964
+ from { opacity: 0; transform: translateY(6px); }
965
+ to { opacity: 1; transform: translateY(0); }
966
+ }
967
+
968
+ /* The "+" becomes an "×" while the menu is open — the button says what tapping
969
+ it again will do. */
970
+ .fz-fab-trigger svg { transition: transform 220ms cubic-bezier(0.16, 1, 0.3, 1); }
971
+ .fz-fab-trigger[data-state='open'] svg { transform: rotate(135deg); }
972
+
973
+ @media (prefers-reduced-motion: reduce) {
974
+ .fz-fab-menu[data-state='open'],
975
+ .fz-fab-menu[data-state='closed'],
976
+ .fz-fab-menu[data-state='open'] .fz-fab-item { animation: none; }
977
+ .fz-fab-trigger svg { transition: none; }
978
+ }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "fayz": {
4
4
  "status": "beta"
5
5
  },
6
- "version": "0.15.0",
6
+ "version": "0.16.0",
7
7
  "description": "Fayz SDK UI — Radix + Tailwind component library with CRUD engine and layout shells",
8
8
  "type": "module",
9
9
  "sideEffects": [
@@ -79,7 +79,7 @@
79
79
  "clsx": "^2.1.0",
80
80
  "recharts": "^2.15.0",
81
81
  "tailwind-merge": "^2.4.0",
82
- "@fayz-ai/core": "^0.15.0"
82
+ "@fayz-ai/core": "^0.16.0"
83
83
  },
84
84
  "devDependencies": {
85
85
  "@types/react": "^18.3.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/stores/page-header.store.ts","../src/stores/layout.store.ts"],"names":["create"],"mappings":"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","file":"chunk-FFJ2C5YH.js","sourcesContent":["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 /** The claimed header carries a back action, i.e. what the bar is showing is\n * a SUBPAGE (\"← Contas a Pagar / Nova\"), not the module's own screen. The\n * module's tab band reads this to step aside: a form reached from a tab is\n * not one of the tabs, and leaving the strip up marks a place the user is no\n * longer at, one line under a back link that says so. */\n hasBack: boolean\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 /**\n * Quantos blocos de ações de página estão montados agora. A barra precisa\n * saber ANTES de decidir se existe: ela some no celular de alguns produtos, e\n * um \"Novo\" entregue a uma barra escondida simplesmente não aparecia.\n */\n actions: number\n claim: (owner: string, node: React.ReactNode, hasBack?: boolean) => void\n release: (owner: string) => void\n addHost: () => void\n removeHost: () => void\n addOutlet: () => void\n removeOutlet: () => void\n addActions: () => void\n removeActions: () => void\n}\n\nconst usePageHeaderStore = create<PageHeaderState>((set, get) => ({\n slot: null,\n owner: null,\n hasBack: false,\n hosts: 0,\n outlets: 0,\n actions: 0,\n claim: (owner, node, hasBack = false) => set({ owner, slot: node, hasBack }),\n release: (owner) => {\n if (get().owner === owner) set({ owner: null, slot: null, hasBack: false })\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 addActions: () => set((s) => ({ actions: s.actions + 1 })),\n removeActions: () => set((s) => ({ actions: Math.max(0, s.actions - 1) })),\n}))\n\n/** Declara que esta página tem ações no topo. Chamado por PageHeaderActions. */\nexport function useRegisterPageActions(): void {\n const add = usePageHeaderStore((s) => s.addActions)\n const remove = usePageHeaderStore((s) => s.removeActions)\n React.useEffect(() => {\n add()\n return remove\n }, [add, remove])\n}\n\n/** Se alguma página tem ações no topo agora. A barra usa para não sumir com\n * elas no celular, e para não existir vazia. */\nexport function useHasPageActions(): boolean {\n return usePageHeaderStore((s) => s.actions > 0)\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, options?: { back?: boolean }): void {\n const id = React.useId()\n const claim = usePageHeaderStore((s) => s.claim)\n const release = usePageHeaderStore((s) => s.release)\n const back = options?.back ?? false\n\n React.useEffect(() => {\n if (node == null) {\n release(id)\n return\n }\n claim(id, node, back)\n return () => release(id)\n }, [id, node, back, claim, release])\n}\n\n/** True while the bar is showing a subpage's \"← parent / title\". See\n * `PageHeaderState.hasBack`. */\nexport function useHasPageHeaderBack(): boolean {\n return usePageHeaderStore((s) => s.hasBack)\n}\n\nexport { usePageHeaderStore }\n","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"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/layout/AppShellSkeleton.tsx","../src/layout/page-trail.tsx","../src/layout/ContentSplit.tsx"],"names":["jsx","React2","jsxs"],"mappings":"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","file":"chunk-J7F3Z52K.js","sourcesContent":["import * as React from 'react'\nimport { cn } from '../lib/cn'\n\n// ---------------------------------------------------------------------------\n// AppShellSkeleton — what the admin shows while it is still booting (session\n// restore, plugin runtime, first paint).\n//\n// It used to draw the SHAPE of the shell: rail, header band, tiles, table. The\n// idea was that the app would resolve into its own outline. What it did in\n// practice was promise a specific screen and then contradict it — the outline\n// is a dashboard, and half the time you were opening something else — and the\n// pulsing bars read as content that failed to load rather than content on its\n// way. Worse, it made the wait look LONGER: a page of fake rows holds the eye,\n// so every extra frame of it registers.\n//\n// One spinner on the rail's own color says exactly as much (the app is coming)\n// and nothing false. It also matches the HTML boot screen the Vite plugin\n// injects (see @fayz-ai/sdk boot-skeleton), so the whole cold load is one\n// continuous image — same background, same spinner, in the same place — from\n// first paint to mounted app, with nothing swapping underneath.\n// ---------------------------------------------------------------------------\n\nexport interface AppShellSkeletonProps {\n /** Kept for API compatibility. The boot screen no longer draws a shell shape,\n * so every layout gets the same one. */\n variant?: 'sidebar' | 'topbar' | 'minimal'\n /** Kept for API compatibility; the boot screen has no content frame. */\n contentFrame?: boolean\n /** Kept for API compatibility; the boot screen shows no logo. */\n logo?: React.ReactNode\n /** What is loading, for screen readers. */\n label: string\n className?: string\n}\n\n/** Ring spinner in the page's foreground tone. Static under reduced motion —\n * the ring alone still reads as \"busy\", a frozen spinner reads as \"stuck\". */\nexport function BootSpinner({ className }: { className?: string }) {\n return (\n <span\n aria-hidden\n className={cn(\n 'block h-7 w-7 animate-spin rounded-full border-2 border-foreground/20 border-t-foreground/70',\n 'motion-reduce:animate-none motion-reduce:border-t-foreground/20 motion-reduce:animate-pulse',\n className,\n )}\n />\n )\n}\n\nexport function AppShellSkeleton({ label, className }: AppShellSkeletonProps) {\n return (\n <div\n role=\"status\"\n aria-busy=\"true\"\n className={cn('flex h-screen items-center justify-center overflow-hidden bg-background', className)}\n >\n <span className=\"sr-only\">{label}</span>\n <BootSpinner />\n </div>\n )\n}\nAppShellSkeleton.displayName = 'AppShellSkeleton'\n","import * as React from 'react'\n\n// ---------------------------------------------------------------------------\n// PageTrail — quem é o PAI da tela que está desenhando agora.\n//\n// Uma migalha (\"← Entrega / Embalagens\") precisa de duas coisas que moram em\n// lugares diferentes: o nome do nível de cima, que só o container sabe, e o\n// nome do nível atual, que só a folha sabe. Sem um caminho entre os dois cada\n// container desenhava a própria seta \"para não perder o caminho de volta\" — e\n// foi assim que Configurações ficou com dois cabeçalhos empilhados: um da\n// barra da shell (\"Configurações\") e um escrito à mão dentro do plugin\n// (\"← Entrega\"), desalinhados, para uma coisa só.\n//\n// Aqui o container apenas DECLARA o nível dele. Quem desenha é sempre a folha,\n// uma vez só, pelo mesmo PageHeader que o resto do app usa — uma seta na tela,\n// nunca duas.\n// ---------------------------------------------------------------------------\n\nexport interface PageTrailCrumb {\n /** Nome do nível — a palavra antes da barra para quem vem abaixo. */\n label: string\n /** Rota (hash) deste nível. É também a IDENTIDADE dele: uma tela cuja rota é\n * igual à do nível não é filha dele, é ele — sem isso a lista de Locais,\n * que É a aba, viraria \"← Locais / Locais\". */\n href: string\n /** Como voltar. Sem isso, a própria rota. */\n onNavigate?: () => void\n}\n\nconst EMPTY: PageTrailCrumb[] = []\nconst PageTrailContext = React.createContext<PageTrailCrumb[]>(EMPTY)\n\n/** Declara um nível para tudo que renderizar abaixo. */\nexport function PageTrail({\n label,\n href,\n onNavigate,\n children,\n}: PageTrailCrumb & { children: React.ReactNode }) {\n const parent = React.useContext(PageTrailContext)\n // Identidade estável: a folha memoiza o nó do cabeçalho a partir daqui, e um\n // array novo a cada render faria a reivindicação da barra recomeçar sem fim.\n const trail = React.useMemo(\n () => [...parent, { label, href, onNavigate }],\n [parent, label, href, onNavigate],\n )\n return <PageTrailContext.Provider value={trail}>{children}</PageTrailContext.Provider>\n}\n\nexport function usePageTrail(): PageTrailCrumb[] {\n return React.useContext(PageTrailContext)\n}\n\n/**\n * O nível imediatamente acima de `href`, ou undefined quando não há trilha —\n * fora de Configurações a página segue sem migalha, como sempre foi.\n */\nexport function usePageTrailParent(href?: string): PageTrailCrumb | undefined {\n const trail = React.useContext(PageTrailContext)\n return React.useMemo(() => {\n const above = href ? trail.filter((c) => c.href !== href) : trail\n return above[above.length - 1]\n }, [trail, href])\n}\n\nexport function navigateToCrumb(crumb: PageTrailCrumb): void {\n if (crumb.onNavigate) crumb.onNavigate()\n else window.location.hash = crumb.href\n}\n","import * as React from 'react'\nimport { PanelRight, PanelRightClose, PanelRightOpen } from 'lucide-react'\nimport { cn } from '../lib/cn'\nimport { Button } from '../primitives/button'\nimport {\n Sheet, SheetContent, SheetHeader, SheetBody, SheetTitle, SheetDescription,\n} from '../primitives/sheet'\n\n// ---------------------------------------------------------------------------\n// ContentSplit — main content with a right-aligned companion panel, mobile\n// first. Below `lg` the aside lives in a right Sheet (opened by a trigger the\n// host places wherever fits — typically SubpageHeader actions, via\n// <ContentSplitTrigger/>). From `lg` up it docks as a sticky right column.\n//\n// Pairs with SubpageHeader/ModulePage: the page keeps its own back-button\n// header; ContentSplit only owns the columns below it. Reuse for any\n// \"document + operational panel\" page (script + shooting checklist, form +\n// help, detail + activity feed).\n// ---------------------------------------------------------------------------\n\ninterface ContentSplitContextValue {\n open: boolean\n setOpen: (open: boolean) => void\n}\n\nconst ContentSplitContext = React.createContext<ContentSplitContextValue | null>(null)\n\nexport interface ContentSplitProps {\n /** Main column (the document). */\n children: React.ReactNode\n /** Companion panel content (the checklist / help / activity). */\n aside: React.ReactNode\n /** Panel title — Sheet header on mobile, card header on desktop. */\n asideTitle: React.ReactNode\n /** Optional subtitle under the title. */\n asideDescription?: React.ReactNode\n /** Desktop column width (defaults to 20rem). */\n asideWidth?: string\n /** Controlled mobile-sheet state; uncontrolled when omitted. */\n asideOpen?: boolean\n onAsideOpenChange?: (open: boolean) => void\n /** Desktop column can collapse into a slim reopen rail. */\n collapsible?: boolean\n /** Initial desktop collapsed state (e.g. expand only on the relevant day). */\n defaultCollapsed?: boolean\n className?: string\n}\n\nexport function ContentSplit({\n children,\n aside,\n asideTitle,\n asideDescription,\n asideWidth = '20rem',\n asideOpen,\n onAsideOpenChange,\n collapsible = false,\n defaultCollapsed = false,\n className,\n}: ContentSplitProps) {\n const [internalOpen, setInternalOpen] = React.useState(false)\n const open = asideOpen ?? internalOpen\n const setOpen = onAsideOpenChange ?? setInternalOpen\n const [collapsed, setCollapsed] = React.useState(collapsible && defaultCollapsed)\n\n return (\n <ContentSplitContext.Provider value={{ open, setOpen }}>\n <div\n className={cn('lg:grid lg:items-start lg:gap-6', className)}\n style={{ gridTemplateColumns: `minmax(0, 1fr) ${collapsed ? 'auto' : asideWidth}` }}\n >\n <div className=\"min-w-0\">{children}</div>\n\n {/* Desktop: docked sticky column (or slim reopen rail when collapsed) */}\n <aside className=\"hidden lg:block lg:sticky lg:top-4\">\n {collapsed ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setCollapsed(false)}\n className=\"h-9 w-9 p-0\"\n aria-label={typeof asideTitle === 'string' ? asideTitle : undefined}\n title={typeof asideTitle === 'string' ? asideTitle : undefined}\n >\n <PanelRightOpen className=\"h-4 w-4\" />\n </Button>\n ) : (\n <div className=\"rounded-card border border-border bg-card\">\n <div className=\"flex items-start justify-between gap-2 border-b border-border px-4 py-3\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-semibold text-foreground\">{asideTitle}</p>\n {asideDescription && (\n <p className=\"mt-0.5 text-xs text-muted-foreground\">{asideDescription}</p>\n )}\n </div>\n {collapsible && (\n <button\n type=\"button\"\n onClick={() => setCollapsed(true)}\n className=\"rounded p-1 text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground\"\n aria-label=\"collapse\"\n >\n <PanelRightClose className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n <div className=\"p-4\">{aside}</div>\n </div>\n )}\n </aside>\n </div>\n\n {/* Mobile: right sheet */}\n <div className=\"lg:hidden\">\n <Sheet open={open} onOpenChange={setOpen}>\n <SheetContent width=\"max-w-sm\">\n <SheetHeader>\n <SheetTitle>{asideTitle}</SheetTitle>\n {asideDescription && <SheetDescription>{asideDescription}</SheetDescription>}\n </SheetHeader>\n <SheetBody>{aside}</SheetBody>\n </SheetContent>\n </Sheet>\n </div>\n </ContentSplitContext.Provider>\n )\n}\n\nexport interface ContentSplitTriggerProps {\n /** Accessible label; also the visible text unless `iconOnly`. */\n label: React.ReactNode\n iconOnly?: boolean\n className?: string\n}\n\n/** Opens the mobile aside sheet. Renders nothing from `lg` up (the panel is\n * already docked). Place inside SubpageHeader `actions` or any toolbar. */\nexport function ContentSplitTrigger({ label, iconOnly, className }: ContentSplitTriggerProps) {\n const ctx = React.useContext(ContentSplitContext)\n if (!ctx) return null\n return (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => ctx.setOpen(true)}\n className={cn('lg:hidden', className)}\n aria-label={typeof label === 'string' ? label : undefined}\n >\n <PanelRight className={cn('h-4 w-4', !iconOnly && 'mr-1.5')} />\n {!iconOnly && label}\n </Button>\n )\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/primitives/card.tsx","../src/primitives/dropdown.tsx","../src/primitives/checkbox.tsx","../src/primitives/data-table.tsx","../src/primitives/skeleton.tsx","../src/primitives/page-toolbar.tsx"],"names":["React","React2","jsx","React3","Check","React4","jsxs","_","ToolbarButton","ToolbarAction"],"mappings":"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","file":"chunk-KD2V3TAX.js","sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../lib/cn'\n\nconst Card = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'fayz-glass-surface rounded-card border bg-card text-card-foreground shadow-sm',\n className\n )}\n {...props}\n />\n))\nCard.displayName = 'Card'\n\nconst CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex flex-col space-y-1 p-4', className)}\n {...props}\n />\n))\nCardHeader.displayName = 'CardHeader'\n\nconst CardTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h3\n ref={ref}\n className={cn(\n 'text-sm font-semibold leading-tight tracking-tight',\n className\n )}\n {...props}\n />\n))\nCardTitle.displayName = 'CardTitle'\n\nconst CardDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('text-xs text-muted-foreground', className)}\n {...props}\n />\n))\nCardDescription.displayName = 'CardDescription'\n\nconst CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div ref={ref} className={cn('p-4 pt-0', className)} {...props} />\n))\nCardContent.displayName = 'CardContent'\n\nconst CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex items-center p-4 pt-0', className)}\n {...props}\n />\n))\nCardFooter.displayName = 'CardFooter'\n\nexport { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }\n","import * as React from 'react'\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'\nimport { Check, ChevronRight, Circle } from 'lucide-react'\n\nimport { cn } from '../lib/cn'\n\nconst Dropdown = DropdownMenuPrimitive.Root\n\nconst DropdownTrigger = DropdownMenuPrimitive.Trigger\n\nconst DropdownGroup = DropdownMenuPrimitive.Group\n\nconst DropdownPortal = DropdownMenuPrimitive.Portal\n\nconst DropdownSub = DropdownMenuPrimitive.Sub\n\nconst DropdownRadioGroup = DropdownMenuPrimitive.RadioGroup\n\nconst DropdownSubTrigger = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean\n }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n 'flex cursor-default select-none items-center rounded-button px-2 py-1.5 text-sm outline-none focus:bg-muted data-[state=open]:bg-muted',\n inset && 'pl-8',\n className\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto h-4 w-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n))\nDropdownSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName\n\nconst DropdownSubContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n // Portaled, like DropdownContent. Without it the submenu renders inside the\n // parent panel's DOM — and that panel is `overflow-hidden`, so the submenu\n // was clipped to its box: a flyout you could open and never reach.\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n 'fayz-glass-surface z-50 min-w-[8rem] overflow-hidden rounded-card border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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',\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n))\nDropdownSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName\n\nconst DropdownContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'fayz-glass-surface z-50 min-w-[8rem] overflow-hidden rounded-card border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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',\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n))\nDropdownContent.displayName = DropdownMenuPrimitive.Content.displayName\n\nconst DropdownItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex cursor-default select-none items-center rounded-button px-2 py-1.5 text-sm outline-none transition-colors focus:bg-muted data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n inset && 'pl-8',\n className\n )}\n {...props}\n />\n))\nDropdownItem.displayName = DropdownMenuPrimitive.Item.displayName\n\nconst DropdownCheckboxItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n 'relative flex cursor-default select-none items-center rounded-button py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-muted data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n))\nDropdownCheckboxItem.displayName =\n DropdownMenuPrimitive.CheckboxItem.displayName\n\nconst DropdownRadioItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n 'relative flex cursor-default select-none items-center rounded-button py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-muted data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n className\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n))\nDropdownRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName\n\nconst DropdownLabel = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n 'px-2 py-1.5 text-sm font-semibold',\n inset && 'pl-8',\n className\n )}\n {...props}\n />\n))\nDropdownLabel.displayName = DropdownMenuPrimitive.Label.displayName\n\nconst DropdownSeparator = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn('-mx-1 my-1 h-px bg-muted', className)}\n {...props}\n />\n))\nDropdownSeparator.displayName = DropdownMenuPrimitive.Separator.displayName\n\nconst DropdownShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn('ml-auto text-xs tracking-widest opacity-60', className)}\n {...props}\n />\n )\n}\nDropdownShortcut.displayName = 'DropdownShortcut'\n\nexport {\n Dropdown,\n DropdownTrigger,\n DropdownContent,\n DropdownItem,\n DropdownCheckboxItem,\n DropdownRadioItem,\n DropdownLabel,\n DropdownSeparator,\n DropdownShortcut,\n DropdownGroup,\n DropdownPortal,\n DropdownSub,\n DropdownSubContent,\n DropdownSubTrigger,\n DropdownRadioGroup,\n}\n","import * as React from 'react'\nimport { Check, Minus } from 'lucide-react'\nimport { cn } from '../lib/cn'\n\ntype CheckboxColor = 'primary' | 'success' | 'warning' | 'destructive'\n\ninterface CheckboxProps {\n checked?: boolean\n onChange?: (checked: boolean) => void\n disabled?: boolean\n className?: string\n color?: CheckboxColor\n id?: string\n /** Some but not all of what this box stands for is checked (a table header\n * over a partly selected page). Painted filled with a dash, and announced as\n * \"mixed\" — an empty box would claim nothing is selected. */\n indeterminate?: boolean\n 'aria-label'?: string\n}\n\nconst COLOR_CLASSES: Record<CheckboxColor, string> = {\n primary: 'border-primary bg-primary text-primary-foreground',\n success: 'border-success bg-success text-white dark:border-success dark:bg-success',\n warning: 'border-warning bg-warning text-white',\n destructive: 'border-destructive bg-destructive text-destructive-foreground',\n}\n\nconst Checkbox = React.forwardRef<HTMLButtonElement, CheckboxProps>(\n ({ checked = false, onChange, disabled, className, color = 'primary', id, indeterminate = false, ...props }, ref) => {\n const filled = checked || indeterminate\n return (\n <button\n ref={ref}\n id={id}\n type=\"button\"\n role=\"checkbox\"\n aria-checked={indeterminate ? 'mixed' : checked}\n disabled={disabled}\n onClick={() => onChange?.(!checked)}\n className={cn(\n 'peer inline-flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px] border-2 transition-all duration-150',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n filled\n ? `${COLOR_CLASSES[color]} shadow-sm`\n : 'border-muted-foreground/40 bg-background hover:border-muted-foreground/60',\n className,\n )}\n {...props}\n >\n {indeterminate\n ? <Minus className=\"h-3.5 w-3.5\" strokeWidth={3} />\n : checked && <Check className=\"h-3.5 w-3.5\" strokeWidth={3} />}\n </button>\n )\n },\n)\nCheckbox.displayName = 'Checkbox'\n\nexport { Checkbox }\nexport type { CheckboxColor, CheckboxProps }\n","import * as React from 'react'\nimport {\n type ColumnDef,\n type SortingState,\n flexRender,\n getCoreRowModel,\n getSortedRowModel,\n useReactTable,\n} from '@tanstack/react-table'\nimport { ArrowUpDown, ArrowUp, ArrowDown } from 'lucide-react'\nimport { useTranslation } from '@fayz-ai/core'\n\nimport { cn } from '../lib/cn'\nimport { Checkbox } from './checkbox'\n\ninterface DataTableProps<TData, TValue> {\n columns: ColumnDef<TData, TValue>[]\n data: TData[]\n loading?: boolean\n skeletonRows?: number\n emptyMessage?: React.ReactNode\n onRowClick?: (row: TData) => void\n /** Visual variant: 'card' (white bg, card wrapper — default), 'flat'\n * (transparent bg, still bordered), or 'bare' — no wrapper chrome at all,\n * for a table already inside a card that owns the border and radius. */\n variant?: 'card' | 'flat' | 'bare'\n /** Compact mode: smaller padding and font size */\n compact?: boolean\n /**\n * Qual coluna está ordenada e para que lado, quando quem ordena é OUTRO\n * controle (o menu \"Ordenar\" da barra de ferramentas).\n *\n * Marca o cabeçalho sem torná-lo clicável: com a ordenação fora da tabela,\n * a seta é INFORMAÇÃO (\"está ordenado por isto, assim\"), não um botão. Sem\n * ela, mudar a ordem por um menu que fecha em seguida não deixava rastro\n * nenhum na tela.\n */\n sortIndicator?: { columnId: string; dir: 'asc' | 'desc' }\n /**\n * Turns on the checkbox column on the left. Selection is CONTROLLED by ids:\n * what a bulk action needs is \"which records\", and the table's own row indexes\n * stop meaning that the moment the list refetches, sorts or pages.\n */\n selectable?: boolean\n selectedIds?: string[]\n onSelectedIdsChange?: (ids: string[]) => void\n /** Row identity for selection. Defaults to `row.id`. */\n getRowId?: (row: TData) => string\n}\n\nfunction DataTable<TData, TValue>({\n columns,\n data,\n loading = false,\n skeletonRows = 3,\n emptyMessage = 'No results.',\n onRowClick,\n variant = 'card',\n compact = false,\n sortIndicator,\n selectable = false,\n selectedIds,\n onSelectedIdsChange,\n getRowId,\n}: DataTableProps<TData, TValue>) {\n const t = useTranslation()\n const isCard = variant === 'card'\n // Rounded box and scroll container must be SEPARATE elements: a scroll\n // container paints its content over its own border-radius, which squared\n // the corners the moment a row background met them.\n const wrapperCls = isCard\n ? 'overflow-hidden rounded-card border bg-card shadow-sm'\n : variant === 'bare'\n ? ''\n : 'overflow-hidden rounded-lg border'\n // 'bare' sits below something else inside its parent card (a search/tools\n // toolbar), so its header is a mid-card band: no rounding, and it keeps the\n // card's own surface rather than starting a new tinted block.\n const headerCls = isCard\n ? 'border-b bg-muted/50'\n : variant === 'bare'\n ? 'border-b bg-muted/30 rounded-none'\n : 'border-b bg-muted/30'\n const thCls = compact ? 'px-3 py-1.5 text-left text-[11px] font-medium text-muted-foreground' : 'px-4 py-2.5 text-left font-medium text-muted-foreground'\n const tdCls = compact ? 'px-3 py-1.5 align-middle text-xs' : 'px-4 py-3 align-middle'\n const tableCls = compact ? 'w-full text-xs min-w-max' : 'w-full text-sm min-w-max'\n const rowHoverCls = isCard ? 'hover:bg-muted/30' : 'hover:bg-muted/20'\n const [sorting, setSorting] = React.useState<SortingState>([])\n\n const rowId = React.useCallback(\n (row: TData) => (getRowId ? getRowId(row) : String((row as { id?: unknown }).id ?? '')),\n [getRowId],\n )\n const selected = React.useMemo(() => new Set(selectedIds ?? []), [selectedIds])\n const pageIds = React.useMemo(() => data.map(rowId), [data, rowId])\n const selectedOnPage = pageIds.filter((id) => selected.has(id)).length\n const allOnPageSelected = pageIds.length > 0 && selectedOnPage === pageIds.length\n\n const toggleRow = React.useCallback((id: string) => {\n const next = new Set(selected)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n onSelectedIdsChange?.([...next])\n }, [selected, onSelectedIdsChange])\n // The header box acts on THIS page only — it must not silently drop a\n // selection made on another page, nor claim to have selected rows that were\n // never loaded.\n const toggleAllOnPage = React.useCallback(() => {\n const next = new Set(selected)\n if (allOnPageSelected) pageIds.forEach((id) => next.delete(id))\n else pageIds.forEach((id) => next.add(id))\n onSelectedIdsChange?.([...next])\n }, [selected, allOnPageSelected, pageIds, onSelectedIdsChange])\n\n // Built here rather than asked of every caller: the column is pure chrome, and\n // a hand-rolled copy per list is where the checkbox column drifts.\n const selectionColumn = React.useMemo<ColumnDef<TData, TValue>>(() => ({\n id: '__select__',\n enableSorting: false,\n header: () => (\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={selectedOnPage > 0 && !allOnPageSelected}\n onChange={toggleAllOnPage}\n aria-label={t('crud.list.selectAllRows')}\n />\n ),\n cell: ({ row }) => {\n const id = rowId(row.original)\n return (\n <Checkbox\n checked={selected.has(id)}\n onChange={() => toggleRow(id)}\n aria-label={t('crud.list.selectRow')}\n />\n )\n },\n // `toggleAllOnPage` is in the deps because it closes over the CURRENT page's\n // ids: turning the page with nothing selected changes no other dep, and the\n // memo would hand the header a button that ticks the previous page's rows.\n }), [allOnPageSelected, selectedOnPage, selected, rowId, toggleRow, toggleAllOnPage, t])\n\n const allColumns = React.useMemo(\n () => (selectable ? [selectionColumn, ...columns] : columns),\n [selectable, selectionColumn, columns],\n )\n\n const table = useReactTable({\n data,\n columns: allColumns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n onSortingChange: setSorting,\n state: { sorting },\n })\n\n if (loading) {\n return (\n <div className={wrapperCls}>\n <div className=\"overflow-x-auto\">\n <table className={tableCls}>\n <thead>\n <tr className={headerCls}>\n {allColumns.map((_, i) => (\n <th key={i} className={thCls}>\n <div className=\"h-3.5 w-20 animate-pulse rounded bg-muted\" />\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {Array.from({ length: skeletonRows }).map((_, i) => (\n <tr key={i} className=\"border-b last:border-0\">\n {allColumns.map((_, j) => (\n <td key={j} className={tdCls}>\n <div className=\"h-3.5 w-full animate-pulse rounded bg-muted\" />\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )\n }\n\n return (\n <div className={wrapperCls}>\n <div className=\"overflow-x-auto\">\n <table className={tableCls}>\n <thead>\n {table.getHeaderGroups().map((headerGroup) => (\n <tr key={headerGroup.id} className={headerCls}>\n {headerGroup.headers.map((header) => {\n const sorted = header.column.getIsSorted()\n return (\n <th\n key={header.id}\n className={cn(thCls, header.column.id === '__select__' && 'w-10 pr-0')}\n >\n {header.isPlaceholder ? null : sortIndicator?.columnId === header.column.id ? (\n <span className=\"inline-flex items-center gap-1 text-foreground\">\n {flexRender(header.column.columnDef.header, header.getContext())}\n {sortIndicator.dir === 'desc'\n ? <ArrowDown className=\"h-3 w-3\" />\n : <ArrowUp className=\"h-3 w-3\" />}\n </span>\n ) : header.column.getCanSort() ? (\n <button\n className=\"flex items-center gap-1 hover:text-foreground transition-colors\"\n onClick={header.column.getToggleSortingHandler()}\n >\n {flexRender(header.column.columnDef.header, header.getContext())}\n {sorted === 'asc' ? (\n <ArrowUp className=\"h-3 w-3\" />\n ) : sorted === 'desc' ? (\n <ArrowDown className=\"h-3 w-3\" />\n ) : (\n <ArrowUpDown className=\"h-3 w-3 opacity-40\" />\n )}\n </button>\n ) : (\n flexRender(header.column.columnDef.header, header.getContext())\n )}\n </th>\n )\n })}\n </tr>\n ))}\n </thead>\n <tbody>\n {table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => {\n const isSelected = selectable && selected.has(rowId(row.original))\n return (\n <tr\n key={row.id}\n className={cn(\n `border-b last:border-0 transition-colors ${rowHoverCls}`,\n onRowClick && 'cursor-pointer',\n isSelected && 'bg-muted/40',\n )}\n onClick={() => onRowClick?.(row.original)}\n data-selected={isSelected || undefined}\n >\n {row.getVisibleCells().map((cell) => {\n const isSelectCell = cell.column.id === '__select__'\n return (\n <td\n key={cell.id}\n className={cn(tdCls, isSelectCell && 'w-10 pr-0')}\n // Ticking a box is not opening the record: without this\n // the row's own click handler fired underneath and the\n // list navigated away from the selection just made.\n onClick={isSelectCell ? (e) => e.stopPropagation() : undefined}\n >\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n )\n })}\n </tr>\n )\n })\n ) : (\n <tr>\n {/* Height, not just padding: an empty table that collapses to one\n thin row reads as a rendering glitch rather than \"nothing\n here yet\". `emptyMessage` takes a node so callers can hand in\n a full empty state (icon, headline, create action). */}\n <td colSpan={allColumns.length} className=\"h-64 px-6 text-center align-middle text-muted-foreground\">\n {emptyMessage}\n </td>\n </tr>\n )}\n </tbody>\n </table>\n </div>\n </div>\n )\n}\n\nexport { DataTable, type DataTableProps }\n","import { cn } from '../lib/cn'\n\nfunction Skeleton({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('animate-pulse rounded-md bg-muted', className)}\n {...props}\n />\n )\n}\n\n/**\n * Skeleton loader that mimics a table with rows and columns.\n * Drop-in replacement for \"Loading...\" text in list views.\n */\nfunction TableSkeleton({ columns = 4, rows = 2 }: { columns?: number; rows?: number }) {\n return (\n <div className=\"rounded-lg border overflow-hidden\">\n <div className=\"border-b bg-muted/30 flex gap-4 px-4 py-2.5\">\n {Array.from({ length: columns }).map((_, i) => (\n <Skeleton key={i} className=\"h-3 flex-1 rounded bg-muted-foreground/10\" />\n ))}\n </div>\n <div className=\"divide-y\">\n {Array.from({ length: rows }).map((_, r) => (\n <div key={r} className=\"flex items-center gap-4 px-4 py-3.5\">\n {Array.from({ length: columns }).map((_, c) => (\n <Skeleton\n key={c}\n className={cn(\n 'h-3 rounded',\n c === 0 ? 'flex-[2]' : 'flex-1',\n )}\n />\n ))}\n </div>\n ))}\n </div>\n </div>\n )\n}\n\nexport { Skeleton, TableSkeleton }\n","import * as React from 'react'\nimport { Calendar, Check, ChevronDown, GripVertical, RefreshCw } from 'lucide-react'\nimport { cn } from '../lib/cn'\nimport { Button } from './button'\nimport { Dropdown, DropdownTrigger, DropdownContent, DropdownItem } from './dropdown'\n\n// ---------------------------------------------------------------------------\n// PageToolbar — a barra flutuante do que a tela está MOSTRANDO.\n//\n// A barra da shell carrega o que se FAZ numa tela (Novo, Importar, Salvar).\n// Esta carrega a pergunta que a tela responde: qual período, quais filtros,\n// quais cartões. Eram duas respostas diferentes para as mesmas três coisas — a\n// faixa de Análises, larga e com cromo próprio, e o \"Customize\" solto do\n// dashboard —, então o mesmo trabalho parecia recurso de produto diferente\n// dependendo da página aberta.\n//\n// Flutuante e à direita de propósito: ela governa a grade ABAIXO dela e fica\n// parada enquanto essa grade rola por baixo (sticky, com borda e sombra, para\n// ler como algo POR CIMA dos cartões e não como uma emenda no layout).\n// ---------------------------------------------------------------------------\n\n/**\n * O gatilho padrão da barra: sem contorno, com o rótulo sublinhado tracejado.\n *\n * Contornados, os três viravam três caixas arredondadas dentro de outra caixa\n * arredondada — a borda do vidro e a dos botões disputavam a mesma leitura, e a\n * barra parecia um grupo de botões e não um controle. O tracejado é o traço\n * clássico de \"este valor se troca\": diz que clica sem desenhar mais um limite.\n */\nexport const ToolbarButton = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<typeof Button> & { icon?: React.ElementType; caret?: boolean }\n>(function ToolbarButton({ icon: Icon, caret = true, children, className, ...props }, ref) {\n return (\n <Button\n ref={ref}\n variant=\"ghost\"\n size=\"sm\"\n className={cn(\n // Sem fundo no hover: um retângulo arredondado aparecendo atrás do\n // rótulo desenha, no hover, exatamente o botão que o repouso não tem.\n // O que muda é o texto e o traço — mais firmes, e o tracejado vira\n // contínuo, que é o mesmo \"agora sim, clique\" sem inventar caixa.\n 'group gap-1.5 border-0 bg-transparent px-2 font-medium text-muted-foreground shadow-none',\n 'hover:bg-transparent hover:text-foreground',\n className,\n )}\n {...props}\n >\n {Icon ? <Icon className=\"h-3 w-3 shrink-0 opacity-70\" /> : null}\n <span className=\"inline-flex items-center gap-1.5 border-b border-dashed border-muted-foreground/40 pb-px transition-colors group-hover:border-solid group-hover:border-foreground\">\n {children}\n </span>\n {caret ? <ChevronDown className=\"h-3 w-3 shrink-0 opacity-60\" /> : null}\n </Button>\n )\n})\n\n/**\n * O gatilho de COMANDO da barra — Exportar, Imprimir, Novo.\n *\n * Mesma matéria do ToolbarButton acima (sem contorno, sem fundo, fantasma) e\n * sem o sublinhado tracejado: o tracejado promete \"este valor se troca\", e\n * imprimir não é um valor. Eram botões contornados no meio de uma barra sem\n * contorno nenhum — duas caixas arredondadas ao lado de três rótulos soltos,\n * que é o desenho que faz a barra parecer duas barras.\n */\nexport const ToolbarAction = React.forwardRef<\n HTMLButtonElement,\n React.ComponentProps<typeof Button> & { icon?: React.ElementType; caret?: boolean }\n>(function ToolbarAction({ icon: Icon, caret = false, children, className, ...props }, ref) {\n return (\n <Button\n ref={ref}\n variant=\"ghost\"\n size=\"sm\"\n className={cn(\n 'gap-1.5 border-0 bg-transparent px-2 font-medium text-muted-foreground shadow-none',\n 'hover:bg-transparent hover:text-foreground',\n className,\n )}\n {...props}\n >\n {Icon ? <Icon className=\"h-3 w-3 shrink-0 opacity-70\" /> : null}\n {children}\n {caret ? <ChevronDown className=\"h-3 w-3 shrink-0 opacity-60\" /> : null}\n </Button>\n )\n})\n\nexport interface RangeOption {\n value: string\n label: string\n}\n\nexport interface RangeControlProps {\n options: RangeOption[]\n value: string\n onChange: (value: string) => void\n /** Rótulo do gatilho quando não é nenhum dos presets (ex.: \"Personalizado\"). */\n label?: string\n /** \"21 jul – 19 ago\" — a janela que os números realmente cobrem. Um nome de\n * preset sozinho deixa a dúvida se \"este mês\" já inclui hoje. */\n span?: string\n /** Itens extras no fim do menu (ex.: abrir uma janela personalizada). */\n extra?: React.ReactNode\n /** Desenhado ao lado do gatilho (ex.: os dois seletores de data). */\n children?: React.ReactNode\n icon?: React.ElementType\n className?: string\n}\n\n/**\n * O controle de período — um só, para o dashboard e para as análises.\n *\n * Puramente apresentacional: quem tem o estado (o contexto de analytics, o de\n * dashboard) passa opções e valor. Eram dois desenhos para a mesma escolha, um\n * segmentado de 7d/30d/90d e um menu de presets, e trocar de tela trocava a\n * gramática do controle sem trocar o que ele faz.\n */\nexport function RangeControl({\n options, value, onChange, label, span, extra, children, icon = Calendar, className,\n}: RangeControlProps) {\n const current = options.find((o) => o.value === value)\n return (\n <div className={cn('flex items-center gap-1.5', className)}>\n <Dropdown>\n <DropdownTrigger asChild>\n <ToolbarButton icon={icon}>\n {label ?? current?.label ?? value}\n {span ? <span className=\"font-normal text-muted-foreground\">{span}</span> : null}\n </ToolbarButton>\n </DropdownTrigger>\n <DropdownContent align=\"end\" className=\"w-56\">\n {options.map((o) => (\n <DropdownItem key={o.value} onSelect={() => onChange(o.value)}>\n {o.label}\n {o.value === value ? <Check className=\"ml-auto h-3.5 w-3.5 shrink-0 pl-1\" /> : null}\n </DropdownItem>\n ))}\n {extra}\n </DropdownContent>\n </Dropdown>\n {children}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Onde a barra mora.\n//\n// Ela flutua sobre a grade, e \"sobre a grade\" às vezes quer dizer \"em cima do\n// título do terceiro cartão\". Em vez de escolher por todo mundo um canto que\n// nunca atrapalhe — não existe —, a barra ganha uma alça e o usuário resolve.\n//\n// UMA posição para todas as telas, por omissão: \"onde fica a barra flutuante\" é\n// uma preferência, não sete. Uma superfície que precise da sua passa `storageKey`.\n// ---------------------------------------------------------------------------\n\ninterface ToolbarOffset { x: number; y: number }\n\nconst OFFSET_KEY = (scope: string) => `fayz.toolbar.offset.${scope}`\nconst EDGE = 8\n\nfunction readOffset(key: string): ToolbarOffset {\n if (typeof window === 'undefined') return { x: 0, y: 0 }\n try {\n const raw = window.localStorage.getItem(key)\n if (!raw) return { x: 0, y: 0 }\n const parsed = JSON.parse(raw) as Partial<ToolbarOffset>\n return {\n x: Number.isFinite(parsed.x) ? Number(parsed.x) : 0,\n y: Number.isFinite(parsed.y) ? Number(parsed.y) : 0,\n }\n } catch {\n return { x: 0, y: 0 }\n }\n}\n\nfunction writeOffset(key: string, offset: ToolbarOffset): void {\n if (typeof window === 'undefined') return\n try {\n if (offset.x === 0 && offset.y === 0) window.localStorage.removeItem(key)\n else window.localStorage.setItem(key, JSON.stringify(offset))\n } catch {\n /* quota / private mode — perder isto custa uma posição, não um dado */\n }\n}\n\n/**\n * Deslocamento arrastável, preso à viewport.\n *\n * O clamp mede o elemento JÁ transladado e desconta o deslocamento atual para\n * achar a âncora — é o que mantém a barra inteira na tela depois de um resize,\n * de um rail que abre, ou de uma posição guardada numa janela maior.\n */\nfunction useToolbarOffset(storageKey: string, enabled: boolean) {\n const key = OFFSET_KEY(storageKey)\n const barRef = React.useRef<HTMLDivElement>(null)\n const [offset, setOffset] = React.useState<ToolbarOffset>(() => (enabled ? readOffset(key) : { x: 0, y: 0 }))\n const [dragging, setDragging] = React.useState(false)\n const latest = React.useRef(offset)\n latest.current = offset\n const origin = React.useRef<{ px: number; py: number; ox: number; oy: number } | null>(null)\n\n const clamp = React.useCallback((next: ToolbarOffset): ToolbarOffset => {\n const el = barRef.current\n if (!el || typeof window === 'undefined') return next\n const rect = el.getBoundingClientRect()\n const anchorLeft = rect.left - latest.current.x\n const anchorTop = rect.top - latest.current.y\n return {\n x: Math.min(\n Math.max(next.x, EDGE - anchorLeft),\n Math.max(EDGE - anchorLeft, window.innerWidth - EDGE - rect.width - anchorLeft),\n ),\n y: Math.min(\n Math.max(next.y, EDGE - anchorTop),\n Math.max(EDGE - anchorTop, window.innerHeight - EDGE - rect.height - anchorTop),\n ),\n }\n }, [])\n\n const move = React.useCallback((next: ToolbarOffset, persist: boolean) => {\n const clamped = clamp(next)\n setOffset(clamped)\n if (persist) writeOffset(key, clamped)\n }, [clamp, key])\n\n const onPointerDown = (event: React.PointerEvent<HTMLElement>) => {\n if (!enabled || event.button !== 0) return\n event.preventDefault()\n event.currentTarget.setPointerCapture(event.pointerId)\n origin.current = { px: event.clientX, py: event.clientY, ox: latest.current.x, oy: latest.current.y }\n setDragging(true)\n }\n\n const onPointerMove = (event: React.PointerEvent<HTMLElement>) => {\n const from = origin.current\n if (!from) return\n move({ x: from.ox + (event.clientX - from.px), y: from.oy + (event.clientY - from.py) }, false)\n }\n\n const endDrag = (event: React.PointerEvent<HTMLElement>) => {\n if (!origin.current) return\n origin.current = null\n setDragging(false)\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId)\n }\n writeOffset(key, latest.current)\n }\n\n // Teclado: a alça é um botão, e um controle que só responde ao arrasto não\n // existe para quem não usa mouse.\n const onKeyDown = (event: React.KeyboardEvent) => {\n if (!enabled) return\n const step = event.shiftKey ? 24 : 8\n const delta: Record<string, ToolbarOffset> = {\n ArrowLeft: { x: -step, y: 0 },\n ArrowRight: { x: step, y: 0 },\n ArrowUp: { x: 0, y: -step },\n ArrowDown: { x: 0, y: step },\n }\n if (event.key === 'Escape' || event.key === 'Home') {\n event.preventDefault()\n move({ x: 0, y: 0 }, true)\n return\n }\n const d = delta[event.key]\n if (!d) return\n event.preventDefault()\n move({ x: latest.current.x + d.x, y: latest.current.y + d.y }, true)\n }\n\n const reset = React.useCallback(() => move({ x: 0, y: 0 }, true), [move])\n\n // Uma posição guardada numa janela larga não pode esconder a barra numa\n // estreita — reancora sem gravar, para não sobrescrever a escolha do usuário.\n React.useEffect(() => {\n if (!enabled) return\n const onResize = () => move(latest.current, false)\n window.addEventListener('resize', onResize)\n return () => window.removeEventListener('resize', onResize)\n }, [enabled, move])\n\n return { barRef, offset, dragging, reset, handlers: { onPointerDown, onPointerMove, onPointerUp: endDrag, onPointerCancel: endDrag, onKeyDown } }\n}\n\nexport interface PageToolbarProps {\n /** O período. */\n range?: React.ReactNode\n /** Filtros gerais e comparação — o que estreita a pergunta. */\n filters?: React.ReactNode\n /** Filtros aplicados, como pastilhas removíveis. */\n chips?: React.ReactNode\n /** Quais componentes aparecem. */\n customize?: React.ReactNode\n /** Extras da tela (exportar, um relatório novo). */\n actions?: React.ReactNode\n onRefresh?: () => void\n refreshLabel?: string\n /** Solta a barra do topo (dentro de um modal, ou ao imprimir). */\n sticky?: boolean\n /** Alça de arrastar à esquerda. Desligue onde a barra não flutua sobre nada. */\n movable?: boolean\n /** Separa a posição desta barra da compartilhada. Ver useToolbarOffset. */\n storageKey?: string\n /** Rótulo acessível da alça. */\n moveLabel?: string\n className?: string\n}\n\nexport function PageToolbar({\n range, filters, chips, customize, actions, onRefresh, refreshLabel,\n sticky = true, movable = true, storageKey = 'shared', moveLabel, className,\n}: PageToolbarProps) {\n const { barRef, offset, dragging, reset, handlers } = useToolbarOffset(storageKey, movable)\n if (!range && !filters && !chips && !customize && !actions && !onRefresh) return null\n return (\n // Caixa de altura ZERO: a barra flutua sobre os cartões em vez de abrir uma\n // linha só para ela. Ocupando espaço, ela empurrava a grade inteira para\n // baixo para hospedar controles que a maioria das visitas nem toca — e\n // \"flutuante\" que reserva o próprio lugar não está flutuando.\n //\n // Zero + sticky, não `absolute`: absoluto não gruda, e a pergunta que a\n // página responde tem de continuar à mão depois de vinte cartões de rolagem.\n // `pointer-events-none` na caixa para que a faixa vazia dos lados não coma o\n // clique do cartão embaixo.\n <div\n className={cn(\n // `items-start` não é enfeite: num flex de altura 0, o alinhamento\n // padrão (stretch) achata o filho para 0px — a barra some e só os\n // botões transbordam, sem vidro nenhum atrás.\n 'pointer-events-none z-20 flex h-0 items-start justify-end',\n sticky && 'sticky top-0',\n )}\n >\n <div\n ref={barRef}\n // Transform, não `top/left`: um deslocamento composto não tira a barra\n // do fluxo nem briga com o `sticky` do pai — ele desloca o que o sticky\n // já posicionou.\n style={offset.x || offset.y ? { transform: `translate3d(${offset.x}px, ${offset.y}px, 0)` } : undefined}\n className={cn(\n // O mesmo vidro do assistente (fayz-floating-surface, em styles.css):\n // é a outra coisa que flutua sobre a página, e as duas se diziam\n // flutuantes em materiais diferentes. Fill fino + blur pesado, para a\n // grade passar por baixo sem competir.\n 'fayz-floating-surface pointer-events-auto flex max-w-full flex-wrap items-center justify-end gap-2 rounded-2xl px-2 py-1.5',\n dragging && 'select-none',\n className,\n )}\n >\n {movable ? (\n <button\n type=\"button\"\n aria-label={moveLabel ?? 'Mover a barra'}\n title={moveLabel ?? 'Mover a barra'}\n // `touch-none` para o arrasto não virar rolagem no celular; o\n // duplo clique devolve a barra ao canto de origem, que é a saída\n // para quem a largou num lugar ruim.\n onDoubleClick={reset}\n {...handlers}\n className={cn(\n 'flex h-[26px] w-4 shrink-0 touch-none items-center justify-center rounded-md text-muted-foreground/50',\n 'transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n dragging ? 'cursor-grabbing text-foreground' : 'cursor-grab',\n )}\n >\n <GripVertical className=\"h-3.5 w-3.5\" />\n </button>\n ) : null}\n {range}\n {filters}\n {chips}\n {customize}\n {actions}\n {onRefresh ? (\n <Button\n variant=\"ghost\" size=\"sm\" onClick={onRefresh}\n aria-label={refreshLabel}\n className=\"w-[26px] border-0 bg-transparent p-0 text-muted-foreground shadow-none hover:bg-transparent hover:text-foreground\"\n >\n <RefreshCw className=\"h-3 w-3\" />\n </Button>\n ) : null}\n </div>\n </div>\n )\n}\n"]}