@fayz-ai/ui 0.10.2 → 0.12.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 (75) 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/batch.d.ts +19 -0
  4. package/dist/analytics/batch.d.ts.map +1 -0
  5. package/dist/analytics/context.d.ts.map +1 -1
  6. package/dist/analytics/derive.d.ts.map +1 -1
  7. package/dist/analytics/index.d.ts +2 -0
  8. package/dist/analytics/index.d.ts.map +1 -1
  9. package/dist/{chunk-SEIY2F5F.js → chunk-7BHG3XGJ.js} +317 -86
  10. package/dist/chunk-7BHG3XGJ.js.map +1 -0
  11. package/dist/{chunk-I6CPKAOD.js → chunk-7BMXN7MP.js} +215 -99
  12. package/dist/chunk-7BMXN7MP.js.map +1 -0
  13. package/dist/{chunk-6V5MGYXH.js → chunk-JGJNRNQW.js} +142 -31
  14. package/dist/chunk-JGJNRNQW.js.map +1 -0
  15. package/dist/chunk-ZBQ772DU.js +17 -0
  16. package/dist/chunk-ZBQ772DU.js.map +1 -0
  17. package/dist/{chunk-H63TOSQ7.js → chunk-ZDRHCKRK.js} +499 -142
  18. package/dist/chunk-ZDRHCKRK.js.map +1 -0
  19. package/dist/dashboard/ChartWidget.d.ts.map +1 -1
  20. package/dist/dashboard/KpiCard.d.ts.map +1 -1
  21. package/dist/dashboard/SidebarOnboarding.d.ts +16 -11
  22. package/dist/dashboard/SidebarOnboarding.d.ts.map +1 -1
  23. package/dist/dashboard/Sparkline.d.ts +13 -0
  24. package/dist/dashboard/Sparkline.d.ts.map +1 -0
  25. package/dist/dashboard/index.d.ts +1 -0
  26. package/dist/dashboard/index.d.ts.map +1 -1
  27. package/dist/dashboard/index.js +3 -2
  28. package/dist/index.d.ts +2 -2
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +237 -117
  31. package/dist/index.js.map +1 -1
  32. package/dist/layout/AppShell.d.ts +4 -1
  33. package/dist/layout/AppShell.d.ts.map +1 -1
  34. package/dist/layout/AppShellSkeleton.d.ts +23 -0
  35. package/dist/layout/AppShellSkeleton.d.ts.map +1 -0
  36. package/dist/layout/ModulePage.d.ts +5 -1
  37. package/dist/layout/ModulePage.d.ts.map +1 -1
  38. package/dist/layout/Sidebar.d.ts +19 -1
  39. package/dist/layout/Sidebar.d.ts.map +1 -1
  40. package/dist/layout/Topbar.d.ts +4 -1
  41. package/dist/layout/Topbar.d.ts.map +1 -1
  42. package/dist/layout/index.d.ts +2 -0
  43. package/dist/layout/index.d.ts.map +1 -1
  44. package/dist/layout/index.js +2 -1
  45. package/dist/layout/page-trail.d.ts +23 -0
  46. package/dist/layout/page-trail.d.ts.map +1 -0
  47. package/dist/layout/rail-flyout.d.ts +39 -0
  48. package/dist/layout/rail-flyout.d.ts.map +1 -0
  49. package/dist/primitives/bulk-action-bar.d.ts +30 -0
  50. package/dist/primitives/bulk-action-bar.d.ts.map +1 -0
  51. package/dist/primitives/checkbox.d.ts +5 -0
  52. package/dist/primitives/checkbox.d.ts.map +1 -1
  53. package/dist/primitives/data-table.d.ts +11 -1
  54. package/dist/primitives/data-table.d.ts.map +1 -1
  55. package/dist/primitives/dropdown.d.ts.map +1 -1
  56. package/dist/primitives/index.d.ts +5 -0
  57. package/dist/primitives/index.d.ts.map +1 -1
  58. package/dist/primitives/index.js +2 -2
  59. package/dist/primitives/list-chrome.d.ts +20 -0
  60. package/dist/primitives/list-chrome.d.ts.map +1 -0
  61. package/dist/primitives/modal.d.ts.map +1 -1
  62. package/dist/primitives/phone-field.d.ts +19 -0
  63. package/dist/primitives/phone-field.d.ts.map +1 -0
  64. package/dist/primitives/refresh-button.d.ts +18 -0
  65. package/dist/primitives/refresh-button.d.ts.map +1 -0
  66. package/dist/primitives/search-select.d.ts +6 -1
  67. package/dist/primitives/search-select.d.ts.map +1 -1
  68. package/dist/primitives/thumbnail.d.ts +19 -0
  69. package/dist/primitives/thumbnail.d.ts.map +1 -0
  70. package/dist/styles.css +298 -1
  71. package/package.json +2 -2
  72. package/dist/chunk-6V5MGYXH.js.map +0 -1
  73. package/dist/chunk-H63TOSQ7.js.map +0 -1
  74. package/dist/chunk-I6CPKAOD.js.map +0 -1
  75. package/dist/chunk-SEIY2F5F.js.map +0 -1
