@snksergio/design-system 0.53.0 → 0.54.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 (28) hide show
  1. package/dist-lib/chunks/{toggle-group-C9rrkkmh.cjs → toggle-group-BTnqY_nt.cjs} +23 -23
  2. package/dist-lib/chunks/toggle-group-BTnqY_nt.cjs.map +1 -0
  3. package/dist-lib/chunks/{toggle-group-mXbG8_Jm.mjs → toggle-group-BYmj8142.mjs} +22 -22
  4. package/dist-lib/chunks/toggle-group-BYmj8142.mjs.map +1 -0
  5. package/dist-lib/index.cjs +630 -1
  6. package/dist-lib/index.cjs.map +1 -1
  7. package/dist-lib/index.mjs +638 -9
  8. package/dist-lib/index.mjs.map +1 -1
  9. package/dist-lib/shadcn.cjs +1 -1
  10. package/dist-lib/shadcn.mjs +1 -1
  11. package/dist-lib/src/components/index.d.ts +1 -0
  12. package/dist-lib/src/components/index.d.ts.map +1 -1
  13. package/dist-lib/src/components/ui/TabsNavigation/index.d.ts +5 -0
  14. package/dist-lib/src/components/ui/TabsNavigation/index.d.ts.map +1 -0
  15. package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation-context.d.ts +19 -0
  16. package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation-context.d.ts.map +1 -0
  17. package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.d.ts +84 -0
  18. package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.d.ts.map +1 -0
  19. package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.styles.d.ts +393 -0
  20. package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.styles.d.ts.map +1 -0
  21. package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.types.d.ts +99 -0
  22. package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.types.d.ts.map +1 -0
  23. package/dist-lib/src/components/ui/TabsNavigation/use-arrastar-para-rolar.d.ts +26 -0
  24. package/dist-lib/src/components/ui/TabsNavigation/use-arrastar-para-rolar.d.ts.map +1 -0
  25. package/dist-lib/theme.css +15 -0
  26. package/package.json +1 -1
  27. package/dist-lib/chunks/toggle-group-C9rrkkmh.cjs.map +0 -1
  28. package/dist-lib/chunks/toggle-group-mXbG8_Jm.mjs.map +0 -1
@@ -6,7 +6,7 @@ const avatar = require("./chunks/avatar-DAmZ7fBZ.cjs");
6
6
  const jsxRuntime = require("react/jsx-runtime");
7
7
  const React = require("react");
8
8
  const sheet = require("./chunks/sheet-rg6uupt1.cjs");
9
- const toggleGroup = require("./chunks/toggle-group-C9rrkkmh.cjs");
9
+ const toggleGroup = require("./chunks/toggle-group-BTnqY_nt.cjs");
10
10
  const lucideReact = require("lucide-react");
11
11
  const input = require("./chunks/input-Ci_2-5Te.cjs");
12
12
  const kpiDelta = require("./chunks/kpi-delta-1-gsPFvU.cjs");
@@ -5412,6 +5412,618 @@ const ScreenLoader = React.forwardRef(
5412
5412
  }
5413
5413
  );
5414
5414
  ScreenLoader.displayName = "ScreenLoader";
