@rendra-ui/web 2.7.0 → 2.8.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 (50) hide show
  1. package/README.md +14 -14
  2. package/dist/base.css +1 -1
  3. package/dist/{brand-feedback-icon-BYNcqBel.js → brand-feedback-icon-CVux4pNh.js} +3 -3
  4. package/dist/{brand-feedback-icon-BYNcqBel.js.map → brand-feedback-icon-CVux4pNh.js.map} +1 -1
  5. package/dist/{button-DlzWwpZk.js → button-CrSlVIsY.js} +6 -6
  6. package/dist/{button-DlzWwpZk.js.map → button-CrSlVIsY.js.map} +1 -1
  7. package/dist/chart.js +7 -7
  8. package/dist/cli/auditar.js +1 -1
  9. package/dist/cli/codigos.js +2 -2
  10. package/dist/cli/executar-auditar.js +1 -1
  11. package/dist/cli/help.js +1 -1
  12. package/dist/cli/trocar.js +2 -2
  13. package/dist/cli/typescript-loader.js +1 -1
  14. package/dist/{cn-B0N3Pek0.js → cn-BlJHpkDs.js} +2 -2
  15. package/dist/{cn-B0N3Pek0.js.map → cn-BlJHpkDs.js.map} +1 -1
  16. package/dist/{components-CpQPMGfT.js → components-6RpoJ2Od.js} +4 -4
  17. package/dist/components-6RpoJ2Od.js.map +1 -0
  18. package/dist/components.css +19 -1
  19. package/dist/document-viewer.js +4 -4
  20. package/dist/{dropdown-menu-M8vs0byD.js → dropdown-menu-BUGKtR6k.js} +5 -5
  21. package/dist/{dropdown-menu-M8vs0byD.js.map → dropdown-menu-BUGKtR6k.js.map} +1 -1
  22. package/dist/{empty-state-a47Kd_Ci.js → empty-state-i4e-LacG.js} +6 -6
  23. package/dist/{empty-state-a47Kd_Ci.js.map → empty-state-i4e-LacG.js.map} +1 -1
  24. package/dist/{features-max-ScxV8gb3.js → features-max-BCIy1Ic-.js} +1 -1
  25. package/dist/flow.js +7 -7
  26. package/dist/index.js +808 -229
  27. package/dist/index.js.map +1 -1
  28. package/dist/{motion-context-BUMPf0e9.js → motion-context-PJPj6X4g.js} +4 -4
  29. package/dist/{motion-context-BUMPf0e9.js.map → motion-context-PJPj6X4g.js.map} +1 -1
  30. package/dist/{motion-on-CNN6y8g-.js → motion-on-Bocf4Smc.js} +2 -2
  31. package/dist/{motion-on-CNN6y8g-.js.map → motion-on-Bocf4Smc.js.map} +1 -1
  32. package/dist/motion.js +2 -2
  33. package/dist/{rendra-provider-DEURIIL3.js → rendra-provider-Do_qWjJC.js} +3 -3
  34. package/dist/{rendra-provider-DEURIIL3.js.map → rendra-provider-Do_qWjJC.js.map} +1 -1
  35. package/dist/rich-text-editor.js +4 -4
  36. package/dist/router-bridge.js +2 -2
  37. package/dist/{timeline-BOh7gUdA.js → timeline-xrMHeV92.js} +10 -10
  38. package/dist/{timeline-BOh7gUdA.js.map → timeline-xrMHeV92.js.map} +1 -1
  39. package/dist/tokens.css +9 -1
  40. package/dist/{tooltip-Ym9S4h9_.js → tooltip-to0h6aPe.js} +5 -5
  41. package/dist/{tooltip-Ym9S4h9_.js.map → tooltip-to0h6aPe.js.map} +1 -1
  42. package/dist/types/components/ui/data-toolbar.d.ts +6 -1
  43. package/dist/types/components/ui/kanban.d.ts +75 -6
  44. package/dist/{use-breakpoint-En17oXKY.js → use-breakpoint-CM-yeDHJ.js} +2 -2
  45. package/dist/{use-breakpoint-En17oXKY.js.map → use-breakpoint-CM-yeDHJ.js.map} +1 -1
  46. package/dist/{use-motion-presets-D3ww1oJX.js → use-motion-presets-I4StrsCi.js} +3 -3
  47. package/dist/{use-motion-presets-D3ww1oJX.js.map → use-motion-presets-I4StrsCi.js.map} +1 -1
  48. package/dist/widget-grid.js +2 -2
  49. package/package.json +2 -1
  50. package/dist/components-CpQPMGfT.js.map +0 -1