package/dist/styles.css CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  @layer base {
6
6
  :root {
7
+ /* Tells the browser which canvas to paint before any CSS of ours applies —
8
+ without it a dark-mode reload flashes a white frame. */
9
+ color-scheme: light;
10
+
7
11
  /* Polaris "Sail" light — page #f1f1f1, cards #ffffff, near-black brand #303030 */
8
12
  --primary: 0 0% 18.8%;
9
13
  --primary-foreground: 0 0% 100%;
@@ -102,6 +106,8 @@
102
106
  }
103
107
 
104
108
  .dark {
109
+ color-scheme: dark;
110
+
105
111
  /* "Sail midnight" — Polaris dark */
106
112
  --primary: 0 0% 100%;
107
113
  --primary-foreground: 0 0% 10.2%;
@@ -279,6 +285,166 @@
279
285
  }
280
286
  }
281
287
 
288
+ /* ---------------------------------------------------------------------------
289
+ * The assistant's floating material.
290
+ *
291
+ * The FAB and the docked composer are the same object in two shapes, so they
292
+ * are one surface: a tinted fill (the caller's, usually bg-primary), a blurred
293
+ * backdrop, a lit top edge and a shadow deep enough to read as floating ABOVE
294
+ * the page rather than pasted onto it.
295
+ *
296
+ * It lives in CSS, not in utility classes, for two reasons: every app gets it
297
+ * without adding Tailwind content globs, and a glass theme extends it through
298
+ * --glass-inner-highlight instead of forking it.
299
+ * ------------------------------------------------------------------------ */
300
+ .fayz-assistant-surface {
301
+ position: relative;
302
+ border: 1px solid rgb(255 255 255 / 0.22);
303
+ /* Tinted glass: the page reads through the fill, the blur keeps it from being
304
+ legible through it. 0.84 is the floor — below that the white label starts
305
+ losing more contrast than the effect is worth. The utility class the caller
306
+ passes (bg-primary) stays as the opaque fallback for browsers, or builds,
307
+ that never see this rule. */
308
+ background-color: hsl(var(--primary) / 0.84);
309
+ backdrop-filter: blur(28px) saturate(1.8);
310
+ -webkit-backdrop-filter: blur(28px) saturate(1.8);
311
+ background-clip: padding-box;
312
+ box-shadow:
313
+ 0 10px 36px -10px rgb(0 0 0 / 0.45),
314
+ 0 2px 6px -3px rgb(0 0 0 / 0.3),
315
+ inset 0 1px 0 rgb(255 255 255 / 0.32),
316
+ var(--glass-inner-highlight);
317
+ transition: box-shadow 200ms ease-out, transform 200ms cubic-bezier(0.22, 1, 0.36, 1);
318
+ }
319
+
320
+ /* The sheen. Negative z-index paints it over the fill but UNDER the icons and
321
+ text, so the highlight lights the surface instead of washing out its label. */
322
+ .fayz-assistant-surface::after {
323
+ content: '';
324
+ position: absolute;
325
+ inset: 0;
326
+ z-index: -1;
327
+ border-radius: inherit;
328
+ pointer-events: none;
329
+ /* Kept to the top third: a sheen that reaches the middle lightens the fill
330
+ exactly where the label sits, and the label pays for it in contrast. */
331
+ background: linear-gradient(
332
+ to bottom,
333
+ rgb(255 255 255 / 0.2),
334
+ rgb(255 255 255 / 0.04) 30%,
335
+ transparent 52%
336
+ );
337
+ }
338
+
339
+ /* Folding back into the FAB, the bar's contents leave first.
340
+ *
341
+ * The send button sits at the collapsing end, so it was the last thing on screen
342
+ * — an arrow carried all the way into the corner and then swapped for a sparkle.
343
+ * Dropping it early means what lands in the corner is an empty capsule, which is
344
+ * what the FAB actually is. */
345
+ .fayz-assistant-leaving .fayz-assistant-send,
346
+ .fayz-assistant-leaving svg,
347
+ .fayz-assistant-leaving input {
348
+ opacity: 0;
349
+ transition: opacity 120ms ease-in;
350
+ }
351
+
352
+ /* An invitation, not an alarm.
353
+ *
354
+ * The bar carries a halo of its own colour: it breathes a few times on arrival,
355
+ * then rests at a static glow for as long as it is open. Hovering or focusing it
356
+ * ends the pulse for good — the attention it was asking for has been paid, and a
357
+ * thing that keeps pulsing after you look at it is just noise in the corner of
358
+ * the eye. Sits at z-index -2, BEHIND the fill, so only the spill shows. */
359
+ .fayz-assistant-glow::before {
360
+ content: '';
361
+ position: absolute;
362
+ inset: 0;
363
+ z-index: -2;
364
+ border-radius: inherit;
365
+ pointer-events: none;
366
+ box-shadow:
367
+ 0 0 0 1px hsl(var(--primary) / 0.3),
368
+ 0 0 28px 3px hsl(var(--primary) / 0.42);
369
+ opacity: 0.32;
370
+ transition: opacity 220ms ease-out;
371
+ animation: fayz-assistant-breathe 3.4s ease-in-out 3;
372
+ }
373
+
374
+ @keyframes fayz-assistant-breathe {
375
+ 0%,
376
+ 100% {
377
+ opacity: 0.32;
378
+ }
379
+ 50% {
380
+ opacity: 0.78;
381
+ }
382
+ }
383
+
384
+ .fayz-assistant-glow:hover::before,
385
+ .fayz-assistant-glow:focus-within::before {
386
+ animation: none;
387
+ opacity: 0.52;
388
+ }
389
+
390
+ @media (prefers-reduced-motion: reduce) {
391
+ .fayz-assistant-glow::before {
392
+ animation: none;
393
+ }
394
+ }
395
+
396
+ /* The composer's own text. Stated here, not as utilities, because the label and
397
+ the send button are the two things that MUST survive: an app whose Tailwind
398
+ build does not scan this package would otherwise draw a grey placeholder and
399
+ a primary-on-primary arrow — an invisible button on a tinted bar. */
400
+ .fayz-assistant-surface input {
401
+ color: hsl(var(--primary-foreground));
402
+ }
403
+
404
+ .fayz-assistant-surface input::placeholder {
405
+ color: hsl(var(--primary-foreground));
406
+ opacity: 0.92;
407
+ }
408
+
409
+ .fayz-assistant-send {
410
+ display: inline-flex;
411
+ align-items: center;
412
+ justify-content: center;
413
+ flex: none;
414
+ width: 2rem;
415
+ height: 2rem;
416
+ border-radius: 9999px;
417
+ /* Fully opaque: the bar around it is translucent now, so anything less here
418
+ lets the page print through the button twice over. */
419
+ background: hsl(var(--primary-foreground));
420
+ color: hsl(var(--primary));
421
+ transition: background-color 150ms ease-out, transform 150ms ease-out;
422
+ }
423
+
424
+ /* Something to send: the button gains weight, the way a primary action should. */
425
+ .fayz-assistant-send[data-ready='true'] {
426
+ box-shadow: 0 1px 3px rgb(0 0 0 / 0.18);
427
+ }
428
+
429
+ .fayz-assistant-send:active {
430
+ transform: scale(0.94);
431
+ }
432
+
433
+ .fayz-assistant-surface:hover,
434
+ .fayz-assistant-surface:focus-within {
435
+ box-shadow:
436
+ 0 18px 50px -12px rgb(0 0 0 / 0.5),
437
+ 0 3px 8px -3px rgb(0 0 0 / 0.32),
438
+ inset 0 1px 0 rgb(255 255 255 / 0.42),
439
+ var(--glass-inner-highlight);
440
+ }
441
+
442
+ @media (prefers-reduced-motion: reduce) {
443
+ .fayz-assistant-surface {
444
+ transition: none;
445
+ }
446
+ }
447
+
282
448
  .fayz-glass-field,