5415
+ const TabsNavigationContext = React.createContext(null);
5416
+ function useArrastarParaRolar(trilho, ativo = true, limiarPx = 6) {
5417
+ const engolirClique = React.useRef(false);
5418
+ React.useEffect(() => {
5419
+ if (!ativo) return;
5420
+ const el = trilho.current;
5421
+ if (!el) return;
5422
+ if (typeof window === "undefined") return;
5423
+ if (window.matchMedia?.("(pointer: coarse)").matches) return;
5424
+ let arrastando = false;
5425
+ let passouLimiar = false;
5426
+ let xInicial = 0;
5427
+ let scrollInicial = 0;
5428
+ const ehInterativo = (alvo) => alvo instanceof Element && !!alvo.closest(
5429
+ 'button, a, input, select, textarea, [role="button"], [role="menuitem"], [data-radix-popper-content-wrapper], [role="dialog"], [role="menu"], [role="tooltip"]'
5430
+ );
5431
+ const onPointerDown = (e) => {
5432
+ if (e.button !== 0 || ehInterativo(e.target)) return;
5433
+ arrastando = true;
5434
+ passouLimiar = false;
5435
+ xInicial = e.clientX;
5436
+ scrollInicial = el.scrollLeft;
5437
+ };
5438
+ const onPointerMove = (e) => {
5439
+ if (!arrastando) return;
5440
+ const delta = e.clientX - xInicial;
5441
+ if (!passouLimiar) {
5442
+ if (Math.abs(delta) < limiarPx) return;
5443
+ passouLimiar = true;
5444
+ engolirClique.current = true;
5445
+ el.setPointerCapture?.(e.pointerId);
5446
+ el.style.cursor = "grabbing";
5447
+ el.style.userSelect = "none";
5448
+ }
5449
+ el.scrollLeft = scrollInicial - delta;
5450
+ };
5451
+ const encerrar = (e) => {
5452
+ if (!arrastando) return;
5453
+ arrastando = false;
5454
+ el.releasePointerCapture?.(e.pointerId);
5455
+ el.style.cursor = "";
5456
+ el.style.userSelect = "";
5457
+ };
5458
+ const onClickCapture = (e) => {
5459
+ if (!engolirClique.current) return;
5460
+ engolirClique.current = false;
5461
+ e.stopPropagation();
5462
+ e.preventDefault();
5463
+ };
5464
+ el.addEventListener("pointerdown", onPointerDown);
5465
+ el.addEventListener("pointermove", onPointerMove);
5466
+ el.addEventListener("pointerup", encerrar);
5467
+ el.addEventListener("pointercancel", encerrar);
5468
+ el.addEventListener("click", onClickCapture, true);
5469
+ return () => {
5470
+ el.removeEventListener("pointerdown", onPointerDown);
5471
+ el.removeEventListener("pointermove", onPointerMove);
5472
+ el.removeEventListener("pointerup", encerrar);
5473
+ el.removeEventListener("pointercancel", encerrar);
5474
+ el.removeEventListener("click", onClickCapture, true);
5475
+ el.style.cursor = "";
5476
+ el.style.userSelect = "";
5477
+ };
5478
+ }, [trilho, ativo, limiarPx]);
5479
+ }
5480
+ const tabsNavigationRoot = avatar.tv({
5481
+ base: "flex gap-gp-2xs px-pad-lg",
5482
+ variants: {
5483
+ /**
5484
+ * O RESPIRO DO TOPO É DO COMPONENTE, não do consumidor — e isso é o que torna a peça
5485
+ * independente da superfície onde ela cai.
5486
+ *
5487
+ * Enquanto o padding vinha de um wrapper por fora, aquela faixa de 8px acima das abas
5488
+ * ficava com a cor do container (a superfície do card) enquanto a tira ficava com o
5489
+ * recuo: duas cores na mesma banda, e a aba inativa parecia "um botão de outra cor
5490
+ * pousado num fundo diferente". Trazendo o padding pra cá, o recuo cobre a banda inteira
5491
+ * e a ÚNICA coisa com fundo próprio passa a ser a aba ativa.
5492
+ */
5493
+ respiro: {
5494
+ comfortable: "pt-pad-md",
5495
+ compact: "pt-pad-sm",
5496
+ nenhum: ""
5497
+ },
5498
+ /**
5499
+ * `items-stretch` é o que faz a aba de altura total valer: com `items-end` ela encolheria
5500
+ * pro próprio conteúdo e o `h-full` não teria contra o que medir. A régua some junto.
5501
+ */
5502
+ fill: {
5503
+ true: "items-stretch",
5504
+ false: "items-end border-b border-border-default"
5505
+ },
5506
+ /**
5507
+ * Fundo recuado da tira — o par por modo explicado no cabeçalho deste arquivo.
5508
+ *
5509
+ * No claro é `bg-emphasis` (0.94), não `bg-subtle` (0.973): contra a aba ativa branca, o
5510
+ * delta de 0.027 do subtle quase não se lia. Com `emphasis` o recuo é 0.06 e a aba
5511
+ * selecionada salta. No escuro `emphasis` é branco a 12% **sobre** o que está atrás, ou
5512
+ * seja mais CLARO que a superfície (0.28 contra 0.225) — inverteria a hierarquia; ali quem
5513
+ * recua continua sendo `canvas`, e o reforço vem da sombra na aba ativa.
5514
+ */
5515
+ chrome: {
5516
+ true: "bg-bg-emphasis dark:bg-bg-canvas",
5517
+ false: ""
5518
+ }
5519
+ },
5520
+ defaultVariants: { fill: false, chrome: true, respiro: "comfortable" }
5521
+ });
5522
+ const tabsNavigationTrilho = avatar.tv({
5523
+ /**
5524
+ * `scrollbar-none` não é preferência: a barra ocupa 11px DENTRO do trilho e empurra as abas
5525
+ * pra cima da régua, matando a união. A affordance de navegação são as setas + a lista.
5526
+ */
5527
+ base: "flex min-w-0 flex-1 gap-gp-2xs overflow-x-auto scrollbar-none",
5528
+ variants: {
5529
+ /** o `pb-px` só existe pra o `-mb-px` da aba não ser cortado pelo overflow. */
5530
+ fill: {
5531
+ true: "items-stretch",
5532
+ false: "items-end pb-px"
5533
+ }
5534
+ },
5535
+ defaultVariants: { fill: false }
5536
+ });
5537
+ const tabsNavigationTab = avatar.tv({
5538
+ base: [
5539
+ "group/aba relative flex shrink-0 cursor-pointer select-none",
5540
+ "items-center gap-gp-sm border border-transparent px-pad-xl",
5541
+ "text-fg-muted transition-colors",
5542
+ "focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand"
5543
+ ],
5544
+ variants: {
5545
+ /**
5546
+ * A largura é fixa (aba que cresce com o título faz a fila dançar a cada troca) — mas
5547
+ * fixa em DOIS degraus: no celular, 228px é quase a tela inteira e o usuário vê uma aba
5548
+ * e meia, sem noção de que há uma fila. Abaixo de `sm` a aba cai pra ~168/148px, que
5549
+ * mostra duas e meia e deixa o gesto de arrastar fazer sentido.
5550
+ */
5551
+ density: {
5552
+ comfortable: "w-[168px] sm:w-[228px]",
5553
+ compact: "w-[148px] sm:w-[196px]"
5554
+ },
5555
+ fill: {
5556
+ true: "h-full self-stretch",
5557
+ false: "-mb-px rounded-t-radius-lg"
5558
+ },
5559
+ /** A superfície da aba ATIVA — tem que casar com o conteúdo logo abaixo dela. */
5560
+ surface: {
5561
+ surface: "",
5562
+ canvas: ""
5563
+ },
5564
+ ativa: {
5565
+ /**
5566
+ * `shadow-sh-sm` faz o trabalho que a cor não consegue no escuro: ali a ativa (0.225) e
5567
+ * o recuo (0.205) distam 0.02, e mudar a cor da ativa quebraria a união com o conteúdo,
5568
+ * que é o ponto do componente. A sombra separa sem mexer na cor — e no dark ela vem
5569
+ * amplificada por token (L-011).
5570
+ */
5571
+ true: "border-border-default text-fg-strong shadow-sh-sm",
5572
+ false: "hover:bg-bg-subtle"
5573
+ }
5574
+ },
5575
+ compoundVariants: [
5576
+ { fill: false, density: "comfortable", class: "min-h-comp-3xl" },
5577
+ { fill: false, density: "compact", class: "min-h-comp-xl" },
5578
+ /**
5579
+ * ⚠️ A borda de baixo da aba ativa é **transparente**, não "da cor do conteúdo".
5580
+ *
5581
+ * A primeira versão pintava `border-b-bg-surface` pra apagar a régua. Funcionava só quando
5582
+ * o conteúdo logo abaixo era exatamente aquela cor — nos exemplos em que a tira ficava
5583
+ * sobre container transparente, ou separada do painel por um gap, sobrava um traço claro
5584
+ * embaixo da aba selecionada. Com a borda transparente é o **fundo da aba** que cobre a
5585
+ * régua (o background pinta sob a border-box, e o `-mb-px` a coloca por cima da linha):
5586
+ * funciona igual em qualquer superfície, que é o comportamento que se espera por padrão —
5587
+ * a aba emenda no conteúdo, sem linha entre os dois.
5588
+ */
5589
+ { ativa: true, surface: "surface", class: "bg-bg-surface border-b-transparent" },
5590
+ { ativa: true, surface: "canvas", class: "bg-bg-canvas border-b-transparent" }
5591
+ ],
5592
+ defaultVariants: { density: "comfortable", fill: false, surface: "surface", ativa: false }
5593
+ });
5594
+ const tabsNavigationDivisoria = avatar.tv({
5595
+ base: "w-px shrink-0 bg-border-default",
5596
+ variants: {
5597
+ fill: {
5598
+ true: "h-[20px] self-center",
5599
+ false: "h-[20px] mb-[14px]"
5600
+ },
5601
+ /** Ao lado da aba ativa some: encostada na borda dela vira uma sombra falsa. */
5602
+ oculta: {
5603
+ true: "bg-transparent",
5604
+ false: ""
5605
+ }
5606
+ },
5607
+ defaultVariants: { fill: false, oculta: false }
5608
+ });
5609
+ const tabsNavigationControles = avatar.tv({
5610
+ base: "flex shrink-0 items-center gap-gp-2xs",
5611
+ variants: {
5612
+ fill: { true: "h-full", false: "" },
5613
+ density: { comfortable: "h-comp-3xl", compact: "h-comp-xl" }
5614
+ },
5615
+ compoundVariants: [
5616
+ { fill: true, density: "comfortable", class: "h-full" },
5617
+ { fill: true, density: "compact", class: "h-full" }
5618
+ ],
5619
+ defaultVariants: { fill: false, density: "comfortable" }
5620
+ });
5621
+ const tabsNavigationAcao = avatar.tv({
5622
+ base: [
5623
+ "inline-flex size-comp-xs items-center justify-center rounded-radius-sm",
5624
+ "transition-colors focus-visible:outline-none focus-visible:ring-4"
5625
+ ],
5626
+ variants: {
5627
+ tom: {
5628
+ neutro: "text-fg-muted hover:bg-bg-muted hover:text-fg-default focus-visible:ring-ring-brand",
5629
+ success: "text-fg-success hover:bg-bg-success-muted focus-visible:ring-ring-success",
5630
+ danger: "text-fg-danger hover:bg-bg-danger-muted focus-visible:ring-ring-danger"
5631
+ }
5632
+ },
5633
+ defaultVariants: { tom: "neutro" }
5634
+ });
5635
+ const tabsNavigationAcoes = avatar.tv({
5636
+ base: "grid transition-[grid-template-columns,opacity] duration-150 ease-out",
5637
+ variants: {
5638
+ visivel: {
5639
+ true: "grid-cols-[1fr] opacity-100",
5640
+ false: "grid-cols-[0fr] opacity-0 group-hover/aba:grid-cols-[1fr] group-hover/aba:opacity-100 group-focus-within/aba:grid-cols-[1fr] group-focus-within/aba:opacity-100"
5641
+ }
5642
+ },
5643
+ defaultVariants: { visivel: false }
5644
+ });
5645
+ const tabsNavigationStatus = avatar.tv({
5646
+ base: "size-icon-2xs shrink-0",
5647
+ variants: {
5648
+ status: {
5649
+ success: "fill-bg-success text-bg-success",
5650
+ warning: "fill-bg-warning text-bg-warning",
5651
+ danger: "fill-bg-danger text-bg-danger",
5652
+ info: "fill-bg-info text-bg-info",
5653
+ neutral: "fill-fg-subtle text-fg-subtle"
5654
+ }
5655
+ },
5656
+ defaultVariants: { status: "neutral" }
5657
+ });
5658
+ const STATUS_CONHECIDOS = ["success", "warning", "danger", "info", "neutral"];
5659
+ const ehStatusConhecido = (s) => typeof s === "string" && STATUS_CONHECIDOS.includes(s);
5660
+ function TabsNavigationTitle({ children, className, ...rest }) {
5661
+ return /* @__PURE__ */ jsxRuntime.jsx(
5662
+ "span",
5663
+ {
5664
+ className: [
5665
+ "block truncate text-body-sm font-medium",
5666
+ "group-aria-selected/aba:font-semibold",
5667
+ className ?? ""
5668
+ ].join(" "),
5669
+ ...rest,
5670
+ children
5671
+ }
5672
+ );
5673
+ }
5674
+ TabsNavigationTitle.displayName = "TabsNavigation.Title";
5675
+ function TabsNavigationSubtitle({ children, className, ...rest }) {
5676
+ const ctx = React.useContext(TabsNavigationContext);
5677
+ if (ctx?.density === "compact") return null;
5678
+ return /* @__PURE__ */ jsxRuntime.jsx(
5679
+ "span",
5680
+ {
5681
+ className: ["block truncate text-caption-md text-fg-subtle", className ?? ""].join(" "),
5682
+ ...rest,
5683
+ children
5684
+ }
5685
+ );
5686
+ }
5687
+ TabsNavigationSubtitle.displayName = "TabsNavigation.Subtitle";
5688
+ const TabsNavigationAction = React.forwardRef(function TabsNavigationAction2({ tom = "neutro", className, onClick, ...rest }, ref) {
5689
+ return /* @__PURE__ */ jsxRuntime.jsx(
5690
+ "button",
5691
+ {
5692
+ ref,
5693
+ type: "button",
5694
+ className: tabsNavigationAcao({ tom, className }),
5695
+ onClick: (e) => {
5696
+ e.stopPropagation();
5697
+ onClick?.(e);
5698
+ },
5699
+ ...rest
5700
+ }
5701
+ );
5702
+ });
5703
+ TabsNavigationAction.displayName = "TabsNavigation.Action";
5704
+ function TabsNavigationActions({ children }) {
5705
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
5706
+ }
5707
+ TabsNavigationActions.displayName = "TabsNavigation.Actions";
5708
+ function TabsNavigationPanel({ value, children, className, ...rest }) {
5709
+ const ctx = React.useContext(TabsNavigationContext);
5710
+ if (!ctx || ctx.value !== value) return null;
5711
+ return /* @__PURE__ */ jsxRuntime.jsx(
5712
+ "div",
5713
+ {
5714
+ role: "tabpanel",
5715
+ "aria-labelledby": ctx.idTab(value),
5716
+ tabIndex: 0,
5717
+ className,
5718
+ ...rest,
5719
+ children
5720
+ }
5721
+ );
5722
+ }
5723
+ TabsNavigationPanel.displayName = "TabsNavigation.Panel";
5724
+ const TabsNavigationTab = React.forwardRef(function TabsNavigationTab2({
5725
+ value,
5726
+ leading,
5727
+ status,
5728
+ badge,
5729
+ actions,
5730
+ onClose,
5731
+ menu,
5732
+ panelId,
5733
+ actionsAlwaysVisible = false,
5734
+ hoverCard,
5735
+ children,
5736
+ className,
5737
+ ...rest
5738
+ }, ref) {
5739
+ const ctx = React.useContext(TabsNavigationContext);
5740
+ if (!ctx) throw new Error("<TabsNavigation.Tab> só funciona dentro de <TabsNavigation>.");
5741
+ const ativa = ctx.value === value;
5742
+ const temAcoesPadrao = !actions && typeof onClose === "function";
5743
+ const conteudoAcoes = actions ?? (temAcoesPadrao ? /* @__PURE__ */ jsxRuntime.jsx(AcoesPadrao, { onClose, menu }) : null);
5744
+ const aba = /* @__PURE__ */ jsxRuntime.jsxs(
5745
+ "div",
5746
+ {
5747
+ ref,
5748
+ role: "tab",
5749
+ id: ctx.idTab(value),
5750
+ "data-value": value,
5751
+ "aria-selected": ativa,
5752
+ "aria-controls": panelId,
5753
+ tabIndex: ativa ? 0 : -1,
5754
+ onClick: () => ctx.onValueChange(value),
5755
+ onKeyDown: (e) => {
5756
+ if (e.key === "Enter" || e.key === " ") {
5757
+ e.preventDefault();
5758
+ ctx.onValueChange(value);
5759
+ }
5760
+ },
5761
+ className: tabsNavigationTab({
5762
+ density: ctx.density,
5763
+ fill: ctx.fill,
5764
+ surface: ctx.surface,
5765
+ ativa,
5766
+ className
5767
+ }),
5768
+ ...rest,
5769
+ children: [
5770
+ leading,
5771
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: status !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-gp-sm", children: [
5772
+ ehStatusConhecido(status) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: tabsNavigationStatus({ status }), "aria-hidden": true }) : status,
5773
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children })
5774
+ ] }) : children }),
5775
+ !ativa && badge !== void 0 && badge !== null && badge !== 0 ? typeof badge === "number" ? /* @__PURE__ */ jsxRuntime.jsx(
5776
+ "span",
5777
+ {
5778
+ className: "inline-flex min-w-[18px] items-center justify-center rounded-radius-full bg-bg-brand px-pad-xs text-caption-sm font-semibold text-fg-on-brand",
5779
+ "aria-hidden": true,
5780
+ children: badge
5781
+ }
5782
+ ) : badge : null,
5783
+ conteudoAcoes ? /* @__PURE__ */ jsxRuntime.jsx(
5784
+ "div",
5785
+ {
5786
+ className: tabsNavigationAcoes({
5787
+ visivel: ativa || actionsAlwaysVisible || ctx.actionsMode === "persistent"
5788
+ }),
5789
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 items-center gap-gp-2xs overflow-hidden", children: conteudoAcoes })
5790
+ }
5791
+ ) : null
5792
+ ]
5793
+ }
5794
+ );
5795
+ if (!hoverCard || ativa) return aba;
5796
+ return /* @__PURE__ */ jsxRuntime.jsxs(toggleGroup.HoverCard, { openDelay: 500, closeDelay: 120, children: [
5797
+ /* @__PURE__ */ jsxRuntime.jsx(toggleGroup.HoverCardTrigger, { asChild: true, children: aba }),
5798
+ /* @__PURE__ */ jsxRuntime.jsx(toggleGroup.HoverCardContent, { align: "start", className: "w-[300px]", children: hoverCard })
5799
+ ] });
5800
+ });
5801
+ TabsNavigationTab.displayName = "TabsNavigation.Tab";
5802
+ function AcoesPadrao({ onClose, menu }) {
5803
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5804
+ /* @__PURE__ */ jsxRuntime.jsxs(avatar.DropdownMenu, { children: [
5805
+ /* @__PURE__ */ jsxRuntime.jsx(avatar.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(TabsNavigationAction, { "aria-label": "Opções da aba", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-icon-sm" }) }) }),
5806
+ /* @__PURE__ */ jsxRuntime.jsxs(avatar.DropdownMenuContent, { align: "start", className: "w-[196px]", children: [
5807
+ menu,
5808
+ menu ? /* @__PURE__ */ jsxRuntime.jsx(avatar.DropdownMenuSeparator, {}) : null,
5809
+ /* @__PURE__ */ jsxRuntime.jsxs(
5810
+ avatar.DropdownMenuItem,
5811
+ {
5812
+ onSelect: onClose,
5813
+ className: "text-fg-danger focus:bg-bg-danger-muted focus:text-fg-danger",
5814
+ children: [
5815
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-icon-sm" }),
5816
+ " Fechar aba"
5817
+ ]
5818
+ }
5819
+ )
5820
+ ] })
5821
+ ] }),
5822
+ /* @__PURE__ */ jsxRuntime.jsx(TabsNavigationAction, { "aria-label": "Fechar aba", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-icon-sm" }) })
5823
+ ] });
5824
+ }
5825
+ const TabsNavigationRoot = React.forwardRef(function TabsNavigation2({
5826
+ value,
5827
+ onValueChange,
5828
+ surface = "surface",
5829
+ density = "comfortable",
5830
+ fill = false,
5831
+ actionsMode = "hover",
5832
+ chrome = true,
5833
+ onNewTab,
5834
+ children,
5835
+ className,
5836
+ "aria-label": ariaLabel,
5837
+ ...rest
5838
+ }, ref) {
5839
+ const prefixo = React.useId();
5840
+ const trilho = React.useRef(null);
5841
+ const ctx = React.useMemo(
5842
+ () => ({
5843
+ value,
5844
+ onValueChange,
5845
+ surface,
5846
+ density,
5847
+ fill,
5848
+ actionsMode,
5849
+ idTab: (v) => `${prefixo}-${v}`
5850
+ }),
5851
+ [value, onValueChange, surface, density, fill, actionsMode, prefixo]
5852
+ );
5853
+ const { abas, acoesGlobais } = React.useMemo(() => {
5854
+ const abas2 = [];
5855
+ let acoesGlobais2 = null;
5856
+ for (const filho of React.Children.toArray(children)) {
5857
+ if (!React.isValidElement(filho)) continue;
5858
+ if (filho.type === TabsNavigationActions) acoesGlobais2 = filho;
5859
+ else abas2.push(filho);
5860
+ }
5861
+ return { abas: abas2, acoesGlobais: acoesGlobais2 };
5862
+ }, [children]);
5863
+ const [rolagem, setRolagem] = React.useState({ transborda: false, esq: false, dir: false });
5864
+ const medir = React.useCallback(() => {
5865
+ const el = trilho.current;
5866
+ if (!el) return;
5867
+ const max = el.scrollWidth - el.clientWidth;
5868
+ setRolagem({ transborda: max > 1, esq: el.scrollLeft > 1, dir: el.scrollLeft < max - 1 });
5869
+ }, []);
5870
+ React.useEffect(() => {
5871
+ const el = trilho.current;
5872
+ if (!el) return;
5873
+ medir();
5874
+ if (typeof ResizeObserver === "undefined") return;
5875
+ const ro = new ResizeObserver(medir);
5876
+ ro.observe(el);
5877
+ for (const filho of Array.from(el.children)) ro.observe(filho);
5878
+ return () => ro.disconnect();
5879
+ }, [medir, abas.length]);
5880
+ React.useEffect(() => {
5881
+ const el = trilho.current;
5882
+ const alvo = el?.querySelector(`[data-value="${CSS.escape(value)}"]`);
5883
+ alvo?.scrollIntoView({ inline: "nearest", block: "nearest", behavior: "smooth" });
5884
+ if (el?.contains(document.activeElement) && alvo !== document.activeElement) alvo?.focus();
5885
+ }, [value]);
5886
+ useArrastarParaRolar(trilho);
5887
+ const rolar = (dir) => trilho.current?.scrollBy({ left: dir * 240, behavior: "smooth" });
5888
+ const onKeyDown = (e) => {
5889
+ const valores = abas.map((a) => a.props.value);
5890
+ const i = valores.indexOf(value);
5891
+ if (i < 0) return;
5892
+ const proximo = e.key === "ArrowRight" ? valores[(i + 1) % valores.length] : e.key === "ArrowLeft" ? valores[(i - 1 + valores.length) % valores.length] : e.key === "Home" ? valores[0] : e.key === "End" ? valores[valores.length - 1] : null;
5893
+ if (!proximo) return;
5894
+ e.preventDefault();
5895
+ onValueChange(proximo);
5896
+ };
5897
+ const controles = tabsNavigationControles({ fill, density });
5898
+ return /* @__PURE__ */ jsxRuntime.jsx(TabsNavigationContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsxs(
5899
+ "div",
5900
+ {
5901
+ ref,
5902
+ role: "tablist",
5903
+ "aria-label": ariaLabel,
5904
+ "aria-orientation": "horizontal",
5905
+ onKeyDown,
5906
+ className: tabsNavigationRoot({
5907
+ fill,
5908
+ chrome,
5909
+ // em `fill` a aba vai de ponta a ponta: respiro no topo desmontaria justamente isso
5910
+ respiro: fill ? "nenhum" : density,
5911
+ className
5912
+ }),
5913
+ ...rest,
5914
+ children: [
5915
+ rolagem.esq ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${controles} hidden pr-pad-xs sm:flex`, children: [
5916
+ /* @__PURE__ */ jsxRuntime.jsx(
5917
+ avatar.Button,
5918
+ {
5919
+ variant: "ghost",
5920
+ color: "secondary",
5921
+ size: "icon-sm",
5922
+ "aria-label": "Abas anteriores",
5923
+ onClick: () => rolar(-1),
5924
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, {})
5925
+ }
5926
+ ),
5927
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: tabsNavigationDivisoria({ fill }) })
5928
+ ] }) : null,
5929
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: trilho, onScroll: medir, className: tabsNavigationTrilho({ fill }), children: abas.map((aba, i) => {
5930
+ const vizinhaDaAtiva = aba.props.value === value || abas[i + 1]?.props.value === value;
5931
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5932
+ "div",
5933
+ {
5934
+ className: ["flex shrink-0", fill ? "items-stretch" : "items-end"].join(" "),
5935
+ children: [
5936
+ aba,
5937
+ i < abas.length - 1 ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: tabsNavigationDivisoria({ fill, oculta: vizinhaDaAtiva }) }) : null
5938
+ ]
5939
+ },
5940
+ aba.props.value
5941
+ );
5942
+ }) }),
5943
+ rolagem.dir ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${controles} hidden pl-pad-xs sm:flex`, children: [
5944
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: tabsNavigationDivisoria({ fill }) }),
5945
+ /* @__PURE__ */ jsxRuntime.jsx(
5946
+ avatar.Button,
5947
+ {
5948
+ variant: "ghost",
5949
+ color: "secondary",
5950
+ size: "icon-sm",
5951
+ "aria-label": "Próximas abas",
5952
+ onClick: () => rolar(1),
5953
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, {})
5954
+ }
5955
+ )
5956
+ ] }) : null,
5957
+ onNewTab || rolagem.transborda && abas.length || acoesGlobais ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: controles, children: [
5958
+ onNewTab ? /* @__PURE__ */ jsxRuntime.jsx(
5959
+ avatar.Button,
5960
+ {
5961
+ variant: "ghost",
5962
+ color: "secondary",
5963
+ size: "icon-sm",
5964
+ "aria-label": "Abrir nova aba",
5965
+ onClick: onNewTab,
5966
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {})
5967
+ }
5968
+ ) : null,
5969
+ rolagem.transborda && abas.length ? /* @__PURE__ */ jsxRuntime.jsxs(avatar.DropdownMenu, { children: [
5970
+ /* @__PURE__ */ jsxRuntime.jsx(avatar.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
5971
+ avatar.Button,
5972
+ {
5973
+ variant: "ghost",
5974
+ color: "secondary",
5975
+ size: "icon-sm",
5976
+ "aria-label": `Listar as ${abas.length} abas abertas`,
5977
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, {})
5978
+ }
5979
+ ) }),
5980
+ /* @__PURE__ */ jsxRuntime.jsxs(
5981
+ avatar.DropdownMenuContent,
5982
+ {
5983
+ align: "end",
5984
+ className: "max-h-[320px] w-[264px] overflow-y-auto scrollbar-thin",
5985
+ children: [
5986
+ /* @__PURE__ */ jsxRuntime.jsxs(avatar.DropdownMenuLabel, { children: [
5987
+ abas.length,
5988
+ " abas abertas"
5989
+ ] }),
5990
+ /* @__PURE__ */ jsxRuntime.jsx(avatar.DropdownMenuSeparator, {}),
5991
+ abas.map((aba) => {
5992
+ const p = aba.props;
5993
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5994
+ avatar.DropdownMenuItem,
5995
+ {
5996
+ onSelect: () => onValueChange(p.value),
5997
+ className: p.value === value ? "bg-bg-brand-subtle text-fg-brand" : void 0,
5998
+ children: [
5999
+ ehStatusConhecido(p.status) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: tabsNavigationStatus({ status: p.status }), "aria-hidden": true }) : null,
6000
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1", children: p.children })
6001
+ ]
6002
+ },
6003
+ p.value
6004
+ );
6005
+ })
6006
+ ]
6007
+ }
6008
+ )
6009
+ ] }) : null,
6010
+ acoesGlobais ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6011
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: tabsNavigationDivisoria({ fill, className: "mx-pad-xs" }) }),
6012
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-gp-2xs", children: acoesGlobais })
6013
+ ] }) : null
6014
+ ] }) : null
6015
+ ]
6016
+ }
6017
+ ) });
6018
+ });
6019
+ const TabsNavigation = Object.assign(TabsNavigationRoot, {
6020
+ Tab: TabsNavigationTab,
6021
+ Title: TabsNavigationTitle,
6022
+ Subtitle: TabsNavigationSubtitle,
6023
+ Action: TabsNavigationAction,
6024
+ Actions: TabsNavigationActions,
6025
+ Panel: TabsNavigationPanel
6026
+ });
5415
6027
  class Adder {
5416
6028
  constructor() {
5417
6029
  this._partials = new Float64Array(32);
@@ -8470,6 +9082,15 @@ exports.Modal = Modal;
8470
9082
  exports.MonthYearPicker = MonthYearPicker;
8471
9083
  exports.ScreenLoader = ScreenLoader;
8472
9084
  exports.Spinner = Spinner;
9085
+ exports.TabsNavigation = TabsNavigation;
9086
+ exports.TabsNavigationAction = TabsNavigationAction;
9087
+ exports.TabsNavigationActions = TabsNavigationActions;
9088
+ exports.TabsNavigationContext = TabsNavigationContext;
9089
+ exports.TabsNavigationPanel = TabsNavigationPanel;
9090
+ exports.TabsNavigationRoot = TabsNavigationRoot;
9091
+ exports.TabsNavigationSubtitle = TabsNavigationSubtitle;
9092
+ exports.TabsNavigationTab = TabsNavigationTab;
9093
+ exports.TabsNavigationTitle = TabsNavigationTitle;
8473
9094
  exports.ToastCard = ToastCard;
8474
9095
  exports.ToolbarFilterControl = ToolbarFilterControl;
8475
9096
  exports.ToolbarMobileDialog = ToolbarMobileDialog;
@@ -8497,6 +9118,14 @@ exports.messageVariablesPickerStyles = messageVariablesPickerStyles;
8497
9118
  exports.numberColumn = numberColumn;
8498
9119
  exports.phoneColumn = phoneColumn;
8499
9120
  exports.statusColumn = statusColumn;
9121
+ exports.tabsNavigationAcao = tabsNavigationAcao;
9122
+ exports.tabsNavigationAcoes = tabsNavigationAcoes;
9123
+ exports.tabsNavigationControles = tabsNavigationControles;
9124
+ exports.tabsNavigationDivisoria = tabsNavigationDivisoria;
9125
+ exports.tabsNavigationRoot = tabsNavigationRoot;
9126
+ exports.tabsNavigationStatus = tabsNavigationStatus;
9127
+ exports.tabsNavigationTab = tabsNavigationTab;
9128
+ exports.tabsNavigationTrilho = tabsNavigationTrilho;
8500
9129
  exports.textColumn = textColumn;
8501
9130
  exports.toast = toast;
8502
9131
  exports.toastVariants = toastVariants;