package/dist/tokens.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! Rendra Design System v2.7.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
1
+ /*! Rendra Design System v2.8.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
2
 
3
3
  @layer theme, base, rendra.base, components, rendra.components, utilities;
4
4
  @layer theme, base, components, utilities;
@@ -122,6 +122,10 @@
122
122
  --rendra-info-foreground: #ffffff;
123
123
  --rendra-info-soft: #e7f0fc;
124
124
  --rendra-info-soft-foreground: #0b58b5;
125
+ --rendra-critical-soft: #f8d6d2;
126
+ --rendra-critical-soft-foreground: #7a1d0a;
127
+ --rendra-warning-mid: #f6d77a;
128
+ --rendra-warning-mid-foreground: #4a3500;
125
129
  --rendra-elevation-sm: 0 1px 2px rgb(var(--rendra-shadow-color) / 0.06);
126
130
  --rendra-elevation-md:
127
131
  0 2px 8px -2px rgb(var(--rendra-shadow-color) / 0.1),
@@ -150,6 +154,10 @@
150
154
  --rendra-info-foreground: #ffffff;
151
155
  --rendra-info-soft: #11305a;
152
156
  --rendra-info-soft-foreground: #7fb4ef;
157
+ --rendra-critical-soft: #5a2214;
158
+ --rendra-critical-soft-foreground: #fbc4b4;
159
+ --rendra-warning-mid: #6b5116;
160
+ --rendra-warning-mid-foreground: #fbe3a0;
153
161
  --rendra-elevation-sm: 0 1px 2px rgb(var(--rendra-shadow-color) / 0.3);
154
162
  --rendra-elevation-md: 0 4px 12px -2px rgb(var(--rendra-shadow-color) / 0.35);
155
163
  --rendra-elevation-lg: 0 16px 40px -8px rgb(var(--rendra-shadow-color) / 0.5);
@@ -1,7 +1,7 @@
1
- /*! Rendra Design System v2.7.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
- import { t as cn } from "./cn-B0N3Pek0.js";
3
- import { i as useMotionLib, o as useMotionOn } from "./motion-context-BUMPf0e9.js";
4
- import { t as useMotionPresets } from "./use-motion-presets-D3ww1oJX.js";
1
+ /*! Rendra Design System v2.8.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
+ import { t as cn } from "./cn-BlJHpkDs.js";
3
+ import { i as useMotionLib, o as useMotionOn } from "./motion-context-PJPj6X4g.js";
4
+ import { t as useMotionPresets } from "./use-motion-presets-I4StrsCi.js";
5
5
  import { Tooltip } from "radix-ui";
6
6
  import { forwardRef, useState } from "react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -73,4 +73,4 @@ function Tooltip$1({ content, children, side = "top", disabled }) {
73
73
  //#endregion
74
74
  export { TooltipProvider as n, Tooltip$1 as t };
75
75
 
76
- //# sourceMappingURL=tooltip-Ym9S4h9_.js.map
76
+ //# sourceMappingURL=tooltip-to0h6aPe.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip-Ym9S4h9_.js","names":[],"sources":["../src/components/ui/tooltip.tsx"],"sourcesContent":["import { Tooltip as T } from 'radix-ui'\nimport { forwardRef, useState, type ComponentPropsWithoutRef, type ReactNode } from 'react'\nimport { cn } from '@/lib/cn'\nimport { useMotionLib, useMotionOn, useMotionPresets } from '@/lib/motion'\nimport type { RendraMotion } from '@/lib/motion/motion-on'\n\n/**\n * Tooltip: só para informação complementar, nunca essencial (não existe hover no toque).\n * Informação essencial vai em texto de ajuda visível ou em Popover acionado por toque.\n */\nexport function TooltipProvider({ children }: { children: ReactNode }) {\n return (\n <T.Provider delayDuration={300} skipDelayDuration={150}>\n {children}\n </T.Provider>\n )\n}\n\ninterface TooltipProps {\n content: ReactNode\n children: ReactNode\n side?: 'top' | 'right' | 'bottom' | 'left'\n /** Desliga o tooltip sem mudar a árvore (ex.: sidebar expandida já mostra o rótulo). */\n disabled?: boolean\n}\n\n// O tooltip nasce do gatilho (W6). A origem vem do Radix.\nconst contentCls =\n 'z-50 max-w-xs origin-(--radix-tooltip-content-transform-origin) wrap-break-word rounded-control bg-foreground px-3 py-2 text-xs font-medium text-background'\n\n/**\n * O corpo animado do tooltip em `on`. O Radix entrega ao filho (asChild) o `data-state`, e é por\n * ele que se sabe se o tooltip abriu \"instantâneo\" (`instant-open`: o usuário já estava com outro\n * aberto, ou foi o foco do teclado). Nesse caso não anima: depois do primeiro, os outros abrem sem\n * atraso e sem animação, e a barra inteira parece mais rápida (W7).\n */\nconst TooltipBody = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<RendraMotion['m']['div']>>(\n function TooltipBody(props, ref) {\n const { m } = useMotionOn()\n const presets = useMotionPresets()\n const instant = (props as { 'data-state'?: string })['data-state'] === 'instant-open'\n return <m.div ref={ref} {...props} {...presets.tooltip(instant)} />\n },\n)\n\nexport function Tooltip({ content, children, side = 'top', disabled }: TooltipProps) {\n const lib = useMotionLib()\n // Só em `on`: o estado aberto fica aqui para o conteúdo continuar montado durante a saída.\n // O Radix segue dono do atraso: `onOpenChange` só dispara depois do `delayDuration`.\n const [open, setOpen] = useState(false)\n if (disabled) return <>{children}</>\n if (lib) {\n return (\n <T.Root open={open} onOpenChange={setOpen}>\n <T.Trigger asChild>{children}</T.Trigger>\n <lib.AnimatePresence>\n {open && (\n <T.Portal forceMount key=\"tooltip\">\n <T.Content\n forceMount\n asChild\n side={side}\n sideOffset={8}\n collisionPadding={16}\n data-rendra=\"TIP-001\"\n className={contentCls}\n >\n <TooltipBody>{content}</TooltipBody>\n </T.Content>\n </T.Portal>\n )}\n </lib.AnimatePresence>\n </T.Root>\n )\n }\n return (\n <T.Root>\n <T.Trigger asChild>{children}</T.Trigger>\n <T.Portal>\n <T.Content\n side={side}\n sideOffset={8}\n collisionPadding={16}\n data-rendra=\"TIP-001\"\n className={cn(\n contentCls,\n // `instant-open` não anima; a saída é mais curta que a entrada (W5, W7).\n 'animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=instant-open]:animate-none',\n )}\n >\n {content}\n </T.Content>\n </T.Portal>\n </T.Root>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAUA,SAAgB,gBAAgB,EAAE,YAAqC;CACrE,OACE,oBAAC,QAAE,UAAH;EAAY,eAAe;EAAK,mBAAmB;EAChD;CACS,CAAA;AAEhB;AAWA,IAAM,aACJ;;;;;;;AAQF,IAAM,cAAc,WAClB,SAAS,YAAY,OAAO,KAAK;CAC/B,MAAM,EAAE,MAAM,YAAY;CAC1B,MAAM,UAAU,iBAAiB;CACjC,MAAM,UAAW,MAAoC,kBAAkB;CACvE,OAAO,oBAAC,EAAE,KAAH;EAAY;EAAK,GAAI;EAAO,GAAI,QAAQ,QAAQ,OAAO;CAAI,CAAA;AACpE,CACF;AAEA,SAAgB,UAAQ,EAAE,SAAS,UAAU,OAAO,OAAO,YAA0B;CACnF,MAAM,MAAM,aAAa;CAGzB,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,IAAI,UAAU,OAAO,oBAAA,YAAA,EAAG,SAAW,CAAA;CACnC,IAAI,KACF,OACE,qBAAC,QAAE,MAAH;EAAc;EAAM,cAAc;EAAlC,UAAA,CACE,oBAAC,QAAE,SAAH;GAAW,SAAA;GAAS;EAAoB,CAAA,GACxC,oBAAC,IAAI,iBAAL,EAAA,UACG,QACC,oBAAC,QAAE,QAAH;GAAU,YAAA;GACR,UAAA,oBAAC,QAAE,SAAH;IACE,YAAA;IACA,SAAA;IACM;IACN,YAAY;IACZ,kBAAkB;IAClB,eAAY;IACZ,WAAW;IAEX,UAAA,oBAAC,aAAD,EAAA,UAAc,QAAqB,CAAA;GAC1B,CAAA;EACH,GAZe,SAYf,EAEO,CAAA,CACf;;CAGZ,OACE,qBAAC,QAAE,MAAH,EAAA,UAAA,CACE,oBAAC,QAAE,SAAH;EAAW,SAAA;EAAS;CAAoB,CAAA,GACxC,oBAAC,QAAE,QAAH,EAAA,UACE,oBAAC,QAAE,SAAH;EACQ;EACN,YAAY;EACZ,kBAAkB;EAClB,eAAY;EACZ,WAAW,GACT,YAEA,6LACF;EAEC,UAAA;CACQ,CAAA,EACH,CAAA,CACJ,EAAA,CAAA;AAEZ"}
1
+ {"version":3,"file":"tooltip-to0h6aPe.js","names":[],"sources":["../src/components/ui/tooltip.tsx"],"sourcesContent":["import { Tooltip as T } from 'radix-ui'\nimport { forwardRef, useState, type ComponentPropsWithoutRef, type ReactNode } from 'react'\nimport { cn } from '@/lib/cn'\nimport { useMotionLib, useMotionOn, useMotionPresets } from '@/lib/motion'\nimport type { RendraMotion } from '@/lib/motion/motion-on'\n\n/**\n * Tooltip: só para informação complementar, nunca essencial (não existe hover no toque).\n * Informação essencial vai em texto de ajuda visível ou em Popover acionado por toque.\n */\nexport function TooltipProvider({ children }: { children: ReactNode }) {\n return (\n <T.Provider delayDuration={300} skipDelayDuration={150}>\n {children}\n </T.Provider>\n )\n}\n\ninterface TooltipProps {\n content: ReactNode\n children: ReactNode\n side?: 'top' | 'right' | 'bottom' | 'left'\n /** Desliga o tooltip sem mudar a árvore (ex.: sidebar expandida já mostra o rótulo). */\n disabled?: boolean\n}\n\n// O tooltip nasce do gatilho (W6). A origem vem do Radix.\nconst contentCls =\n 'z-50 max-w-xs origin-(--radix-tooltip-content-transform-origin) wrap-break-word rounded-control bg-foreground px-3 py-2 text-xs font-medium text-background'\n\n/**\n * O corpo animado do tooltip em `on`. O Radix entrega ao filho (asChild) o `data-state`, e é por\n * ele que se sabe se o tooltip abriu \"instantâneo\" (`instant-open`: o usuário já estava com outro\n * aberto, ou foi o foco do teclado). Nesse caso não anima: depois do primeiro, os outros abrem sem\n * atraso e sem animação, e a barra inteira parece mais rápida (W7).\n */\nconst TooltipBody = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<RendraMotion['m']['div']>>(\n function TooltipBody(props, ref) {\n const { m } = useMotionOn()\n const presets = useMotionPresets()\n const instant = (props as { 'data-state'?: string })['data-state'] === 'instant-open'\n return <m.div ref={ref} {...props} {...presets.tooltip(instant)} />\n },\n)\n\nexport function Tooltip({ content, children, side = 'top', disabled }: TooltipProps) {\n const lib = useMotionLib()\n // Só em `on`: o estado aberto fica aqui para o conteúdo continuar montado durante a saída.\n // O Radix segue dono do atraso: `onOpenChange` só dispara depois do `delayDuration`.\n const [open, setOpen] = useState(false)\n if (disabled) return <>{children}</>\n if (lib) {\n return (\n <T.Root open={open} onOpenChange={setOpen}>\n <T.Trigger asChild>{children}</T.Trigger>\n <lib.AnimatePresence>\n {open && (\n <T.Portal forceMount key=\"tooltip\">\n <T.Content\n forceMount\n asChild\n side={side}\n sideOffset={8}\n collisionPadding={16}\n data-rendra=\"TIP-001\"\n className={contentCls}\n >\n <TooltipBody>{content}</TooltipBody>\n </T.Content>\n </T.Portal>\n )}\n </lib.AnimatePresence>\n </T.Root>\n )\n }\n return (\n <T.Root>\n <T.Trigger asChild>{children}</T.Trigger>\n <T.Portal>\n <T.Content\n side={side}\n sideOffset={8}\n collisionPadding={16}\n data-rendra=\"TIP-001\"\n className={cn(\n contentCls,\n // `instant-open` não anima; a saída é mais curta que a entrada (W5, W7).\n 'animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=instant-open]:animate-none',\n )}\n >\n {content}\n </T.Content>\n </T.Portal>\n </T.Root>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAUA,SAAgB,gBAAgB,EAAE,YAAqC;CACrE,OACE,oBAAC,QAAE,UAAH;EAAY,eAAe;EAAK,mBAAmB;EAChD;CACS,CAAA;AAEhB;AAWA,IAAM,aACJ;;;;;;;AAQF,IAAM,cAAc,WAClB,SAAS,YAAY,OAAO,KAAK;CAC/B,MAAM,EAAE,MAAM,YAAY;CAC1B,MAAM,UAAU,iBAAiB;CACjC,MAAM,UAAW,MAAoC,kBAAkB;CACvE,OAAO,oBAAC,EAAE,KAAH;EAAY;EAAK,GAAI;EAAO,GAAI,QAAQ,QAAQ,OAAO;CAAI,CAAA;AACpE,CACF;AAEA,SAAgB,UAAQ,EAAE,SAAS,UAAU,OAAO,OAAO,YAA0B;CACnF,MAAM,MAAM,aAAa;CAGzB,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,IAAI,UAAU,OAAO,oBAAA,YAAA,EAAG,SAAW,CAAA;CACnC,IAAI,KACF,OACE,qBAAC,QAAE,MAAH;EAAc;EAAM,cAAc;EAAlC,UAAA,CACE,oBAAC,QAAE,SAAH;GAAW,SAAA;GAAS;EAAoB,CAAA,GACxC,oBAAC,IAAI,iBAAL,EAAA,UACG,QACC,oBAAC,QAAE,QAAH;GAAU,YAAA;GACR,UAAA,oBAAC,QAAE,SAAH;IACE,YAAA;IACA,SAAA;IACM;IACN,YAAY;IACZ,kBAAkB;IAClB,eAAY;IACZ,WAAW;IAEX,UAAA,oBAAC,aAAD,EAAA,UAAc,QAAqB,CAAA;GAC1B,CAAA;EACH,GAZe,SAYf,EAEO,CAAA,CACf;;CAGZ,OACE,qBAAC,QAAE,MAAH,EAAA,UAAA,CACE,oBAAC,QAAE,SAAH;EAAW,SAAA;EAAS;CAAoB,CAAA,GACxC,oBAAC,QAAE,QAAH,EAAA,UACE,oBAAC,QAAE,SAAH;EACQ;EACN,YAAY;EACZ,kBAAkB;EAClB,eAAY;EACZ,WAAW,GACT,YAEA,6LACF;EAEC,UAAA;CACQ,CAAA,EACH,CAAA,CACJ,EAAA,CAAA;AAEZ"}
@@ -29,9 +29,14 @@ export interface DataToolbarProps {
29
29
  columns?: ToolbarColumn[];
30
30
  /** Ações secundárias à direita (exportar etc.). No mobile, numa linha abaixo. */
31
31
  actions?: ReactNode;
32
+ /**
33
+ * Resumo logo depois da busca (ex.: totais de um quadro). No desktop fica entre a busca e as
34
+ * ações; no mobile, numa linha própria abaixo da busca. Sem ele, nada é desenhado.
35
+ */
36
+ summary?: ReactNode;
32
37
  /** Ação principal da listagem (ex.: Novo cliente). Sempre a última à direita. */
33
38
  primaryAction?: ReactNode;
34
39
  /** Substitui a barra quando há itens selecionados (ações em massa, só desktop). */
35
40
  selectionBar?: ReactNode;
36
41
  }
37
- export declare function DataToolbar({ search, filters, filterCount, onClearFilters, chips, sort, columns, actions, primaryAction, selectionBar, }: DataToolbarProps): import("react").JSX.Element;
42
+ export declare function DataToolbar({ search, filters, filterCount, onClearFilters, chips, sort, columns, actions, summary, primaryAction, selectionBar, }: DataToolbarProps): import("react").JSX.Element;
@@ -7,6 +7,20 @@ export interface KanbanColumn {
7
7
  tone?: BadgeProps['tone'];
8
8
  /** Limite de cards (WIP). Passando dele, o contador fica em alerta. */
9
9
  limit?: number;
10
+ /**
11
+ * Dias máximos de um card nesta etapa. Passando disso (pela `enteredColumnAt` do card), a
12
+ * cadência está vencida. Sem ela, a etapa nunca vence. Aparece no cabeçalho da coluna.
13
+ */
14
+ cadenceDays?: number;
15
+ }
16
+ /** Próxima atividade agendada do card: tipo, data com hora e com quem. */
17
+ export interface KanbanActivity {
18
+ /** Ex.: "Reunião", "Ligação". Só aparece no hint do calendário. */
19
+ type: string;
20
+ /** Data e hora da atividade. */
21
+ at: Date;
22
+ /** Com quem (pessoa de contato). */
23
+ with?: string;
10
24
  }
11
25
  export interface KanbanCard {
12
26
  id: string;
@@ -33,12 +47,36 @@ export interface KanbanCard {
33
47
  meta?: string;
34
48
  /** Valores numéricos do card, pelas chaves de valueFields (ex.: { ps: 4800, mrr: 590 }). */
35
49
  values?: Record<string, number>;
50
+ /**
51
+ * Próxima atividade. Com ela (ou com `cadenceDays` em alguma etapa) o quadro passa a
52
+ * colorir o card pela situação e a mostrar o calendário no lugar do `dueDate`.
53
+ */
54
+ activity?: KanbanActivity;
55
+ /**
56
+ * Quando o card entrou na etapa atual. Quem usa o componente atualiza esta data ao mover
57
+ * o card, para a contagem da cadência recomeçar.
58
+ */
59
+ enteredColumnAt?: Date;
36
60
  }
37
61
  /** Valor somado no cabeçalho da coluna e mostrado no card (ex.: P&S e MRR). */
38
62
  export interface KanbanValueField {
39
63
  key: string;
40
64
  label: string;
41
65
  }
66
+ /** Confirmação opcional de um destino de arraste: abre um modal antes de agir. */
67
+ export interface KanbanDropConfirm {
68
+ title: string;
69
+ description: string;
70
+ /** Texto do botão. Padrão: o `label` do destino. */
71
+ confirmLabel?: string;
72
+ /** Botão destrutivo (ex.: Perder). */
73
+ destructive?: boolean;
74
+ /** Motivos a escolher; o escolhido chega como terceiro argumento de `onDropTarget`. */
75
+ reasons?: {
76
+ value: string;
77
+ label: string;
78
+ }[];
79
+ }
42
80
  /**
43
81
  * Destino de arraste (etapa A14): uma ação para onde o card vai, diferente de "outra
44
82
  * coluna" (ex.: "Marcar como ganho", "Arquivar"). Aparece numa barra durante o arraste e
@@ -54,6 +92,8 @@ export interface KanbanDropTarget {
54
92
  disabled?: boolean;
55
93
  /** Motivo mostrado quando desabilitado; o destino recusa o solto. */
56
94
  disabledReason?: string;
95
+ /** Sem ela, o destino age na hora. Com ela, abre a confirmação (mouse, toque e menu). */
96
+ confirm?: KanbanDropConfirm;
57
97
  }
58
98
  export interface KanbanProps {
59
99
  columns: KanbanColumn[];
@@ -74,11 +114,11 @@ export interface KanbanProps {
74
114
  hasMore?: (columnId: string) => boolean;
75
115
  /** Etapas visíveis por vez no desktop; as demais pela rolagem lateral. Padrão: 5. */
76
116
  visibleColumns?: number;
77
- /** Conteúdo próprio do card, no lugar do padrão. */
117
+ /** Conteúdo próprio do card, no lugar do padrão (substitui também calendário e valores). */
78
118
  renderCard?: (card: KanbanCard) => ReactNode;
79
119
  /**
80
- * Valores do card (até 2, lado a lado com divisória) e o total de cada um na coluna.
81
- * Ex.: [{ key: 'ps', label: 'P&S' }, { key: 'mrr', label: 'MRR' }].
120
+ * Valores do card (até 2, empilhados no rodapé) e o total de cada um na coluna, com o
121
+ * percentual sobre o total do quadro. Ex.: [{ key: 'ps', label: 'P&S' }, { key: 'mrr', label: 'MRR' }].
82
122
  */
83
123
  valueFields?: KanbanValueField[];
84
124
  /** Formato dos valores. Padrão: moeda (R$ 1.250,00). */
@@ -88,11 +128,40 @@ export interface KanbanProps {
88
128
  * barra durante o arraste e o menu "Mover para" passa a listar estes destinos.
89
129
  */
90
130
  dropTargets?: KanbanDropTarget[];
91
- /** Card solto num destino da barra (ou escolhido no menu "Mover para"). */
92
- onDropTarget?: (cardId: string, targetId: string) => void;
131
+ /**
132
+ * Card solto num destino da barra (ou escolhido no menu "Mover para"). `reason` é o motivo
133
+ * escolhido na confirmação (destinos com `confirm.reasons`).
134
+ */
135
+ onDropTarget?: (cardId: string, targetId: string, reason?: string) => void;
136
+ /** Data de hoje, para o status e a cadência (injetável em teste). Padrão: agora. */
137
+ referenceDate?: Date;
138
+ /** Liga a barra do quadro: busca, filtros, totais, Customizar e Novo card. */
139
+ toolbar?: boolean;
140
+ /** "Novo card" da barra do quadro (sem coluna; o (+) da coluna segue com `onAddCard`). */
141
+ onNewCard?: () => void;
142
+ /**
143
+ * Chave do `localStorage` em que o Customizar guarda os campos escondidos (por navegador).
144
+ * Sem ela, a escolha vale só enquanto o quadro está montado.
145
+ */
146
+ storageKey?: string;
93
147
  'aria-label'?: string;
94
148
  className?: string;
95
149
  }
96
- export declare function Kanban({ columns, cards, onCardMove, onCardClick, onAddCard, renderCard, valueFields, formatValue, pageSize, visibleColumns, onLoadMore, hasMore, dropTargets, onDropTarget, className, ...aria }: KanbanProps): import("react").JSX.Element;
150
+ export interface KanbanCardStatus {
151
+ /** Fundo do card: crítico, cadência vencida, sem atividade ou normal. */
152
+ background: 'critical' | 'cadenceOverdue' | 'noActivity' | 'normal';
153
+ /** Situação do calendário: em dia, vence hoje, atrasada ou sem atividade. */
154
+ activity: 'onTime' | 'today' | 'late' | 'none';
155
+ /** Dias de calendário na etapa; `null` sem `enteredColumnAt`. */
156
+ daysInColumn: number | null;
157
+ /** Dias de atraso da atividade (0 fora de `late`). */
158
+ daysLate: number;
159
+ }
160
+ /**
161
+ * Situação do card a partir da próxima atividade e da cadência da etapa. Compara por dia de
162
+ * calendário; `referenceDate` é o "hoje" (injetável para teste).
163
+ */
164
+ export declare function getKanbanCardStatus(card: KanbanCard, column: KanbanColumn | undefined, referenceDate: Date): KanbanCardStatus;
165
+ export declare function Kanban({ columns, cards, onCardMove, onCardClick, onAddCard, renderCard, valueFields, formatValue, pageSize, visibleColumns, onLoadMore, hasMore, dropTargets, onDropTarget, referenceDate, toolbar, onNewCard, storageKey, className, ...aria }: KanbanProps): import("react").JSX.Element;
97
166
  /** Move um card na lista (para usar no onCardMove): devolve a lista nova. */
98
167
  export declare function moveKanbanCard(cards: KanbanCard[], cardId: string, toColumnId: string, toIndex: number): KanbanCard[];
@@ -1,4 +1,4 @@
1
- /*! Rendra Design System v2.7.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
1
+ /*! Rendra Design System v2.8.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
2
  import { useSyncExternalStore } from "react";
3
3
  //#region src/hooks/use-breakpoint.ts
4
4
  /**
@@ -46,4 +46,4 @@ function useBreakpoint() {
46
46
  //#endregion
47
47
  export { useBreakpoint as n, breakpoints as t };
48
48
 
49
- //# sourceMappingURL=use-breakpoint-En17oXKY.js.map
49
+ //# sourceMappingURL=use-breakpoint-CM-yeDHJ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-breakpoint-En17oXKY.js","names":[],"sources":["../src/hooks/use-breakpoint.ts"],"sourcesContent":["import { useSyncExternalStore } from 'react'\n\n/**\n * Pontos de quebra, espelhando os padrões do Tailwind (sm 40rem, md 48rem, lg 64rem...).\n * Único hook de detecção de tela do sistema. Para adaptação ao espaço disponível\n * dentro de um bloco (e não à tela), use container queries (@container) no CSS.\n */\nexport const breakpoints = { sm: 640, md: 768, lg: 1024, xl: 1280, '2xl': 1536 } as const\nexport type Breakpoint = keyof typeof breakpoints\n\nconst order: Breakpoint[] = ['sm', 'md', 'lg', 'xl', '2xl']\n\nfunction subscribe(cb: () => void) {\n const lists = order.map((bp) => matchMedia(`(min-width: ${breakpoints[bp]}px)`))\n lists.forEach((mq) => mq.addEventListener('change', cb))\n return () => lists.forEach((mq) => mq.removeEventListener('change', cb))\n}\n\nfunction getCurrent(): Breakpoint | 'base' {\n let current: Breakpoint | 'base' = 'base'\n for (const bp of order) if (matchMedia(`(min-width: ${breakpoints[bp]}px)`).matches) current = bp\n return current\n}\n\nexport function useBreakpoint() {\n const current = useSyncExternalStore(subscribe, getCurrent, () => 'lg' as const)\n const rank = current === 'base' ? -1 : order.indexOf(current)\n const up = (bp: Breakpoint) => rank >= order.indexOf(bp)\n return {\n current,\n up,\n /** Abaixo de 768px: componentes se reconstroem no formato mobile. */\n isMobile: !up('md'),\n isTablet: up('md') && !up('lg'),\n isDesktop: up('lg'),\n }\n}\n"],"mappings":";;;;;;;;AAOA,IAAa,cAAc;CAAE,IAAI;CAAK,IAAI;CAAK,IAAI;CAAM,IAAI;CAAM,OAAO;AAAK;AAG/E,IAAM,QAAsB;CAAC;CAAM;CAAM;CAAM;CAAM;AAAK;AAE1D,SAAS,UAAU,IAAgB;CACjC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,eAAe,YAAY,IAAI,IAAI,CAAC;CAC/E,MAAM,SAAS,OAAO,GAAG,iBAAiB,UAAU,EAAE,CAAC;CACvD,aAAa,MAAM,SAAS,OAAO,GAAG,oBAAoB,UAAU,EAAE,CAAC;AACzE;AAEA,SAAS,aAAkC;CACzC,IAAI,UAA+B;CACnC,KAAK,MAAM,MAAM,OAAO,IAAI,WAAW,eAAe,YAAY,IAAI,IAAI,CAAC,CAAC,SAAS,UAAU;CAC/F,OAAO;AACT;AAEA,SAAgB,gBAAgB;CAC9B,MAAM,UAAU,qBAAqB,WAAW,kBAAkB,IAAa;CAC/E,MAAM,OAAO,YAAY,SAAS,KAAK,MAAM,QAAQ,OAAO;CAC5D,MAAM,MAAM,OAAmB,QAAQ,MAAM,QAAQ,EAAE;CACvD,OAAO;EACL;EACA;;EAEA,UAAU,CAAC,GAAG,IAAI;EAClB,UAAU,GAAG,IAAI,KAAK,CAAC,GAAG,IAAI;EAC9B,WAAW,GAAG,IAAI;CACpB;AACF"}
1
+ {"version":3,"file":"use-breakpoint-CM-yeDHJ.js","names":[],"sources":["../src/hooks/use-breakpoint.ts"],"sourcesContent":["import { useSyncExternalStore } from 'react'\n\n/**\n * Pontos de quebra, espelhando os padrões do Tailwind (sm 40rem, md 48rem, lg 64rem...).\n * Único hook de detecção de tela do sistema. Para adaptação ao espaço disponível\n * dentro de um bloco (e não à tela), use container queries (@container) no CSS.\n */\nexport const breakpoints = { sm: 640, md: 768, lg: 1024, xl: 1280, '2xl': 1536 } as const\nexport type Breakpoint = keyof typeof breakpoints\n\nconst order: Breakpoint[] = ['sm', 'md', 'lg', 'xl', '2xl']\n\nfunction subscribe(cb: () => void) {\n const lists = order.map((bp) => matchMedia(`(min-width: ${breakpoints[bp]}px)`))\n lists.forEach((mq) => mq.addEventListener('change', cb))\n return () => lists.forEach((mq) => mq.removeEventListener('change', cb))\n}\n\nfunction getCurrent(): Breakpoint | 'base' {\n let current: Breakpoint | 'base' = 'base'\n for (const bp of order) if (matchMedia(`(min-width: ${breakpoints[bp]}px)`).matches) current = bp\n return current\n}\n\nexport function useBreakpoint() {\n const current = useSyncExternalStore(subscribe, getCurrent, () => 'lg' as const)\n const rank = current === 'base' ? -1 : order.indexOf(current)\n const up = (bp: Breakpoint) => rank >= order.indexOf(bp)\n return {\n current,\n up,\n /** Abaixo de 768px: componentes se reconstroem no formato mobile. */\n isMobile: !up('md'),\n isTablet: up('md') && !up('lg'),\n isDesktop: up('lg'),\n }\n}\n"],"mappings":";;;;;;;;AAOA,IAAa,cAAc;CAAE,IAAI;CAAK,IAAI;CAAK,IAAI;CAAM,IAAI;CAAM,OAAO;AAAK;AAG/E,IAAM,QAAsB;CAAC;CAAM;CAAM;CAAM;CAAM;AAAK;AAE1D,SAAS,UAAU,IAAgB;CACjC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,eAAe,YAAY,IAAI,IAAI,CAAC;CAC/E,MAAM,SAAS,OAAO,GAAG,iBAAiB,UAAU,EAAE,CAAC;CACvD,aAAa,MAAM,SAAS,OAAO,GAAG,oBAAoB,UAAU,EAAE,CAAC;AACzE;AAEA,SAAS,aAAkC;CACzC,IAAI,UAA+B;CACnC,KAAK,MAAM,MAAM,OAAO,IAAI,WAAW,eAAe,YAAY,IAAI,IAAI,CAAC,CAAC,SAAS,UAAU;CAC/F,OAAO;AACT;AAEA,SAAgB,gBAAgB;CAC9B,MAAM,UAAU,qBAAqB,WAAW,kBAAkB,IAAa;CAC/E,MAAM,OAAO,YAAY,SAAS,KAAK,MAAM,QAAQ,OAAO;CAC5D,MAAM,MAAM,OAAmB,QAAQ,MAAM,QAAQ,EAAE;CACvD,OAAO;EACL;EACA;;EAEA,UAAU,CAAC,GAAG,IAAI;EAClB,UAAU,GAAG,IAAI,KAAK,CAAC,GAAG,IAAI;EAC9B,WAAW,GAAG,IAAI;CACpB;AACF"}
@@ -1,5 +1,5 @@
1
- /*! Rendra Design System v2.7.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
- import { a as useMotionMode, c as getReducedMotion, l as subscribeReducedMotion } from "./motion-context-BUMPf0e9.js";
1
+ /*! Rendra Design System v2.8.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
+ import { a as useMotionMode, c as getReducedMotion, l as subscribeReducedMotion } from "./motion-context-PJPj6X4g.js";
3
3
  import { useMemo, useSyncExternalStore } from "react";
4
4
  //#region src/lib/motion/tokens.ts
5
5
  /**
@@ -398,4 +398,4 @@ function useMotionPresets() {
398
398
  //#endregion
399
399
  export { toCubicBezier as n, useMotionPresets as t };
400
400
 
401
- //# sourceMappingURL=use-motion-presets-D3ww1oJX.js.map
401
+ //# sourceMappingURL=use-motion-presets-I4StrsCi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-motion-presets-D3ww1oJX.js","names":[],"sources":["../src/lib/motion/tokens.ts","../src/lib/motion/presets.ts","../src/lib/motion/use-motion-presets.ts"],"sourcesContent":["/*\n * Durações e curvas do motion (linguagem única, web e app). A fonte é o globals.css:\n * --rendra-duration-* bloco :root fora de camada (vai para o dist/tokens.css do pacote);\n * --rendra-ease-* no mesmo bloco, então o host as sobrescreve; o @theme guarda os nomes\n * do Tailwind (--ease-out, --ease-move...) como alias delas.\n * As constantes daqui são a reserva em tempo de execução (SSR, variável ausente ou inválida), e\n * tokens.test.ts confere que elas batem com o globals.css. Valores em segundos e vetores de 4\n * números, o formato que o Motion aceita.\n */\n\nexport type Bezier = [number, number, number, number]\n\n/**\n * Reserva das durações, em segundos (SSR, ou variável ausente).\n * `press` e `fast` valem o mesmo (120 ms) com propósitos diferentes: o toque e a saída de overlay.\n */\nexport const DURATION = {\n press: 0.12,\n hover: 0.15,\n fast: 0.12,\n base: 0.2,\n move: 0.25,\n slow: 0.32,\n draw: 0.42,\n pulse: 1,\n}\nexport type DurationName = keyof typeof DURATION\n\n/**\n * Reveal: entrada de uso único (dashboard: bloco, cascata, contador e desenho do gráfico), mais\n * lenta que as interações do dia a dia. Reserva em segundos (SSR, ou variável ausente).\n */\nexport const REVEAL = { enter: 0.6, stagger: 0.12, count: 1.2, draw: 0.9 }\nexport type RevealName = keyof typeof REVEAL\n\n/**\n * Curvas do globals.css (`--rendra-ease-*`). `spring` é a curva \"back\" (quique): só para a cota\n * rara de encanto. `move` desloca na tela; `drawer` é a curva de gaveta e folha.\n */\nexport const EASE: Record<'out' | 'inOut' | 'spring' | 'move' | 'drawer', Bezier> = {\n out: [0.22, 1, 0.36, 1],\n inOut: [0.65, 0, 0.35, 1],\n spring: [0.34, 1.56, 0.64, 1],\n move: [0.77, 0, 0.175, 1],\n drawer: [0.32, 0.72, 0, 1],\n}\nexport type EaseName = keyof typeof EASE\n\n/** Nome da variável CSS de cada curva (`inOut` vira `in-out`). */\nconst EASE_VAR: Record<EaseName, string> = {\n out: 'out',\n inOut: 'in-out',\n spring: 'spring',\n move: 'move',\n drawer: 'drawer',\n}\n\n/**\n * Molas no formato \"duração e quique\" (Motion). `settle` assenta sem passar do ponto (layout,\n * overlay que entra, soltura do arraste); `sheet` é a folha depois do gesto, com quique mínimo.\n * Mola não é variável CSS: mora aqui, e o app a espelha em `dampingRatio`.\n */\nexport const SPRING = {\n settle: { duration: 0.4, bounce: 0 },\n sheet: { duration: 0.3, bounce: 0.2 },\n}\n\n/** Escalas da linguagem: entrada de overlay, tooltip, ponto pequeno, toque, pop e salto curto. */\nexport const SCALE = { enter: 0.95, tooltip: 0.97, small: 0.9, press: 0.97, pop: 0.8, bump: 1.08 }\n\n/** Desfoque (px) que disfarça o cruzamento entre dois estados (troca de passo). Abaixo de 20. */\nexport const BLUR = 2\n\nexport interface MotionTokens {\n duration: Record<DurationName, number>\n reveal: Record<RevealName, number>\n ease: Record<EaseName, Bezier>\n}\n\nfunction toSeconds(value: string): number | null {\n const v = value.trim()\n const n = parseFloat(v)\n if (!Number.isFinite(n)) return null\n if (v.endsWith('ms')) return n / 1000\n if (v.endsWith('s')) return n\n return null\n}\n\n/** `cubic-bezier(a, b, c, d)` em vetor; qualquer outra coisa (`ease-in`, vazio) vira `null`. */\nfunction toBezier(value: string): Bezier | null {\n const m = /^cubic-bezier\\(([^)]+)\\)$/.exec(value.trim())\n if (!m) return null\n const parts = m[1]!.split(',').map((n) => parseFloat(n))\n if (parts.length !== 4 || parts.some((n) => !Number.isFinite(n))) return null\n return parts as Bezier\n}\n\n/** Lê as durações e as curvas do documento; o que faltar (ou sem window) vem da reserva. */\nexport function readMotionTokens(): MotionTokens {\n const duration = { ...DURATION }\n const reveal = { ...REVEAL }\n const ease = { ...EASE }\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n const style = getComputedStyle(document.documentElement)\n for (const name of Object.keys(DURATION) as DurationName[]) {\n const read = toSeconds(style.getPropertyValue(`--rendra-duration-${name}`))\n if (read !== null) duration[name] = read\n }\n for (const name of Object.keys(REVEAL) as RevealName[]) {\n const read = toSeconds(style.getPropertyValue(`--rendra-reveal-${name}`))\n if (read !== null) reveal[name] = read\n }\n for (const name of Object.keys(EASE) as EaseName[]) {\n const read = toBezier(style.getPropertyValue(`--rendra-ease-${EASE_VAR[name]}`))\n if (read !== null) ease[name] = read\n }\n }\n return { duration, reveal, ease }\n}\n","import type { Target, TargetAndTransition, Transition } from 'motion/react'\nimport { BLUR, readMotionTokens, SCALE, SPRING, type Bezier, type MotionTokens } from './tokens'\n\n/*\n * Presets do caminho `on` (linguagem única de movimento): fade, scale/open, sheet, tooltip,\n * indicator, pop, slide, reveal, press, move, settle e stagger. Toda duração e toda curva vêm de\n * readMotionTokens (globals.css); nenhum número de duração mora neste arquivo (o presets.test.ts\n * varre o código-fonte atrás de literal). As molas e as escalas vêm de tokens.ts.\n *\n * Duas regras moram aqui:\n * - Assimetria: o que o usuário decidiu (abrir) entra no tempo `base`, e o que o sistema\n * responde ao fechar sai em `fast`, só em opacidade. Gaveta e folha saem em `base`, de volta\n * pelo lado de onde vieram.\n * - Reduzido: sem deslocamento, escala, filtro nem cascata; a opacidade usa `base` (não zero),\n * porque o esmaecimento é o que explica a mudança de estado.\n */\n\nexport interface MotionPreset {\n initial: Target\n animate: TargetAndTransition\n exit: TargetAndTransition\n transition: Transition\n}\n\n/** Toque: o alvo do `whileTap` (`undefined` no reduzido) e a transição de ida e de volta. */\nexport interface PressPreset {\n whileTap: TargetAndTransition | undefined\n transition: Transition\n}\n\nexport type SlideFrom = 'left' | 'right' | 'top' | 'bottom'\n\n/** Distância do slide: `full` (painel que entra da borda) ou `short` (conteúdo que assenta). */\nexport type SlideDistance = 'full' | 'short'\n\nconst SHORT_PX = 8\n\nexport interface Presets {\n reduced: boolean\n /** Toque do botão, do polegar e dos controles: 120 ms, `ease.out`, escala 0,97. */\n press: PressPreset\n /** Alias de `press.whileTap`, o nome antigo. Sem movimento reduzido vem `undefined`. */\n tap: TargetAndTransition | undefined\n /**\n * Salto curto de escala (célula do OTP), com a transição dentro do alvo. Estável entre\n * renders; `undefined` se reduzido.\n */\n bump: TargetAndTransition | undefined\n tokens: MotionTokens\n fade: MotionPreset\n /** Alias de `open()`: escala 0,95 com mola a partir da origem, saída rápida só em opacidade. */\n scale: MotionPreset\n /**\n * Cota rara de encanto (check do passo concluído): 0,8 -> 1 com a curva back, em `slow`. Nunca\n * em controle de uso frequente.\n */\n pop: MotionPreset\n /**\n * Indicador de controle frequente (check do Checkbox, ponto do Radio): 0,9 -> 1 com opacidade\n * em `fast`, sem quique e sem partir de zero.\n */\n indicator: MotionPreset\n slide: (from: SlideFrom, distance?: SlideDistance) => MotionPreset\n /**\n * Overlay ancorado (popover, menu, modal, painel do select). Número = escala de partida\n * (padrão 0,95); `{ y }` = entrada plana, sem escala, para a superfície em tela cheia.\n * Entra em mola criticamente amortecida (sem quique) em `base` e sai em `fast`, em opacidade.\n */\n open: (from?: number | { y: number }) => MotionPreset\n /** Gaveta e folha: entram de `from` em `slow` com `ease.drawer`, saem em `fast` pelo mesmo lado. */\n sheet: (from: SlideFrom) => MotionPreset\n /** Tooltip: escala 0,97 em `fast`; aberto em `instant-open` não anima. */\n tooltip: (instant: boolean) => MotionPreset\n /**\n * Troca de conteúdo no lugar (passo do wizard), sem esperar a saída: o que sai esmaece com\n * `blur` de 2 px em `fast`; o que entra vem de `direction` (1 avança, -1 volta), 8 px, em\n * `base`. O desfoque disfarça o cruzamento: sem ele o olho vê dois objetos trocando de lugar.\n */\n swap: (direction: 1 | -1) => MotionPreset\n /**\n * Entrada de uso único (reveal do dashboard): desloca 8 px e dura `reveal.enter`, mais lenta\n * que `slide`. Não serve a interação repetida (overlay, tab, botão).\n */\n reveal: (from: SlideFrom) => MotionPreset\n /** Deslocamento na tela (indicador, reordenação): `move` em `ease.move`. */\n move: Transition\n /** Nome antigo de `move`. */\n layout: Transition\n /** Mola sem quique: onde há gesto ou soltura (drop do kanban, folha que volta). */\n settle: Transition\n /** Mola da folha depois do arraste (quique mínimo). */\n springSheet: Transition\n /**\n * A mesma mola da folha em rigidez e amortecimento (massa 1), que é o que o arraste do Motion\n * (`dragTransition`) pede para a volta à origem: rigidez = (2π / duração)², amortecimento =\n * 2 (1 - quique) raiz(rigidez).\n */\n sheetBounce: { bounceStiffness: number; bounceDamping: number }\n /** Atraso de entrada do item `index`, limitado a `limit` itens (padrão 8: 480 ms). */\n stagger: (index: number, limit?: number) => Transition\n /** Atraso do bloco `index` no reveal (passo `reveal.stagger`), limitado a `limit` blocos. */\n staggerReveal: (index: number, limit?: number) => Transition\n}\n\n/** Mola em \"duração e quique\" para rigidez e amortecimento (massa 1). */\nfunction springToBounce({ duration, bounce }: { duration: number; bounce: number }) {\n const stiffness = ((2 * Math.PI) / duration) ** 2\n return {\n bounceStiffness: Math.round(stiffness),\n bounceDamping: Math.round(2 * (1 - bounce) * Math.sqrt(stiffness)),\n }\n}\n\nexport function createPresets(tokens: MotionTokens, reduced: boolean): Presets {\n const { duration, reveal, ease } = tokens\n const base: Transition = { duration: duration.base, ease: ease.out }\n const fastOut: Transition = { duration: duration.fast, ease: ease.out }\n const settle: Transition = { type: 'spring', ...SPRING.settle }\n const enter: Transition = {\n type: 'spring',\n duration: duration.base,\n bounce: SPRING.settle.bounce,\n }\n\n /** O que sobra sob \"reduzir movimento\": só opacidade, em `base`. */\n const flat = (): MotionPreset => ({\n initial: { opacity: 0 },\n animate: { opacity: 1 },\n exit: { opacity: 0 },\n transition: base,\n })\n const make = (initial: Target, animate: Target, time: number, curve = ease.out): MotionPreset =>\n reduced\n ? flat()\n : {\n initial,\n animate,\n exit: initial,\n transition: { duration: time, ease: curve },\n }\n\n const offset = (from: SlideFrom, distance: SlideDistance): Target => {\n const far = distance === 'full' ? '100%' : SHORT_PX\n const sign = from === 'left' || from === 'top' ? -1 : 1\n const value = typeof far === 'string' ? `${sign * 100}%` : sign * far\n return from === 'left' || from === 'right' ? { x: value, opacity: 0 } : { y: value, opacity: 0 }\n }\n const settled = (initial: Target): Target => ({\n opacity: 1,\n ...(initial.x !== undefined ? { x: 0 } : {}),\n ...(initial.y !== undefined ? { y: 0 } : {}),\n })\n\n const fade: MotionPreset = reduced\n ? flat()\n : {\n initial: { opacity: 0 },\n animate: { opacity: 1 },\n exit: { opacity: 0, transition: fastOut },\n transition: base,\n }\n\n const open = (from: number | { y: number } = SCALE.enter): MotionPreset => {\n if (reduced) return flat()\n const initial: Target =\n typeof from === 'number' ? { opacity: 0, scale: from } : { opacity: 0, y: from.y }\n const to: Target = typeof from === 'number' ? { opacity: 1, scale: 1 } : { opacity: 1, y: 0 }\n return {\n initial,\n animate: { ...to, transition: enter },\n exit: { opacity: 0, transition: fastOut },\n transition: enter,\n }\n }\n\n const sheet = (from: SlideFrom): MotionPreset => {\n if (reduced) return flat()\n const sign = from === 'left' || from === 'top' ? -1 : 1\n const axis = from === 'left' || from === 'right' ? 'x' : 'y'\n const away = { [axis]: `${sign * 100}%` }\n return {\n initial: away,\n animate: { [axis]: 0 },\n exit: { ...away, transition: { duration: duration.fast, ease: ease.drawer } },\n transition: { duration: duration.slow, ease: ease.drawer },\n }\n }\n\n const tooltip = (instant: boolean): MotionPreset => {\n if (reduced) return instant ? { ...flat(), transition: { duration: 0 } } : flat()\n return {\n initial: { opacity: 0, scale: SCALE.tooltip },\n animate: { opacity: 1, scale: 1 },\n exit: { opacity: 0, transition: fastOut },\n transition: instant ? { duration: 0 } : fastOut,\n }\n }\n\n const blurred = `blur(${BLUR}px)`\n const swap = (direction: 1 | -1): MotionPreset => {\n if (reduced) return flat()\n return {\n initial: { opacity: 0, x: direction * SHORT_PX, filter: blurred },\n animate: { opacity: 1, x: 0, filter: 'blur(0px)', transition: base },\n exit: { opacity: 0, filter: blurred, transition: fastOut },\n transition: base,\n }\n }\n\n const indicatorInitial: Target = { opacity: 0, scale: SCALE.small }\n const press: PressPreset = {\n whileTap: reduced ? undefined : { scale: SCALE.press },\n transition: { duration: duration.press, ease: ease.out },\n }\n const move: Transition = reduced ? { duration: 0 } : { duration: duration.move, ease: ease.move }\n\n return {\n reduced,\n press,\n tap: press.whileTap,\n bump: reduced ? undefined : { scale: [SCALE.bump, 1], transition: fastOut },\n tokens,\n fade,\n scale: open(),\n pop: make(\n { opacity: 0, scale: SCALE.pop },\n { opacity: 1, scale: 1 },\n duration.slow,\n ease.spring,\n ),\n indicator: reduced\n ? flat()\n : {\n initial: indicatorInitial,\n animate: { opacity: 1, scale: 1 },\n exit: indicatorInitial,\n transition: fastOut,\n },\n slide: (from, distance = 'full') => {\n const initial = offset(from, distance)\n return make(initial, settled(initial), distance === 'full' ? duration.slow : duration.base)\n },\n open,\n sheet,\n tooltip,\n swap,\n reveal: (from) => {\n const initial = offset(from, 'short')\n return make(initial, settled(initial), reveal.enter)\n },\n move,\n layout: move,\n settle: reduced ? { duration: 0 } : settle,\n springSheet: reduced ? { duration: 0 } : { type: 'spring', ...SPRING.sheet },\n sheetBounce: springToBounce(SPRING.sheet),\n stagger: (index, limit = 8) => ({\n delay: reduced ? 0 : Math.min(index, limit) * (duration.fast / 2),\n }),\n staggerReveal: (index, limit = 8) => ({\n delay: reduced ? 0 : Math.min(index, limit) * reveal.stagger,\n }),\n }\n}\n\n/** Curva no formato do recharts: `cubic-bezier(a,b,c,d)`, sem espaços. */\nexport function toCubicBezier([\n a,\n b,\n c,\n d,\n]: Bezier): `cubic-bezier(${number},${number},${number},${number})` {\n return `cubic-bezier(${a},${b},${c},${d})`\n}\n\n/** Presets com os tokens lidos agora do documento. */\nexport function presetsFromDocument(reduced: boolean): Presets {\n return createPresets(readMotionTokens(), reduced)\n}\n","import { useMemo, useSyncExternalStore } from 'react'\nimport { getReducedMotion, subscribeReducedMotion } from '@/hooks/use-reduced-motion'\nimport { useMotionMode } from './motion-context'\nimport { createPresets, presetsFromDocument, type Presets } from './presets'\nimport { DURATION, EASE, REVEAL } from './tokens'\n\n/** Em `off` ninguém lê o documento nem assina o matchMedia: um objeto único e inerte. */\nconst OFF_PRESETS = createPresets({ duration: DURATION, reveal: REVEAL, ease: EASE }, false)\nconst noSubscribe = () => () => {}\nconst never = () => false\n\n/**\n * Presets do motion para o componente. A preferência \"reduzir movimento\" vem do mesmo\n * `matchMedia` do hook do projeto (`use-reduced-motion.ts`: Spinner, Progress), a fonte única,\n * reativa e testável, sem `MotionConfig reducedMotion` somando por cima. Só em `on` a\n * preferência é assinada e os tokens lidos do documento; em `off` o custo é zero.\n */\nexport function useMotionPresets(): Presets {\n const on = useMotionMode() === 'on'\n const reduced = useSyncExternalStore(\n on ? subscribeReducedMotion : noSubscribe,\n on ? getReducedMotion : never,\n never,\n )\n return useMemo(() => (on ? presetsFromDocument(reduced) : OFF_PRESETS), [on, reduced])\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-motion-presets-I4StrsCi.js","names":[],"sources":["../src/lib/motion/tokens.ts","../src/lib/motion/presets.ts","../src/lib/motion/use-motion-presets.ts"],"sourcesContent":["/*\n * Durações e curvas do motion (linguagem única, web e app). A fonte é o globals.css:\n * --rendra-duration-* bloco :root fora de camada (vai para o dist/tokens.css do pacote);\n * --rendra-ease-* no mesmo bloco, então o host as sobrescreve; o @theme guarda os nomes\n * do Tailwind (--ease-out, --ease-move...) como alias delas.\n * As constantes daqui são a reserva em tempo de execução (SSR, variável ausente ou inválida), e\n * tokens.test.ts confere que elas batem com o globals.css. Valores em segundos e vetores de 4\n * números, o formato que o Motion aceita.\n */\n\nexport type Bezier = [number, number, number, number]\n\n/**\n * Reserva das durações, em segundos (SSR, ou variável ausente).\n * `press` e `fast` valem o mesmo (120 ms) com propósitos diferentes: o toque e a saída de overlay.\n */\nexport const DURATION = {\n press: 0.12,\n hover: 0.15,\n fast: 0.12,\n base: 0.2,\n move: 0.25,\n slow: 0.32,\n draw: 0.42,\n pulse: 1,\n}\nexport type DurationName = keyof typeof DURATION\n\n/**\n * Reveal: entrada de uso único (dashboard: bloco, cascata, contador e desenho do gráfico), mais\n * lenta que as interações do dia a dia. Reserva em segundos (SSR, ou variável ausente).\n */\nexport const REVEAL = { enter: 0.6, stagger: 0.12, count: 1.2, draw: 0.9 }\nexport type RevealName = keyof typeof REVEAL\n\n/**\n * Curvas do globals.css (`--rendra-ease-*`). `spring` é a curva \"back\" (quique): só para a cota\n * rara de encanto. `move` desloca na tela; `drawer` é a curva de gaveta e folha.\n */\nexport const EASE: Record<'out' | 'inOut' | 'spring' | 'move' | 'drawer', Bezier> = {\n out: [0.22, 1, 0.36, 1],\n inOut: [0.65, 0, 0.35, 1],\n spring: [0.34, 1.56, 0.64, 1],\n move: [0.77, 0, 0.175, 1],\n drawer: [0.32, 0.72, 0, 1],\n}\nexport type EaseName = keyof typeof EASE\n\n/** Nome da variável CSS de cada curva (`inOut` vira `in-out`). */\nconst EASE_VAR: Record<EaseName, string> = {\n out: 'out',\n inOut: 'in-out',\n spring: 'spring',\n move: 'move',\n drawer: 'drawer',\n}\n\n/**\n * Molas no formato \"duração e quique\" (Motion). `settle` assenta sem passar do ponto (layout,\n * overlay que entra, soltura do arraste); `sheet` é a folha depois do gesto, com quique mínimo.\n * Mola não é variável CSS: mora aqui, e o app a espelha em `dampingRatio`.\n */\nexport const SPRING = {\n settle: { duration: 0.4, bounce: 0 },\n sheet: { duration: 0.3, bounce: 0.2 },\n}\n\n/** Escalas da linguagem: entrada de overlay, tooltip, ponto pequeno, toque, pop e salto curto. */\nexport const SCALE = { enter: 0.95, tooltip: 0.97, small: 0.9, press: 0.97, pop: 0.8, bump: 1.08 }\n\n/** Desfoque (px) que disfarça o cruzamento entre dois estados (troca de passo). Abaixo de 20. */\nexport const BLUR = 2\n\nexport interface MotionTokens {\n duration: Record<DurationName, number>\n reveal: Record<RevealName, number>\n ease: Record<EaseName, Bezier>\n}\n\nfunction toSeconds(value: string): number | null {\n const v = value.trim()\n const n = parseFloat(v)\n if (!Number.isFinite(n)) return null\n if (v.endsWith('ms')) return n / 1000\n if (v.endsWith('s')) return n\n return null\n}\n\n/** `cubic-bezier(a, b, c, d)` em vetor; qualquer outra coisa (`ease-in`, vazio) vira `null`. */\nfunction toBezier(value: string): Bezier | null {\n const m = /^cubic-bezier\\(([^)]+)\\)$/.exec(value.trim())\n if (!m) return null\n const parts = m[1]!.split(',').map((n) => parseFloat(n))\n if (parts.length !== 4 || parts.some((n) => !Number.isFinite(n))) return null\n return parts as Bezier\n}\n\n/** Lê as durações e as curvas do documento; o que faltar (ou sem window) vem da reserva. */\nexport function readMotionTokens(): MotionTokens {\n const duration = { ...DURATION }\n const reveal = { ...REVEAL }\n const ease = { ...EASE }\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n const style = getComputedStyle(document.documentElement)\n for (const name of Object.keys(DURATION) as DurationName[]) {\n const read = toSeconds(style.getPropertyValue(`--rendra-duration-${name}`))\n if (read !== null) duration[name] = read\n }\n for (const name of Object.keys(REVEAL) as RevealName[]) {\n const read = toSeconds(style.getPropertyValue(`--rendra-reveal-${name}`))\n if (read !== null) reveal[name] = read\n }\n for (const name of Object.keys(EASE) as EaseName[]) {\n const read = toBezier(style.getPropertyValue(`--rendra-ease-${EASE_VAR[name]}`))\n if (read !== null) ease[name] = read\n }\n }\n return { duration, reveal, ease }\n}\n","import type { Target, TargetAndTransition, Transition } from 'motion/react'\nimport { BLUR, readMotionTokens, SCALE, SPRING, type Bezier, type MotionTokens } from './tokens'\n\n/*\n * Presets do caminho `on` (linguagem única de movimento): fade, scale/open, sheet, tooltip,\n * indicator, pop, slide, reveal, press, move, settle e stagger. Toda duração e toda curva vêm de\n * readMotionTokens (globals.css); nenhum número de duração mora neste arquivo (o presets.test.ts\n * varre o código-fonte atrás de literal). As molas e as escalas vêm de tokens.ts.\n *\n * Duas regras moram aqui:\n * - Assimetria: o que o usuário decidiu (abrir) entra no tempo `base`, e o que o sistema\n * responde ao fechar sai em `fast`, só em opacidade. Gaveta e folha saem em `base`, de volta\n * pelo lado de onde vieram.\n * - Reduzido: sem deslocamento, escala, filtro nem cascata; a opacidade usa `base` (não zero),\n * porque o esmaecimento é o que explica a mudança de estado.\n */\n\nexport interface MotionPreset {\n initial: Target\n animate: TargetAndTransition\n exit: TargetAndTransition\n transition: Transition\n}\n\n/** Toque: o alvo do `whileTap` (`undefined` no reduzido) e a transição de ida e de volta. */\nexport interface PressPreset {\n whileTap: TargetAndTransition | undefined\n transition: Transition\n}\n\nexport type SlideFrom = 'left' | 'right' | 'top' | 'bottom'\n\n/** Distância do slide: `full` (painel que entra da borda) ou `short` (conteúdo que assenta). */\nexport type SlideDistance = 'full' | 'short'\n\nconst SHORT_PX = 8\n\nexport interface Presets {\n reduced: boolean\n /** Toque do botão, do polegar e dos controles: 120 ms, `ease.out`, escala 0,97. */\n press: PressPreset\n /** Alias de `press.whileTap`, o nome antigo. Sem movimento reduzido vem `undefined`. */\n tap: TargetAndTransition | undefined\n /**\n * Salto curto de escala (célula do OTP), com a transição dentro do alvo. Estável entre\n * renders; `undefined` se reduzido.\n */\n bump: TargetAndTransition | undefined\n tokens: MotionTokens\n fade: MotionPreset\n /** Alias de `open()`: escala 0,95 com mola a partir da origem, saída rápida só em opacidade. */\n scale: MotionPreset\n /**\n * Cota rara de encanto (check do passo concluído): 0,8 -> 1 com a curva back, em `slow`. Nunca\n * em controle de uso frequente.\n */\n pop: MotionPreset\n /**\n * Indicador de controle frequente (check do Checkbox, ponto do Radio): 0,9 -> 1 com opacidade\n * em `fast`, sem quique e sem partir de zero.\n */\n indicator: MotionPreset\n slide: (from: SlideFrom, distance?: SlideDistance) => MotionPreset\n /**\n * Overlay ancorado (popover, menu, modal, painel do select). Número = escala de partida\n * (padrão 0,95); `{ y }` = entrada plana, sem escala, para a superfície em tela cheia.\n * Entra em mola criticamente amortecida (sem quique) em `base` e sai em `fast`, em opacidade.\n */\n open: (from?: number | { y: number }) => MotionPreset\n /** Gaveta e folha: entram de `from` em `slow` com `ease.drawer`, saem em `fast` pelo mesmo lado. */\n sheet: (from: SlideFrom) => MotionPreset\n /** Tooltip: escala 0,97 em `fast`; aberto em `instant-open` não anima. */\n tooltip: (instant: boolean) => MotionPreset\n /**\n * Troca de conteúdo no lugar (passo do wizard), sem esperar a saída: o que sai esmaece com\n * `blur` de 2 px em `fast`; o que entra vem de `direction` (1 avança, -1 volta), 8 px, em\n * `base`. O desfoque disfarça o cruzamento: sem ele o olho vê dois objetos trocando de lugar.\n */\n swap: (direction: 1 | -1) => MotionPreset\n /**\n * Entrada de uso único (reveal do dashboard): desloca 8 px e dura `reveal.enter`, mais lenta\n * que `slide`. Não serve a interação repetida (overlay, tab, botão).\n */\n reveal: (from: SlideFrom) => MotionPreset\n /** Deslocamento na tela (indicador, reordenação): `move` em `ease.move`. */\n move: Transition\n /** Nome antigo de `move`. */\n layout: Transition\n /** Mola sem quique: onde há gesto ou soltura (drop do kanban, folha que volta). */\n settle: Transition\n /** Mola da folha depois do arraste (quique mínimo). */\n springSheet: Transition\n /**\n * A mesma mola da folha em rigidez e amortecimento (massa 1), que é o que o arraste do Motion\n * (`dragTransition`) pede para a volta à origem: rigidez = (2π / duração)², amortecimento =\n * 2 (1 - quique) raiz(rigidez).\n */\n sheetBounce: { bounceStiffness: number; bounceDamping: number }\n /** Atraso de entrada do item `index`, limitado a `limit` itens (padrão 8: 480 ms). */\n stagger: (index: number, limit?: number) => Transition\n /** Atraso do bloco `index` no reveal (passo `reveal.stagger`), limitado a `limit` blocos. */\n staggerReveal: (index: number, limit?: number) => Transition\n}\n\n/** Mola em \"duração e quique\" para rigidez e amortecimento (massa 1). */\nfunction springToBounce({ duration, bounce }: { duration: number; bounce: number }) {\n const stiffness = ((2 * Math.PI) / duration) ** 2\n return {\n bounceStiffness: Math.round(stiffness),\n bounceDamping: Math.round(2 * (1 - bounce) * Math.sqrt(stiffness)),\n }\n}\n\nexport function createPresets(tokens: MotionTokens, reduced: boolean): Presets {\n const { duration, reveal, ease } = tokens\n const base: Transition = { duration: duration.base, ease: ease.out }\n const fastOut: Transition = { duration: duration.fast, ease: ease.out }\n const settle: Transition = { type: 'spring', ...SPRING.settle }\n const enter: Transition = {\n type: 'spring',\n duration: duration.base,\n bounce: SPRING.settle.bounce,\n }\n\n /** O que sobra sob \"reduzir movimento\": só opacidade, em `base`. */\n const flat = (): MotionPreset => ({\n initial: { opacity: 0 },\n animate: { opacity: 1 },\n exit: { opacity: 0 },\n transition: base,\n })\n const make = (initial: Target, animate: Target, time: number, curve = ease.out): MotionPreset =>\n reduced\n ? flat()\n : {\n initial,\n animate,\n exit: initial,\n transition: { duration: time, ease: curve },\n }\n\n const offset = (from: SlideFrom, distance: SlideDistance): Target => {\n const far = distance === 'full' ? '100%' : SHORT_PX\n const sign = from === 'left' || from === 'top' ? -1 : 1\n const value = typeof far === 'string' ? `${sign * 100}%` : sign * far\n return from === 'left' || from === 'right' ? { x: value, opacity: 0 } : { y: value, opacity: 0 }\n }\n const settled = (initial: Target): Target => ({\n opacity: 1,\n ...(initial.x !== undefined ? { x: 0 } : {}),\n ...(initial.y !== undefined ? { y: 0 } : {}),\n })\n\n const fade: MotionPreset = reduced\n ? flat()\n : {\n initial: { opacity: 0 },\n animate: { opacity: 1 },\n exit: { opacity: 0, transition: fastOut },\n transition: base,\n }\n\n const open = (from: number | { y: number } = SCALE.enter): MotionPreset => {\n if (reduced) return flat()\n const initial: Target =\n typeof from === 'number' ? { opacity: 0, scale: from } : { opacity: 0, y: from.y }\n const to: Target = typeof from === 'number' ? { opacity: 1, scale: 1 } : { opacity: 1, y: 0 }\n return {\n initial,\n animate: { ...to, transition: enter },\n exit: { opacity: 0, transition: fastOut },\n transition: enter,\n }\n }\n\n const sheet = (from: SlideFrom): MotionPreset => {\n if (reduced) return flat()\n const sign = from === 'left' || from === 'top' ? -1 : 1\n const axis = from === 'left' || from === 'right' ? 'x' : 'y'\n const away = { [axis]: `${sign * 100}%` }\n return {\n initial: away,\n animate: { [axis]: 0 },\n exit: { ...away, transition: { duration: duration.fast, ease: ease.drawer } },\n transition: { duration: duration.slow, ease: ease.drawer },\n }\n }\n\n const tooltip = (instant: boolean): MotionPreset => {\n if (reduced) return instant ? { ...flat(), transition: { duration: 0 } } : flat()\n return {\n initial: { opacity: 0, scale: SCALE.tooltip },\n animate: { opacity: 1, scale: 1 },\n exit: { opacity: 0, transition: fastOut },\n transition: instant ? { duration: 0 } : fastOut,\n }\n }\n\n const blurred = `blur(${BLUR}px)`\n const swap = (direction: 1 | -1): MotionPreset => {\n if (reduced) return flat()\n return {\n initial: { opacity: 0, x: direction * SHORT_PX, filter: blurred },\n animate: { opacity: 1, x: 0, filter: 'blur(0px)', transition: base },\n exit: { opacity: 0, filter: blurred, transition: fastOut },\n transition: base,\n }\n }\n\n const indicatorInitial: Target = { opacity: 0, scale: SCALE.small }\n const press: PressPreset = {\n whileTap: reduced ? undefined : { scale: SCALE.press },\n transition: { duration: duration.press, ease: ease.out },\n }\n const move: Transition = reduced ? { duration: 0 } : { duration: duration.move, ease: ease.move }\n\n return {\n reduced,\n press,\n tap: press.whileTap,\n bump: reduced ? undefined : { scale: [SCALE.bump, 1], transition: fastOut },\n tokens,\n fade,\n scale: open(),\n pop: make(\n { opacity: 0, scale: SCALE.pop },\n { opacity: 1, scale: 1 },\n duration.slow,\n ease.spring,\n ),\n indicator: reduced\n ? flat()\n : {\n initial: indicatorInitial,\n animate: { opacity: 1, scale: 1 },\n exit: indicatorInitial,\n transition: fastOut,\n },\n slide: (from, distance = 'full') => {\n const initial = offset(from, distance)\n return make(initial, settled(initial), distance === 'full' ? duration.slow : duration.base)\n },\n open,\n sheet,\n tooltip,\n swap,\n reveal: (from) => {\n const initial = offset(from, 'short')\n return make(initial, settled(initial), reveal.enter)\n },\n move,\n layout: move,\n settle: reduced ? { duration: 0 } : settle,\n springSheet: reduced ? { duration: 0 } : { type: 'spring', ...SPRING.sheet },\n sheetBounce: springToBounce(SPRING.sheet),\n stagger: (index, limit = 8) => ({\n delay: reduced ? 0 : Math.min(index, limit) * (duration.fast / 2),\n }),\n staggerReveal: (index, limit = 8) => ({\n delay: reduced ? 0 : Math.min(index, limit) * reveal.stagger,\n }),\n }\n}\n\n/** Curva no formato do recharts: `cubic-bezier(a,b,c,d)`, sem espaços. */\nexport function toCubicBezier([\n a,\n b,\n c,\n d,\n]: Bezier): `cubic-bezier(${number},${number},${number},${number})` {\n return `cubic-bezier(${a},${b},${c},${d})`\n}\n\n/** Presets com os tokens lidos agora do documento. */\nexport function presetsFromDocument(reduced: boolean): Presets {\n return createPresets(readMotionTokens(), reduced)\n}\n","import { useMemo, useSyncExternalStore } from 'react'\nimport { getReducedMotion, subscribeReducedMotion } from '@/hooks/use-reduced-motion'\nimport { useMotionMode } from './motion-context'\nimport { createPresets, presetsFromDocument, type Presets } from './presets'\nimport { DURATION, EASE, REVEAL } from './tokens'\n\n/** Em `off` ninguém lê o documento nem assina o matchMedia: um objeto único e inerte. */\nconst OFF_PRESETS = createPresets({ duration: DURATION, reveal: REVEAL, ease: EASE }, false)\nconst noSubscribe = () => () => {}\nconst never = () => false\n\n/**\n * Presets do motion para o componente. A preferência \"reduzir movimento\" vem do mesmo\n * `matchMedia` do hook do projeto (`use-reduced-motion.ts`: Spinner, Progress), a fonte única,\n * reativa e testável, sem `MotionConfig reducedMotion` somando por cima. Só em `on` a\n * preferência é assinada e os tokens lidos do documento; em `off` o custo é zero.\n */\nexport function useMotionPresets(): Presets {\n const on = useMotionMode() === 'on'\n const reduced = useSyncExternalStore(\n on ? subscribeReducedMotion : noSubscribe,\n on ? getReducedMotion : never,\n never,\n )\n return useMemo(() => (on ? presetsFromDocument(reduced) : OFF_PRESETS), [on, reduced])\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- /*! Rendra Design System v2.7.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
- import { t as cn } from "./cn-B0N3Pek0.js";
1
+ /*! Rendra Design System v2.8.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
+ import { t as cn } from "./cn-BlJHpkDs.js";
3
3
  import { GripVertical } from "lucide-react";
4
4
  import { useMemo, useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rendra-ui/web",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "type": "module",
5
5
  "description": "Rendra, design system e boilerplate React (Vite, TypeScript, Tailwind v4, Radix), com CLI de catálogo, auditoria e troca de variante.",
6
6
  "author": {
@@ -127,6 +127,7 @@
127
127
  "test:motion": "playwright test --project=motion --project=estados",
128
128
  "test:lazy": "playwright test --project=lazy",
129
129
  "test:flow": "playwright test --project=flow",
130
+ "test:kanban": "playwright test --project=kanban",
130
131
  "test:css-layers": "playwright test --project=css-layers",
131
132
  "test:site": "playwright test -c playwright.site.config.ts",
132
133
  "registry:build": "node scripts/build-registry.mjs",
@@ -1 +0,0 @@
1
- {"version":3,"file":"components-CpQPMGfT.js","names":[],"sources":["../src/catalog/components.ts"],"sourcesContent":["/**\n * Catálogo de códigos de componente (etapa 1.2.0-alpha.1 do plano da v2).\n *\n * Cada componente de `src/components/ui` (menos os internos `overlay-shell` e\n * `picker-panel`, e menos os arquivos de teste) tem ao menos um código aqui. Uma variante\n * visual relevante (a prop que muda o formato do componente, não tom nem tamanho) ganha o\n * seu próprio código, numerado 001, 002... na ordem em que aparece neste arquivo.\n *\n * O código é o que o cliente escolhe no `docs/BRIEFING_MODELO.md` (\"Componentes e\n * variantes\") e o que aparece na vitrine (`/componentes`), no `data-rendra` do elemento\n * raiz de cada componente e no `registry.json` (`meta.codes`).\n *\n * Formato: `^[A-Z]{3,4}-\\d{3}$` (ex.: \"ABA-001\", \"BTN-006\"). Nunca editar um código depois\n * de publicado: ele é o identificador estável de uma variante.\n */\n\nexport interface ComponentCatalogEntry {\n /** Formato ^[A-Z]{3,4}-\\d{3}$, ex.: \"ABA-001\". Único no catálogo inteiro. */\n code: string\n /** Nome em português do Brasil, ex.: \"Abas em linha\". */\n name: string\n /** Nome do componente React, ex.: \"Tabs\". */\n component: string\n /** Caminho relativo a partir de src/, ex.: \"components/ui/tabs.tsx\". */\n file: string\n /** Props (nome: valor) que definem esta variante especificamente. */\n variantProps: Record<string, string | number | boolean>\n /** Frase curta de quando usar esta variante, para o BRIEFING_MODELO. */\n whenToUse: string\n /**\n * Esta é a variante que o componente usa quando a prop não é passada (o valor padrão de\n * `variantProps` no próprio componente React, ex.: `variant = 'line'` em `tabs.tsx`)? No\n * máximo uma por componente (nenhuma, para o componente sem variante ou sem um padrão real,\n * como `Chart`, cuja prop `type` é obrigatória); um componente com mais de uma variante tem\n * exatamente uma marcada `true` (teste de integridade, `assertCatalogIntegrity`). Usada por\n * `rendra trocar`: um elemento sem a prop conta como esta variante, e trocar para uma\n * variante `isDefault` remove a prop em vez de escrever o valor por extenso.\n */\n isDefault?: true\n}\n\n/** Formato do código: de 3 a 4 letras maiúsculas, hífen, três dígitos. */\nexport const COMPONENT_CODE_PATTERN = /^[A-Z]{3,4}-\\d{3}$/\n\n/**\n * Arquivos de `src/components/ui` que não entram no catálogo: são peças internas, sem uso\n * direto em tela (nunca aparecem sozinhos numa tela, só dentro de outro componente).\n */\nexport const CATALOG_EXCLUDED_FILES = [\n 'components/ui/overlay-shell.tsx',\n 'components/ui/picker-panel.tsx',\n 'components/ui/sortable-handle.tsx',\n]\n\nexport const CATALOG: ComponentCatalogEntry[] = [\n // ---------------------------------------------------------------- accordion\n {\n code: 'ACRN-001',\n name: 'Acordeão',\n component: 'Accordion',\n file: 'components/ui/accordion.tsx',\n variantProps: {},\n whenToUse: 'Para agrupar conteúdo que a pessoa abre um de cada vez, como perguntas frequentes.',\n },\n // ---------------------------------------------------------------- action-bar\n {\n code: 'ACB-001',\n name: 'Barra de ação',\n component: 'ActionBar',\n file: 'components/ui/action-bar.tsx',\n variantProps: {},\n whenToUse:\n 'Para os botões de salvar, cancelar e ações extras de um formulário, drawer ou modal.',\n },\n // ---------------------------------------------------------------- alert\n {\n code: 'ALRT-001',\n name: 'Alerta',\n component: 'Alert',\n file: 'components/ui/alert.tsx',\n variantProps: {},\n whenToUse: 'Para um aviso de sucesso, erro, atenção ou informação dentro do corpo da tela.',\n },\n // ---------------------------------------------------------------- avatar\n {\n code: 'AVT-001',\n name: 'Avatar',\n component: 'Avatar',\n file: 'components/ui/avatar.tsx',\n variantProps: {},\n whenToUse: 'Para a foto ou as iniciais de uma pessoa.',\n },\n {\n code: 'AVT-002',\n name: 'Avatar em grupo',\n component: 'AvatarGroup',\n file: 'components/ui/avatar.tsx',\n variantProps: {},\n whenToUse: 'Para mostrar várias pessoas sobrepostas, com contador do excedente.',\n },\n // ---------------------------------------------------------------- badge\n {\n code: 'BDG-001',\n name: 'Selo',\n component: 'Badge',\n file: 'components/ui/badge.tsx',\n variantProps: {},\n whenToUse: 'Para marcar situação, categoria ou contagem curta ao lado de um texto.',\n },\n // ---------------------------------------------------------------- brand-feedback-icon\n {\n code: 'BFI-001',\n name: 'Ícone de feedback da marca',\n component: 'BrandFeedbackIcon',\n file: 'components/ui/brand-feedback-icon.tsx',\n variantProps: {},\n whenToUse:\n 'Para o símbolo da marca tingido pela cor semântica em toast, alerta e telas de status.',\n },\n // ---------------------------------------------------------------- brand-logo\n {\n code: 'LOGO-001',\n name: 'Logotipo',\n component: 'BrandLogo',\n file: 'components/ui/brand-logo.tsx',\n variantProps: {},\n whenToUse: 'Para o logotipo da marca na sidebar, no header ou no painel do login.',\n },\n // ---------------------------------------------------------------- breadcrumb\n {\n code: 'BRD-001',\n name: 'Trilha responsiva',\n component: 'Breadcrumb',\n file: 'components/ui/breadcrumb.tsx',\n variantProps: { variant: 'responsive' },\n whenToUse: 'Dentro do corpo da página: trilha no desktop e botão voltar no celular.',\n isDefault: true,\n },\n {\n code: 'BRD-002',\n name: 'Trilha em texto',\n component: 'Breadcrumb',\n file: 'components/ui/breadcrumb.tsx',\n variantProps: { variant: 'trail' },\n whenToUse: 'No header do AppShell, abaixo do título, sempre em texto pequeno.',\n },\n // ---------------------------------------------------------------- button\n {\n code: 'BTN-001',\n name: 'Botão primário',\n component: 'Button',\n file: 'components/ui/button.tsx',\n variantProps: { variant: 'primary' },\n whenToUse: 'Para a ação principal da tela, do formulário ou da barra de ações.',\n isDefault: true,\n },\n {\n code: 'BTN-002',\n name: 'Botão secundário',\n component: 'Button',\n file: 'components/ui/button.tsx',\n variantProps: { variant: 'secondary' },\n whenToUse:\n 'Para uma segunda cor de destaque da marca, quando a primária já está em uso na tela.',\n },\n {\n code: 'BTN-003',\n name: 'Botão contornado',\n component: 'Button',\n file: 'components/ui/button.tsx',\n variantProps: { variant: 'outline' },\n whenToUse: 'Para a ação de cancelar ou para ações secundárias ao lado de um botão primário.',\n },\n {\n code: 'BTN-004',\n name: 'Botão fantasma',\n component: 'Button',\n file: 'components/ui/button.tsx',\n variantProps: { variant: 'ghost' },\n whenToUse: 'Para ações discretas dentro de cards, linhas de tabela e barras de ferramenta.',\n },\n {\n code: 'BTN-005',\n name: 'Botão destrutivo',\n component: 'Button',\n file: 'components/ui/button.tsx',\n variantProps: { variant: 'destructive' },\n whenToUse: 'Para uma ação irreversível, como excluir ou encerrar.',\n },\n {\n code: 'BTN-006',\n name: 'Botão link',\n component: 'Button',\n file: 'components/ui/button.tsx',\n variantProps: { variant: 'link' },\n whenToUse: 'Para uma ação com aparência de link de texto, dentro de uma frase ou de um rodapé.',\n },\n // ---------------------------------------------------------------- button-group\n {\n code: 'BTNG-001',\n name: 'Grupo de botões',\n component: 'ButtonGroup',\n file: 'components/ui/button-group.tsx',\n variantProps: { orientation: 'horizontal' },\n whenToUse: 'Para botões encostados ou um controle segmentado de escolha única.',\n isDefault: true,\n },\n {\n code: 'BTNG-002',\n name: 'Grupo de botões vertical',\n component: 'ButtonGroup',\n file: 'components/ui/button-group.tsx',\n variantProps: { orientation: 'vertical' },\n whenToUse: 'Para botões de ação empilhados, na largura do grupo, com as bordas unidas.',\n },\n {\n code: 'BTNG-003',\n name: 'Grupo de botões responsivo',\n component: 'ButtonGroup',\n file: 'components/ui/button-group.tsx',\n variantProps: { orientation: 'responsive' },\n whenToUse: 'Para botões que empilham no celular e ficam lado a lado a partir do tablet.',\n },\n // ---------------------------------------------------------------- calendar\n {\n code: 'CAL-001',\n name: 'Calendário',\n component: 'Calendar',\n file: 'components/ui/calendar.tsx',\n variantProps: {},\n whenToUse: 'Para agenda com visão de mês, semana, dia ou lista de eventos.',\n },\n // ---------------------------------------------------------------- card\n {\n code: 'CARD-001',\n name: 'Card',\n component: 'Card',\n file: 'components/ui/card.tsx',\n variantProps: {},\n whenToUse: 'Para agrupar conteúdo de página com borda e sem sombra pesada.',\n },\n // ---------------------------------------------------------------- chart\n {\n code: 'CHT-001',\n name: 'Gráfico de linha',\n component: 'Chart',\n file: 'components/ui/chart.tsx',\n variantProps: { type: 'line' },\n whenToUse: 'Para mostrar a evolução de um valor ao longo do tempo.',\n // A prop `type` do Chart é obrigatória (sem valor padrão no componente): marcado aqui só\n // para satisfazer o teste de integridade (um padrão por componente com mais de uma\n // variante); \"rendra trocar\" nunca encontra um <Chart> sem `type`, porque não compila.\n isDefault: true,\n },\n {\n code: 'CHT-002',\n name: 'Gráfico de barras',\n component: 'Chart',\n file: 'components/ui/chart.tsx',\n variantProps: { type: 'bar' },\n whenToUse: 'Para comparar valores entre categorias.',\n },\n {\n code: 'CHT-003',\n name: 'Gráfico de área',\n component: 'Chart',\n file: 'components/ui/chart.tsx',\n variantProps: { type: 'area' },\n whenToUse: 'Para mostrar volume acumulado ao longo do tempo.',\n },\n {\n code: 'CHT-004',\n name: 'Gráfico de pizza',\n component: 'Chart',\n file: 'components/ui/chart.tsx',\n variantProps: { type: 'pie' },\n whenToUse: 'Para mostrar a proporção de poucas categorias dentro de um total.',\n },\n {\n code: 'CHT-005',\n name: 'Gráfico combinado',\n component: 'Chart',\n file: 'components/ui/chart.tsx',\n variantProps: { type: 'combo' },\n whenToUse: 'Para juntar barras e linha no mesmo gráfico, como receita e meta.',\n },\n {\n code: 'CHT-006',\n name: 'Velocímetro de meta',\n component: 'Chart',\n file: 'components/ui/chart.tsx',\n variantProps: { type: 'gauge' },\n whenToUse: 'Para o percentual de uma meta batida, com faixas de cor.',\n },\n {\n code: 'CHT-007',\n name: 'Funil',\n component: 'Chart',\n file: 'components/ui/chart.tsx',\n variantProps: { type: 'funnel' },\n whenToUse: 'Para etapas que afunilam, com a conversão entre elas.',\n },\n // ---------------------------------------------------------------- chat\n {\n code: 'CHAT-001',\n name: 'Lista de conversas',\n component: 'ConversationList',\n file: 'components/ui/chat.tsx',\n variantProps: {},\n whenToUse: 'Para a coluna de conversas do atendimento.',\n },\n {\n code: 'CHAT-002',\n name: 'Linha do tempo da conversa',\n component: 'ChatThread',\n file: 'components/ui/chat.tsx',\n variantProps: {},\n whenToUse: 'Para o histórico de mensagens de uma conversa aberta.',\n },\n {\n code: 'CHAT-003',\n name: 'Campo de mensagem',\n component: 'ChatComposer',\n file: 'components/ui/chat.tsx',\n variantProps: {},\n whenToUse: 'Para escrever, anexar e enviar uma mensagem no atendimento.',\n },\n // ---------------------------------------------------------------- checkbox\n {\n code: 'CHK-001',\n name: 'Caixa de seleção',\n component: 'Checkbox',\n file: 'components/ui/checkbox.tsx',\n variantProps: {},\n whenToUse: 'Para uma escolha independente, ligada ou desligada (inclusive indeterminada).',\n },\n {\n code: 'CHK-002',\n name: 'Grupo de caixas de seleção',\n component: 'CheckboxGroup',\n file: 'components/ui/checkbox.tsx',\n variantProps: {},\n whenToUse: 'Para uma lista de opções fixas com \"selecionar todos\".',\n },\n // ---------------------------------------------------------------- checklist\n {\n code: 'CKLT-001',\n name: 'Lista de verificação',\n component: 'Checklist',\n file: 'components/ui/checklist.tsx',\n variantProps: {},\n whenToUse:\n 'Para uma lista de itens que a pessoa cria, renomeia, marca e remove, tudo por teclado.',\n },\n // ---------------------------------------------------------------- color-picker\n {\n code: 'COR-001',\n name: 'Seletor de cor',\n component: 'ColorPicker',\n file: 'components/ui/color-picker.tsx',\n variantProps: {},\n whenToUse: 'Para escolher uma cor entre amostras da marca ou uma cor livre por hexadecimal.',\n },\n // ---------------------------------------------------------------- data-toolbar\n {\n code: 'DTB-001',\n name: 'Barra de ferramentas da listagem',\n component: 'DataToolbar',\n file: 'components/ui/data-toolbar.tsx',\n variantProps: {},\n whenToUse: 'Para busca, filtros, colunas e a ação Novo, sempre dentro do card da tabela.',\n },\n // ---------------------------------------------------------------- date-picker\n {\n code: 'DTP-001',\n name: 'Seletor de data',\n component: 'DatePicker',\n file: 'components/ui/date-picker.tsx',\n variantProps: {},\n whenToUse: 'Para escolher uma data, um período ou um horário.',\n },\n // ---------------------------------------------------------------- document-viewer\n {\n code: 'DOC-001',\n name: 'Visualizador de documentos',\n component: 'DocumentViewer',\n file: 'components/ui/document-viewer.tsx',\n variantProps: {},\n whenToUse: 'Para abrir um PDF (contrato, nota fiscal, comprovante) sem sair da tela.',\n },\n // ---------------------------------------------------------------- drawer\n {\n code: 'GAV-001',\n name: 'Gaveta',\n component: 'Drawer',\n file: 'components/ui/drawer.tsx',\n variantProps: {},\n whenToUse: 'Para formulário ou detalhe de volume médio, até cerca de 12 campos.',\n },\n // ---------------------------------------------------------------- dropdown-menu\n {\n code: 'DDM-001',\n name: 'Menu suspenso',\n component: 'DropdownMenuContent',\n file: 'components/ui/dropdown-menu.tsx',\n variantProps: {},\n whenToUse: 'Para uma lista de ações ou opções que abre a partir de um botão ou de um item.',\n },\n // ---------------------------------------------------------------- empty-state\n {\n code: 'VAZ-001',\n name: 'Estado vazio',\n component: 'EmptyState',\n file: 'components/ui/empty-state.tsx',\n variantProps: {},\n whenToUse: 'Para quando uma lista, busca ou seção não tem nenhum dado ainda.',\n },\n // ---------------------------------------------------------------- error-page\n {\n code: 'ERRO-001',\n name: 'Tela de erro',\n component: 'ErrorPage',\n file: 'components/ui/error-page.tsx',\n variantProps: {},\n whenToUse: 'Para página não encontrada (404) ou falha do lado do servidor (500).',\n },\n // ---------------------------------------------------------------- field\n {\n code: 'FLD-001',\n name: 'Campo com rótulo e ajuda',\n component: 'Field',\n file: 'components/ui/field.tsx',\n variantProps: {},\n whenToUse: 'Para envolver qualquer controle de formulário com rótulo, ajuda e erro.',\n },\n {\n code: 'FLD-002',\n name: 'Rótulo',\n component: 'Label',\n file: 'components/ui/field.tsx',\n variantProps: {},\n whenToUse: 'Para um rótulo avulso, quando o Field completo não se aplica.',\n },\n // ---------------------------------------------------------------- form\n {\n code: 'FORM-001',\n name: 'Formulário',\n component: 'Form',\n file: 'components/ui/form.tsx',\n variantProps: {},\n whenToUse: 'Para envolver um formulário inteiro, ligado ao React Hook Form.',\n },\n {\n code: 'FORM-002',\n name: 'Seção de formulário',\n component: 'FormSection',\n file: 'components/ui/form.tsx',\n variantProps: {},\n whenToUse: 'Para agrupar campos relacionados dentro de um card com título.',\n },\n // ---------------------------------------------------------------- image-cropper\n {\n code: 'CROP-001',\n name: 'Recorte de imagem',\n component: 'ImageCropper',\n file: 'components/ui/image-cropper.tsx',\n variantProps: {},\n whenToUse:\n 'Para recortar uma imagem numa proporção fixa antes de enviar (foto de perfil, capa).',\n },\n // ---------------------------------------------------------------- image-viewer\n {\n code: 'IMG-001',\n name: 'Visualizador de imagens',\n component: 'ImageViewer',\n file: 'components/ui/image-viewer.tsx',\n variantProps: {},\n whenToUse: 'Para abrir uma ou mais imagens em tela cheia, com legenda e navegação.',\n },\n // ---------------------------------------------------------------- info-hint\n {\n code: 'INFO-001',\n name: 'Dica de informação',\n component: 'InfoHint',\n file: 'components/ui/info-hint.tsx',\n variantProps: {},\n whenToUse: 'Para texto orientativo que não tem um título de tela, card ou seção ao lado.',\n },\n // ---------------------------------------------------------------- input\n {\n code: 'CAMP-001',\n name: 'Campo de texto',\n component: 'Input',\n file: 'components/ui/input.tsx',\n variantProps: {},\n whenToUse: 'Para texto, número, senha, telefone, moeda ou qualquer valor de uma linha.',\n },\n // ---------------------------------------------------------------- kanban\n {\n code: 'KANB-001',\n name: 'Quadro kanban',\n component: 'Kanban',\n file: 'components/ui/kanban.tsx',\n // variantProps fica vazio de propósito: a diferença para KANB-002 é a prop `dropTargets`\n // (um array de destinos de arraste), não um literal de string/número/booleano, e o\n // `rendra trocar` não tem como inventar um array, então ele recusa a troca com uma\n // mensagem clara (\"sem prop que os distinga\"), e a variante certa fica documentada aqui.\n variantProps: {},\n whenToUse: 'Para um funil de etapas com cartões que se movem entre colunas.',\n isDefault: true,\n },\n {\n code: 'KANB-002',\n name: 'Quadro kanban com destinos de arraste',\n component: 'Kanban',\n file: 'components/ui/kanban.tsx',\n variantProps: { hasDropTargets: true },\n whenToUse:\n 'Quando o card pode ir para uma ação além de outra coluna (ex.: \"Marcar como ganho\"), ' +\n 'mostrada numa barra durante o arraste e no menu \"Mover para\".',\n },\n // ---------------------------------------------------------------- list\n {\n code: 'LIST-001',\n name: 'Lista',\n component: 'List',\n file: 'components/ui/list.tsx',\n // variantProps fica vazio de propósito: a diferença para LIST-002 é a prop `onReorder`\n // (uma função de callback), não um literal de string/número/booleano, e o `rendra trocar`\n // não tem como inventar uma função, então ele recusa a troca com uma mensagem clara (\"sem\n // prop que os distinga\"), e a variante certa fica documentada aqui.\n variantProps: {},\n whenToUse: 'Para linhas simples com início, título, descrição e fim, navegáveis ou não.',\n isDefault: true,\n },\n {\n code: 'LIST-002',\n name: 'Lista reordenável',\n component: 'List',\n file: 'components/ui/list.tsx',\n variantProps: { sortable: true },\n whenToUse: 'Quando a pessoa pode mudar a ordem das linhas, por arraste ou pelas setas da alça.',\n },\n // ---------------------------------------------------------------- modal\n {\n code: 'MOD-001',\n name: 'Modal de confirmação',\n component: 'Modal',\n file: 'components/ui/modal.tsx',\n variantProps: { type: 'confirm' },\n whenToUse:\n 'Para confirmar uma ação com uma principal e uma de cancelar; type=\"destructive\" usa o ' +\n 'mesmo código, porque só muda a cor.',\n isDefault: true,\n },\n {\n code: 'MOD-002',\n name: 'Modal de formulário',\n component: 'Modal',\n file: 'components/ui/modal.tsx',\n variantProps: { type: 'form' },\n whenToUse: 'Para um formulário de até 3 campos simples, sem sair da tela atual.',\n },\n {\n code: 'MOD-003',\n name: 'Modal informativo',\n component: 'Modal',\n file: 'components/ui/modal.tsx',\n variantProps: { type: 'info' },\n whenToUse:\n 'Para só informar algo, sem decisão a tomar: um botão só, de largura total, que fecha o modal.',\n },\n // ---------------------------------------------------------------- otp-input\n {\n code: 'OTP-001',\n name: 'Código de verificação',\n component: 'OtpInput',\n file: 'components/ui/otp-input.tsx',\n variantProps: {},\n whenToUse: 'Para confirmar um código enviado por SMS ou e-mail (2FA).',\n },\n // ---------------------------------------------------------------- pagination\n {\n code: 'PAG-001',\n name: 'Paginação',\n component: 'Pagination',\n file: 'components/ui/pagination.tsx',\n variantProps: {},\n whenToUse: 'Para navegar entre páginas de uma listagem.',\n },\n // ---------------------------------------------------------------- popover\n {\n code: 'POP-001',\n name: 'Popover',\n component: 'PopoverContent',\n file: 'components/ui/popover.tsx',\n variantProps: {},\n whenToUse: 'Para um painel curto que abre perto de um botão, como um filtro.',\n },\n // ---------------------------------------------------------------- progress\n {\n code: 'PROG-001',\n name: 'Barra de progresso',\n component: 'Progress',\n file: 'components/ui/progress.tsx',\n variantProps: {},\n whenToUse: 'Para o andamento de uma tarefa ou de um envio.',\n },\n // ---------------------------------------------------------------- qr-code\n {\n code: 'QRC-001',\n name: 'Código QR',\n component: 'QrCode',\n file: 'components/ui/qr-code.tsx',\n variantProps: {},\n whenToUse: 'Para gerar um código QR (link, código de acesso) sem depender de serviço externo.',\n },\n // ---------------------------------------------------------------- radio-group\n {\n code: 'RDO-001',\n name: 'Opções em lista',\n component: 'RadioGroup',\n file: 'components/ui/radio-group.tsx',\n variantProps: { variant: 'list' },\n whenToUse: 'Para poucas opções simples, uma escolha só, em lista com bolinha e texto.',\n isDefault: true,\n },\n {\n code: 'RDO-002',\n name: 'Opções em cartões',\n component: 'RadioGroup',\n file: 'components/ui/radio-group.tsx',\n variantProps: { variant: 'cards' },\n whenToUse: 'Para opções com ícone e descrição, quando cada uma merece mais destaque.',\n },\n // ---------------------------------------------------------------- rating\n {\n code: 'RTG-001',\n name: 'Avaliação em estrelas',\n component: 'Rating',\n file: 'components/ui/rating.tsx',\n variantProps: { variant: 'stars' },\n whenToUse: 'Para uma nota rápida de satisfação, em estrelas.',\n isDefault: true,\n },\n {\n code: 'RTG-002',\n name: 'Avaliação em escala',\n component: 'Rating',\n file: 'components/ui/rating.tsx',\n variantProps: { variant: 'scale' },\n whenToUse: 'Para uma nota de 0 a 10 (NPS e pesquisas parecidas), com rótulo nas pontas.',\n },\n // ---------------------------------------------------------------- rendra-credit\n {\n code: 'CRED-001',\n name: 'Crédito Feito com Rendra',\n component: 'RendraCredit',\n file: 'components/ui/rendra-credit.tsx',\n variantProps: {},\n whenToUse:\n 'No rodapé da tela de login, discreto; pode ser removido (credit={false}) ou levado para ' +\n 'outro lugar visível, como uma tela Sobre.',\n },\n // ---------------------------------------------------------------- repeatable-field\n {\n code: 'REP-001',\n name: 'Campo repetível',\n component: 'RepeatableField',\n file: 'components/ui/repeatable-field.tsx',\n variantProps: {},\n whenToUse:\n 'Para uma lista de campos do mesmo tipo (telefones, e-mails, endereços), com um principal.',\n },\n // ---------------------------------------------------------------- rich-text-editor\n {\n code: 'RTE-001',\n name: 'Editor de texto rico',\n component: 'RichTextEditor',\n file: 'components/ui/rich-text-editor.tsx',\n variantProps: {},\n whenToUse: 'Para conteúdo com formatação, listas e imagens, como a descrição de um artigo.',\n },\n // ---------------------------------------------------------------- select\n {\n code: 'SEL-001',\n name: 'Select',\n component: 'Select',\n file: 'components/ui/select.tsx',\n variantProps: {},\n whenToUse: 'Para escolher uma ou mais opções de uma lista, com ou sem busca.',\n },\n // ---------------------------------------------------------------- separator\n {\n code: 'SEP-001',\n name: 'Separador',\n component: 'Separator',\n file: 'components/ui/separator.tsx',\n variantProps: {},\n whenToUse: 'Para dividir conteúdo dentro de um card, no lugar de um card dentro de card.',\n },\n // ---------------------------------------------------------------- skeleton\n {\n code: 'SKEL-001',\n name: 'Esqueleto de carregamento',\n component: 'Skeleton',\n file: 'components/ui/skeleton.tsx',\n variantProps: {},\n whenToUse: 'Para o estado de carregamento, com a mesma estrutura do conteúdo final.',\n },\n // ---------------------------------------------------------------- slider\n {\n code: 'SLD-001',\n name: 'Slider',\n component: 'Slider',\n file: 'components/ui/slider.tsx',\n variantProps: {},\n whenToUse: 'Para escolher um número ou uma faixa dentro de um intervalo, arrastando.',\n },\n // ---------------------------------------------------------------- spinner\n {\n code: 'SPIN-001',\n name: 'Indicador de carregamento',\n component: 'Spinner',\n file: 'components/ui/spinner.tsx',\n variantProps: {},\n whenToUse:\n 'Para um carregamento breve dentro de um botão, campo ou lista, sem barra de progresso.',\n },\n // ---------------------------------------------------------------- stat-card\n {\n code: 'STAT-001',\n name: 'Card de indicador',\n component: 'StatCard',\n file: 'components/ui/stat-card.tsx',\n variantProps: {},\n whenToUse: 'Para um número de destaque com variação, num painel ou dashboard.',\n },\n // ---------------------------------------------------------------- switch\n {\n code: 'SWT-001',\n name: 'Switch',\n component: 'Switch',\n file: 'components/ui/switch.tsx',\n variantProps: {},\n whenToUse: 'Para ligar ou desligar uma opção com efeito imediato.',\n },\n // ---------------------------------------------------------------- table\n {\n code: 'TAB-001',\n name: 'Tabela',\n component: 'Table',\n file: 'components/ui/table.tsx',\n variantProps: {},\n whenToUse: 'Para qualquer listagem de registros, com busca, filtros e paginação.',\n },\n // ---------------------------------------------------------------- tabs\n {\n code: 'ABA-001',\n name: 'Abas em linha',\n component: 'Tabs',\n file: 'components/ui/tabs.tsx',\n variantProps: { variant: 'line' },\n whenToUse: 'Padrão para dividir o conteúdo de uma tela em seções, com sublinhado na aba ativa.',\n isDefault: true,\n },\n {\n code: 'ABA-002',\n name: 'Abas em pílula',\n component: 'Tabs',\n file: 'components/ui/tabs.tsx',\n variantProps: { variant: 'pill' },\n whenToUse: 'Quando as abas precisam de mais destaque visual, como pílulas sobre fundo suave.',\n },\n // ---------------------------------------------------------------- textarea\n {\n code: 'TXT-001',\n name: 'Área de texto',\n component: 'Textarea',\n file: 'components/ui/textarea.tsx',\n variantProps: {},\n whenToUse: 'Para texto longo, com contador de caracteres opcional.',\n },\n // ---------------------------------------------------------------- timeline\n {\n code: 'TLN-001',\n name: 'Linha do tempo',\n component: 'Timeline',\n file: 'components/ui/timeline.tsx',\n variantProps: {},\n whenToUse: 'Para uma sequência de eventos em ordem, cada um com um tom semântico.',\n },\n // ---------------------------------------------------------------- toast\n {\n code: 'TST-001',\n name: 'Toast',\n component: 'toast',\n file: 'components/ui/toast.tsx',\n variantProps: {},\n whenToUse: 'Para uma confirmação rápida depois de uma ação, sem interromper a tela.',\n },\n // ---------------------------------------------------------------- tooltip\n {\n code: 'TIP-001',\n name: 'Tooltip',\n component: 'Tooltip',\n file: 'components/ui/tooltip.tsx',\n variantProps: {},\n whenToUse: 'Para informação complementar, nunca essencial, que aparece ao passar o mouse.',\n },\n // ---------------------------------------------------------------- upload\n {\n code: 'UPL-001',\n name: 'Upload',\n component: 'Upload',\n file: 'components/ui/upload.tsx',\n // A prop que distingue de UPL-002 é `layout` ('list' | 'gallery', padrão 'list'): declarar\n // o valor padrão aqui (em vez de {}) é o que permite ao `rendra trocar` inserir\n // layout=\"gallery\" num elemento sem a prop, ao trocar para UPL-002.\n variantProps: { layout: 'list' },\n whenToUse: 'Para arrastar e soltar ou escolher arquivos, com lista e progresso por arquivo.',\n isDefault: true,\n },\n {\n code: 'UPL-002',\n name: 'Upload em galeria',\n component: 'Upload',\n file: 'components/ui/upload.tsx',\n variantProps: { layout: 'gallery' },\n whenToUse: 'Para upload de fotos e vídeos, com miniatura em vez de linha de lista.',\n },\n // ---------------------------------------------------------------- flow\n {\n code: 'FLX-001',\n name: 'Editor de fluxo',\n component: 'FlowEditor',\n file: 'components/ui/flow-editor.tsx',\n variantProps: {},\n whenToUse:\n 'Para montar, ligar, validar e testar um fluxo de automação (gatilho, ação, condição, espera e fim).',\n },\n {\n code: 'FLX-002',\n name: 'Visualizador de fluxo',\n component: 'FlowViewer',\n file: 'components/ui/flow-viewer.tsx',\n variantProps: {},\n whenToUse: 'Para mostrar um fluxo de automação só para ler, sem editar.',\n },\n // ---------------------------------------------------------------- widget-grid\n {\n code: 'WDG-001',\n name: 'Grade de widgets',\n component: 'WidgetGrid',\n file: 'components/ui/widget-grid.tsx',\n variantProps: {},\n whenToUse: 'Para um painel com blocos que a pessoa pode arrastar e redimensionar.',\n },\n // ---------------------------------------------------------------- wizard\n {\n code: 'WIZ-001',\n name: 'Wizard',\n component: 'Wizard',\n file: 'components/ui/wizard.tsx',\n variantProps: {},\n whenToUse: 'Para um cadastro longo dividido em etapas, com validação por etapa.',\n },\n {\n code: 'WIZ-002',\n name: 'Indicador de etapas',\n component: 'Stepper',\n file: 'components/ui/wizard.tsx',\n variantProps: {},\n whenToUse: 'Para mostrar o progresso em etapas por conta própria, sem o Wizard inteiro.',\n },\n]\n\n/** Um código específico do catálogo (ex.: para montar a vitrine ou o registry). */\nexport function getCatalogEntry(code: string): ComponentCatalogEntry | undefined {\n return CATALOG.find((entry) => entry.code === code)\n}\n\n/** Todos os códigos de um componente (ex.: as duas variantes do Tabs), na ordem cadastrada. */\nexport function catalogByComponent(component: string): ComponentCatalogEntry[] {\n return CATALOG.filter((entry) => entry.component === component)\n}\n\n/**\n * Resolve o código de catálogo de um componente a partir das props que definem a variante.\n * Sem variante (um código só, ou nenhuma prop bate), devolve o primeiro código cadastrado\n * para o componente. Usado pelos próprios componentes para calcular o `data-rendra`, sem\n * duplicar a tabela de variantes.\n */\nexport function resolveCatalogCode(component: string, props: Record<string, unknown> = {}): string {\n const entries = catalogByComponent(component)\n if (entries.length === 0) {\n throw new Error(`Catálogo: nenhum código cadastrado para o componente \"${component}\".`)\n }\n const match = entries.find(\n (entry) =>\n Object.keys(entry.variantProps).length > 0 &&\n Object.entries(entry.variantProps).every(([key, value]) => props[key] === value),\n )\n // entries.length > 0 já foi conferido acima: entries[0] sempre existe aqui.\n return (match ?? entries[0]!).code\n}\n\n/*\n * Regras de integridade (usadas pelo teste em components.test.ts e por assertCatalogIntegrity).\n * São funções puras, sem acesso a arquivo: recebem a lista de entradas e devolvem o que\n * está errado, para o teste poder provar a regra com uma lista fabricada, não só com o\n * catálogo real.\n */\n\n/** Código que aparece mais de uma vez na lista. */\nexport function findDuplicateCodes(entries: ComponentCatalogEntry[]): string[] {\n const seen = new Set<string>()\n const duplicates = new Set<string>()\n for (const entry of entries) {\n if (seen.has(entry.code)) duplicates.add(entry.code)\n seen.add(entry.code)\n }\n return [...duplicates]\n}\n\n/** Código fora do formato ^[A-Z]{3,4}-\\d{3}$. */\nexport function findInvalidFormatCodes(entries: ComponentCatalogEntry[]): string[] {\n return entries\n .filter((entry) => !COMPONENT_CODE_PATTERN.test(entry.code))\n .map((entry) => entry.code)\n}\n\n/**\n * Código que colidiria com um código de modelo (T1, C4, M5...) de src/config/presets.ts,\n * cujo padrão é /[TCM]\\d+/ (uma letra T, C ou M seguida direto de dígitos, sem hífen).\n */\nexport function findPresetCollisions(entries: ComponentCatalogEntry[]): string[] {\n return entries.filter((entry) => /[TCM]\\d+/.test(entry.code)).map((entry) => entry.code)\n}\n\n/** Arquivo (caminho relativo a src/) que não tem nenhuma entrada no catálogo. */\nexport function filesMissingCatalogEntry(\n files: string[],\n entries: ComponentCatalogEntry[],\n): string[] {\n const covered = new Set(entries.map((entry) => entry.file))\n return files.filter((file) => !covered.has(file))\n}\n\n/** Componente (nome) com mais de uma variante no catálogo, agrupadas na ordem cadastrada. */\nfunction groupByComponentWithMultipleVariants(\n entries: ComponentCatalogEntry[],\n): Map<string, ComponentCatalogEntry[]> {\n const byComponent = new Map<string, ComponentCatalogEntry[]>()\n for (const entry of entries) {\n const list = byComponent.get(entry.component) ?? []\n list.push(entry)\n byComponent.set(entry.component, list)\n }\n for (const [component, list] of byComponent) if (list.length <= 1) byComponent.delete(component)\n return byComponent\n}\n\n/**\n * Componente com mais de uma variante que não tem nenhuma marcada `isDefault` (fase 3, Lote\n * B: `rendra trocar` precisa saber qual variante um elemento sem a prop representa).\n */\nexport function findComponentsWithoutDefault(entries: ComponentCatalogEntry[]): string[] {\n const groups = groupByComponentWithMultipleVariants(entries)\n return [...groups]\n .filter(([, list]) => !list.some((entry) => entry.isDefault))\n .map(([component]) => component)\n}\n\n/** Componente com mais de uma variante marcada `isDefault` ao mesmo tempo (só pode uma). */\nexport function findComponentsWithMultipleDefaults(entries: ComponentCatalogEntry[]): string[] {\n const groups = groupByComponentWithMultipleVariants(entries)\n return [...groups]\n .filter(([, list]) => list.filter((entry) => entry.isDefault).length > 1)\n .map(([component]) => component)\n}\n\n/**\n * Lança se houver código duplicado, fora do formato, colidindo com um código de modelo, ou\n * componente com mais de uma variante sem exatamente uma marcada `isDefault`.\n */\nexport function assertCatalogIntegrity(): void {\n const duplicates = findDuplicateCodes(CATALOG)\n if (duplicates.length > 0) {\n throw new Error(`Catálogo: código duplicado: ${duplicates.join(', ')}.`)\n }\n const invalid = findInvalidFormatCodes(CATALOG)\n if (invalid.length > 0) {\n throw new Error(`Catálogo: código fora do formato ^[A-Z]{3,4}-\\\\d{3}$: ${invalid.join(', ')}.`)\n }\n const collisions = findPresetCollisions(CATALOG)\n if (collisions.length > 0) {\n throw new Error(\n `Catálogo: código colide com um código de modelo (T/C/M): ${collisions.join(', ')}.`,\n )\n }\n const semPadrao = findComponentsWithoutDefault(CATALOG)\n if (semPadrao.length > 0) {\n throw new Error(\n `Catálogo: componente com mais de uma variante sem nenhuma marcada isDefault: ${semPadrao.join(', ')}.`,\n )\n }\n const padraoDuplicado = findComponentsWithMultipleDefaults(CATALOG)\n if (padraoDuplicado.length > 0) {\n throw new Error(\n `Catálogo: componente com mais de uma variante marcada isDefault: ${padraoDuplicado.join(', ')}.`,\n )\n }\n}\n"],"mappings":"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AS;EAC/B,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WACE;CACJ;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WACE;CACJ;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EAKN,cAAc,CAAC;EACf,WAAW;EACX,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,gBAAgB,KAAK;EACrC,WACE;CAEJ;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EAKN,cAAc,CAAC;EACf,WAAW;EACX,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,UAAU,KAAK;EAC/B,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,MAAM,UAAU;EAChC,WACE;EAEF,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,MAAM,OAAO;EAC7B,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,MAAM,OAAO;EAC7B,WACE;CACJ;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,SAAS,OAAO;EAChC,WAAW;EACX,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,SAAS,QAAQ;EACjC,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,SAAS,QAAQ;EACjC,WAAW;EACX,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,SAAS,QAAQ;EACjC,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WACE;CAEJ;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WACE;CACJ;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WACE;CACJ;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,SAAS,OAAO;EAChC,WAAW;EACX,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,SAAS,OAAO;EAChC,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EAIN,cAAc,EAAE,QAAQ,OAAO;EAC/B,WAAW;EACX,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,EAAE,QAAQ,UAAU;EAClC,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WACE;CACJ;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CAEA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;CACA;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,MAAM;EACN,cAAc,CAAC;EACf,WAAW;CACb;AACF;;AAGA,SAAgB,gBAAgB,MAAiD;CAC/E,OAAO,QAAQ,MAAM,UAAU,MAAM,SAAS,IAAI;AACpD;;AAGA,SAAgB,mBAAmB,WAA4C;CAC7E,OAAO,QAAQ,QAAQ,UAAU,MAAM,cAAc,SAAS;AAChE;;;;;;;AAQA,SAAgB,mBAAmB,WAAmB,QAAiC,CAAC,GAAW;CACjG,MAAM,UAAU,mBAAmB,SAAS;CAC5C,IAAI,QAAQ,WAAW,GACrB,MAAM,IAAI,MAAM,yDAAyD,UAAU,GAAG;CAQxF,QANc,QAAQ,MACnB,UACC,OAAO,KAAK,MAAM,YAAY,CAAC,CAAC,SAAS,KACzC,OAAO,QAAQ,MAAM,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK,WAAW,MAAM,SAAS,KAAK,CAG3E,KAAS,QAAQ,GAAA,CAAK;AAChC;;AAUA,SAAgB,mBAAmB,SAA4C;CAC7E,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,6BAAa,IAAI,IAAY;CACnC,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,KAAK,IAAI,MAAM,IAAI,GAAG,WAAW,IAAI,MAAM,IAAI;EACnD,KAAK,IAAI,MAAM,IAAI;CACrB;CACA,OAAO,CAAC,GAAG,UAAU;AACvB;;AAGA,SAAgB,uBAAuB,SAA4C;CACjF,OAAO,QACJ,QAAQ,UAAU,CAAC,uBAAuB,KAAK,MAAM,IAAI,CAAC,CAAC,CAC3D,KAAK,UAAU,MAAM,IAAI;AAC9B;;;;;AAMA,SAAgB,qBAAqB,SAA4C;CAC/E,OAAO,QAAQ,QAAQ,UAAU,WAAW,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU,MAAM,IAAI;AACzF;;AAGA,SAAgB,yBACd,OACA,SACU;CACV,MAAM,UAAU,IAAI,IAAI,QAAQ,KAAK,UAAU,MAAM,IAAI,CAAC;CAC1D,OAAO,MAAM,QAAQ,SAAS,CAAC,QAAQ,IAAI,IAAI,CAAC;AAClD;;AAGA,SAAS,qCACP,SACsC;CACtC,MAAM,8BAAc,IAAI,IAAqC;CAC7D,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,OAAO,YAAY,IAAI,MAAM,SAAS,KAAK,CAAC;EAClD,KAAK,KAAK,KAAK;EACf,YAAY,IAAI,MAAM,WAAW,IAAI;CACvC;CACA,KAAK,MAAM,CAAC,WAAW,SAAS,aAAa,IAAI,KAAK,UAAU,GAAG,YAAY,OAAO,SAAS;CAC/F,OAAO;AACT;;;;;AAMA,SAAgB,6BAA6B,SAA4C;CAEvF,OAAO,CAAC,GADO,qCAAqC,OACzC,CAAM,CAAC,CACf,QAAQ,GAAG,UAAU,CAAC,KAAK,MAAM,UAAU,MAAM,SAAS,CAAC,CAAC,CAC5D,KAAK,CAAC,eAAe,SAAS;AACnC;;AAGA,SAAgB,mCAAmC,SAA4C;CAE7F,OAAO,CAAC,GADO,qCAAqC,OACzC,CAAM,CAAC,CACf,QAAQ,GAAG,UAAU,KAAK,QAAQ,UAAU,MAAM,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CACxE,KAAK,CAAC,eAAe,SAAS;AACnC;;;;;AAMA,SAAgB,yBAA+B;CAC7C,MAAM,aAAa,mBAAmB,OAAO;CAC7C,IAAI,WAAW,SAAS,GACtB,MAAM,IAAI,MAAM,+BAA+B,WAAW,KAAK,IAAI,EAAE,EAAE;CAEzE,MAAM,UAAU,uBAAuB,OAAO;CAC9C,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,MAAM,yDAAyD,QAAQ,KAAK,IAAI,EAAE,EAAE;CAEhG,MAAM,aAAa,qBAAqB,OAAO;CAC/C,IAAI,WAAW,SAAS,GACtB,MAAM,IAAI,MACR,4DAA4D,WAAW,KAAK,IAAI,EAAE,EACpF;CAEF,MAAM,YAAY,6BAA6B,OAAO;CACtD,IAAI,UAAU,SAAS,GACrB,MAAM,IAAI,MACR,gFAAgF,UAAU,KAAK,IAAI,EAAE,EACvG;CAEF,MAAM,kBAAkB,mCAAmC,OAAO;CAClE,IAAI,gBAAgB,SAAS,GAC3B,MAAM,IAAI,MACR,oEAAoE,gBAAgB,KAAK,IAAI,EAAE,EACjG;AAEJ"}