283
449
  input.bg-card,
284
450
  textarea.bg-card,
@@ -323,6 +489,27 @@ select.bg-card,
323
489
  to { opacity: 1; transform: translateY(0); }
324
490
  }
325
491
 
492
+ /* Shell entrance — a veil in the theme background laid over the just-mounted
493
+ shell, fading out so the product appears in one quick crossfade instead of
494
+ popping in over the boot spinner. The background is what the HTML boot
495
+ screen and AppShellSkeleton already painted, so boot stays ONE image:
496
+ same surface → same surface → app fading in on top of it. */
497
+ .shell-enter::after {
498
+ content: '';
499
+ position: fixed;
500
+ inset: 0;
501
+ z-index: 100;
502
+ background: hsl(var(--background));
503
+ pointer-events: none;
504
+ animation: shell-enter-veil 350ms ease 50ms forwards;
505
+ }
506
+ @keyframes shell-enter-veil {
507
+ to { opacity: 0; visibility: hidden; }
508
+ }
509
+ @media (prefers-reduced-motion: reduce) {
510
+ .shell-enter::after { animation-duration: 0ms; animation-delay: 0ms; }
511
+ }
512
+
326
513
  /* Radix animation utilities (replaces tailwindcss-animate plugin) */
327
514
  .animate-in {
328
515
  animation-name: enter;
@@ -453,9 +640,119 @@ select.bg-card,
453
640
  to { opacity: 0; transform: translateX(35%); }
454
641
  }
455
642
 
643
+ /* Collapsed-rail flyout — the panel itself SLIDES to the row being pointed at
644
+ (a transform transition on the element); this is only its contents changing
645
+ on arrival, so the swap reads as the same object showing something new. */
646
+ .saas-flyout-swap {
647
+ animation: saas-flyout-swap 160ms var(--saas-transition-easing) both;
648
+ }
649
+
650
+ @keyframes saas-flyout-swap {
651
+ from { opacity: 0; transform: translateY(-3px); }
652
+ to { opacity: 1; transform: translateY(0); }
653
+ }
654
+
456
655
  @media (prefers-reduced-motion: reduce) {
457
656
  .saas-rail-in-forward, .saas-rail-out-forward,
458
- .saas-rail-in-back, .saas-rail-out-back {
657
+ .saas-rail-in-back, .saas-rail-out-back,
658
+ .saas-flyout-swap {
459
659
  animation-duration: 1ms;
460
660
  }
461
661
  }
662
+
663
+ /* ---------------------------------------------------------------------------
664
+ Layout that measures the COLUMN, not the window.
665
+
666
+ The screen is not the space the page gets: the assistant docks over half of
667
+ it, the settings rail takes another slice, and a 27" monitor can leave a form
668
+ with 600px. A `lg:` breakpoint still read 1900px and kept three columns, so
669
+ "Buscar ou criar cliente" wrapped onto four lines inside a 280px rail while
670
+ the window was, technically, huge.
671
+
672
+ These rules query the element instead. A form squeezed to phone width folds
673
+ like a phone, wherever it is — which is the only way a counter sale typed on
674
+ a split screen behaves like one typed full screen.
675
+
676
+ `.fz-container` marks a measuring point; the grids below answer to the
677
+ NEAREST one. Mark the page root and each column of a split, and every field
678
+ grid inside a rail measures the rail.
679
+ --------------------------------------------------------------------------- */
680
+ .fz-container { container-type: inline-size; }
681
+
682
+ /* The wide column + the narrow rail. One column until both actually fit. */
683
+ .fz-split {
684
+ display: grid;
685
+ gap: 1rem;
686
+ grid-template-columns: minmax(0, 1fr);
687
+ }
688
+ @container (min-width: 56rem) {
689
+ .fz-split { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 1.25rem; }
690
+ }
691
+
692
+ /* Field grids. The suffix is the MAXIMUM number of columns, reached only where
693
+ there is room for it — never a promise the layout has to keep at 320px.
694
+ They need a `.fz-container` above them; without one they stay single-column,
695
+ which is cramped but never broken. */
696
+ .fz-fields {
697
+ display: grid;
698
+ gap: 0.75rem;
699
+ grid-template-columns: minmax(0, 1fr);
700
+ align-items: start;
701
+ }
702
+ @container (min-width: 30rem) {
703
+ .fz-fields-2, .fz-fields-3, .fz-fields-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
704
+ }
705
+ @container (min-width: 44rem) {
706
+ .fz-fields-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
707
+ .fz-fields-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
708
+ }
709
+ /* A field that spans the row it is on, whatever the column count is. */
710
+ .fz-field-wide { grid-column: 1 / -1; }
711
+
712
+ /* Rows separated by a rule while they are stacked; side by side the rule is
713
+ drawn between unrelated neighbours, so it goes. */
714
+ @container (min-width: 30rem) {
715
+ .fz-divide-none > :not([hidden]) ~ :not([hidden]) { border-top-width: 0; }
716
+ }
717
+
718
+ /* A detail that yields first when the column gets tight — "2 × R$ 30,00" next
719
+ to a line total, say. Visible is the DEFAULT and the fallback: with no
720
+ container above it the rule never fires, so nothing goes missing on a screen
721
+ nobody measured. */
722
+ @container (max-width: 26rem) {
723
+ .fz-tight-hide { display: none; }
724
+ }
725
+
726
+ /* Card grids size themselves off the track, so they need no container at all:
727
+ a 16rem card is the unit, and however many fit, fit. */
728
+ .fz-cards {
729
+ display: grid;
730
+ gap: 1rem;
731
+ grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
732
+ }
733
+
734
+ /* A row of choices (segmented control, tone pickers). auto-FIT, not auto-fill:
735
+ three options share the row instead of leaving two ghost columns. */
736
+ .fz-options {
737
+ display: grid;
738
+ gap: 0.5rem;
739
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
740
+ }
741
+
742
+ /* Hovering is not something a finger does. A row action revealed on hover is an
743
+ action the tablet at the counter cannot reach at all, so it only hides where
744
+ there is a real pointer to bring it back. */
745
+ .fz-hover-reveal { opacity: 1; }
746
+ @media (hover: hover) and (pointer: fine) {
747
+ .fz-hover-reveal { opacity: 0; }
748
+ .group:hover .fz-hover-reveal,
749
+ .fz-hover-reveal:focus-visible { opacity: 1; }
750
+ }
751
+
752
+ /* Counter ergonomics: a finger is not a mouse pointer. Quantity steppers, the
753
+ remove button and anything else tapped mid-sale get the 44px target the
754
+ platform guidelines ask for, on touch INPUT rather than on screen width —
755
+ a tablet on the counter is as wide as a laptop. */
756
+ @media (pointer: coarse) {
757
+ .fz-tap { min-height: 2.75rem; min-width: 2.75rem; }
758
+ }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "fayz": {
4
4
  "status": "beta"
5
5
  },
6
- "version": "0.10.2",
6
+ "version": "0.12.0",
7
7
  "description": "Fayz SDK UI — Radix + Tailwind component library with CRUD engine and layout shells",
8
8
  "type": "module",
9
9
  "sideEffects": [
@@ -75,7 +75,7 @@
75
75
  "clsx": "^2.1.0",
76
76
  "recharts": "^2.15.0",
77
77
  "tailwind-merge": "^2.4.0",
78
- "@fayz-ai/core": "^0.10.0"
78
+ "@fayz-ai/core": "^0.12.0"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@types/react": "^18.3.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/primitives/card.tsx","../src/primitives/dropdown.tsx","../src/primitives/data-table.tsx","../src/primitives/skeleton.tsx","../src/primitives/segmented-control.tsx"],"names":["React","jsx","React3","jsxs","_"],"mappings":"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","file":"chunk-6V5MGYXH.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 <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n 'fayz-glass-surface z-50 min-w-[8rem] overflow-hidden rounded-md 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))\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-md 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 {\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'\n\nimport { cn } from '../lib/cn'\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\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}: DataTableProps<TData, TValue>) {\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-lg 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 table = useReactTable({\n data,\n columns,\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 {columns.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 {columns.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={thCls}\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 <tr\n key={row.id}\n className={cn(\n `border-b last:border-0 transition-colors ${rowHoverCls}`,\n onRowClick && 'cursor-pointer'\n )}\n onClick={() => onRowClick?.(row.original)}\n >\n {row.getVisibleCells().map((cell) => (\n <td key={cell.id} className={tdCls}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n ))}\n </tr>\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={columns.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 { cn } from '../lib/cn'\n\nexport interface SegmentedOption<T extends string = string> {\n value: T\n label: React.ReactNode\n}\n\nexport interface SegmentedControlProps<T extends string = string> {\n /** Options as plain values (label = value) or `{ value, label }` objects. */\n options: ReadonlyArray<T | SegmentedOption<T>>\n value: T\n onChange: (value: T) => void\n /** Matches the equivalent Button heights: sm = 26px, md = 30px. */\n size?: 'sm' | 'md'\n className?: string\n 'aria-label'?: string\n}\n\nconst SIZE: Record<'sm' | 'md', { container: string; segment: string }> = {\n sm: { container: 'h-[26px]', segment: 'px-2.5 text-xs' },\n md: { container: 'h-[30px]', segment: 'px-3 text-sm' },\n}\n\n/**\n * Canonical segmented (pill) control — same chrome as Button (rounded-button\n * radius, hairline border + shadow-button bevel on a card surface). Use this for\n * any 7d/30d/90d-style toggle so every surface stays visually consistent instead\n * of hand-rolling a styled toggle group.\n */\nexport function SegmentedControl<T extends string = string>({\n options, value, onChange, size = 'sm', className, ...rest\n}: SegmentedControlProps<T>) {\n const items = options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o)) as SegmentedOption<T>[]\n return (\n <div\n role=\"tablist\"\n aria-label={rest['aria-label']}\n className={cn(\n 'inline-flex items-center rounded-button border border-border bg-card p-0.5 shadow-button',\n SIZE[size].container,\n className,\n )}\n >\n {items.map((item) => {\n const active = item.value === value\n return (\n <button\n key={item.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n onClick={() => onChange(item.value)}\n className={cn(\n 'flex h-full items-center rounded-button font-semibold transition-colors',\n SIZE[size].segment,\n active ? 'bg-foreground text-background' : 'text-muted-foreground hover:bg-muted/60',\n )}\n >\n {item.label}\n </button>\n )\n })}\n </div>\n )\n}\n"]}