@rendra-ui/web 2.3.0 → 2.5.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 (85) hide show
  1. package/README.md +107 -61
  2. package/bin/rendra.mjs +19 -7
  3. package/dist/base.css +33 -1
  4. package/dist/{button-DWhICtIG.js → button-BzJgR2gH.js} +86 -21
  5. package/dist/button-BzJgR2gH.js.map +1 -0
  6. package/dist/chart.js +61 -15
  7. package/dist/chart.js.map +1 -1
  8. package/dist/cli/auditar.js +66 -16
  9. package/dist/cli/auditar.js.map +1 -1
  10. package/dist/cli/codigos.js +2 -2
  11. package/dist/cli/executar-auditar.js +634 -0
  12. package/dist/cli/executar-auditar.js.map +1 -0
  13. package/dist/cli/help.js +7 -2
  14. package/dist/cli/help.js.map +1 -1
  15. package/dist/cli/trocar.js +2 -2
  16. package/dist/cli/typescript-loader.js +1 -1
  17. package/dist/{cn-DDZQKUVV.js → cn-Cw7M5kEP.js} +2 -2
  18. package/dist/{cn-DDZQKUVV.js.map → cn-Cw7M5kEP.js.map} +1 -1
  19. package/dist/{components-Cq_PmN4y.js → components-DkpspH9h.js} +21 -4
  20. package/dist/components-DkpspH9h.js.map +1 -0
  21. package/dist/components.css +274 -32
  22. package/dist/document-viewer.js +6 -6
  23. package/dist/document-viewer.js.map +1 -1
  24. package/dist/{empty-state-C491qfzf.js → empty-state-Cdb1vkMT.js} +81 -37
  25. package/dist/empty-state-Cdb1vkMT.js.map +1 -0
  26. package/dist/features-max--5VEt6M7.js +3 -0
  27. package/dist/index.js +1170 -390
  28. package/dist/index.js.map +1 -1
  29. package/dist/motion-context-5BRIQAJm.js +107 -0
  30. package/dist/motion-context-5BRIQAJm.js.map +1 -0
  31. package/dist/{rendra-provider-BRtk5Qa1.js → rendra-provider-CRe0XdOU.js} +9 -5
  32. package/dist/rendra-provider-CRe0XdOU.js.map +1 -0
  33. package/dist/rich-text-editor.js +4 -4
  34. package/dist/router-bridge.js +5 -4
  35. package/dist/router-bridge.js.map +1 -1
  36. package/dist/tokens.css +73 -15
  37. package/dist/tooltip-BAMSaGbS.js +224 -0
  38. package/dist/tooltip-BAMSaGbS.js.map +1 -0
  39. package/dist/types/components/app-shell/app-shell.d.ts +22 -2
  40. package/dist/types/components/app-shell/shell-context.d.ts +7 -1
  41. package/dist/types/components/app-shell/types.d.ts +23 -0
  42. package/dist/types/components/layout/page-header.d.ts +17 -1
  43. package/dist/types/components/rendra-provider.d.ts +7 -1
  44. package/dist/types/components/rendra-router-bridge.d.ts +3 -1
  45. package/dist/types/components/ui/accordion.d.ts +1 -1
  46. package/dist/types/components/ui/badge.d.ts +1 -1
  47. package/dist/types/components/ui/brand-feedback-icon.d.ts +20 -3
  48. package/dist/types/components/ui/button-group.d.ts +8 -1
  49. package/dist/types/components/ui/button.d.ts +1 -1
  50. package/dist/types/components/ui/dropdown-menu.d.ts +5 -5
  51. package/dist/types/components/ui/empty-state.d.ts +4 -0
  52. package/dist/types/components/ui/error-page.d.ts +6 -1
  53. package/dist/types/components/ui/modal.d.ts +4 -0
  54. package/dist/types/components/ui/picker-panel.d.ts +1 -1
  55. package/dist/types/components/ui/popover.d.ts +3 -3
  56. package/dist/types/components/ui/radio-group.d.ts +1 -1
  57. package/dist/types/components/ui/skeleton.d.ts +5 -1
  58. package/dist/types/components/ui/stat-card.d.ts +1 -1
  59. package/dist/types/components/ui/table.d.ts +0 -6
  60. package/dist/types/components/ui/tooltip.d.ts +1 -1
  61. package/dist/types/components/ui/wizard.d.ts +14 -1
  62. package/dist/types/hooks/use-reduced-motion.d.ts +3 -0
  63. package/dist/types/index.d.ts +1 -0
  64. package/dist/types/lib/initials.d.ts +2 -0
  65. package/dist/types/lib/motion/count.d.ts +17 -0
  66. package/dist/types/lib/motion/features-max.d.ts +1 -0
  67. package/dist/types/lib/motion/index.d.ts +5 -0
  68. package/dist/types/lib/motion/motion-context.d.ts +43 -0
  69. package/dist/types/lib/motion/native-events.d.ts +16 -0
  70. package/dist/types/lib/motion/presets.d.ts +92 -0
  71. package/dist/types/lib/motion/reorder.d.ts +7 -0
  72. package/dist/types/lib/motion/tokens.d.ts +66 -0
  73. package/dist/types/lib/motion/use-motion-presets.d.ts +8 -0
  74. package/dist/{use-breakpoint-C3ivDt2R.js → use-breakpoint-O9eqFmsF.js} +2 -2
  75. package/dist/{use-breakpoint-C3ivDt2R.js.map → use-breakpoint-O9eqFmsF.js.map} +1 -1
  76. package/dist/use-motion-presets-BrkgL8lG.js +401 -0
  77. package/dist/use-motion-presets-BrkgL8lG.js.map +1 -0
  78. package/dist/widget-grid.js +3 -3
  79. package/package.json +4 -1
  80. package/dist/button-DWhICtIG.js.map +0 -1
  81. package/dist/components-Cq_PmN4y.js.map +0 -1
  82. package/dist/empty-state-C491qfzf.js.map +0 -1
  83. package/dist/rendra-provider-BRtk5Qa1.js.map +0 -1
  84. package/dist/tooltip-DsNlnBSY.js +0 -105
  85. package/dist/tooltip-DsNlnBSY.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executar-auditar.js","names":[],"sources":["../../src/cli/help-length.ts","../../src/cli/var-prefix.ts","../../src/cli/regras-extras.ts","../../src/cli/auditar-tudo.ts","../../src/cli/argumentos.ts","../../src/cli/config.ts","../../src/cli/executar-auditar.ts"],"sourcesContent":["/*\n * Regra texto-orientativo (DESIGN_RULES.md, \"Texto orientativo\"): os limites de tamanho vivem\n * num módulo único para o verificador (scripts/check-design-rules.mjs) e o teste\n * (help-length.test.ts) nunca divergirem sobre o que é \"curto demais para instruir\".\n *\n * O que mede, só em texto literal escrito no JSX (texto dinâmico, como help={mensagem}, não é\n * medido):\n * - help=\"...\" em <Field> e <FormField>, contra o limite do span literal do campo (sem span,\n * vale md). Span dinâmico (span={x}) também não é medido;\n * - por FormSection: no máximo metade dos Field e FormField com help literal;\n * - description=\"...\" no <PageHeader>: até 150 caracteres;\n * - subtítulo que começa com verbo de instrução (description de qualquer componente e\n * <CardDescription>): descreve o que é, nunca o que fazer.\n */\n\n/** Limite de caracteres da orientação abaixo do campo, pela largura (span) do Field. */\nexport const HELP_LIMITS = {\n full: 150,\n xl: 100,\n lg: 70,\n md: 40,\n half: 40,\n sm: 30,\n xs: 20,\n} as const\n\nexport type HelpSpan = keyof typeof HELP_LIMITS\n\n/** Limite do description do PageHeader (descreve o que é a tela, em uma frase curta). */\nexport const PAGE_DESCRIPTION_LIMIT = 150\n\n/** Verbos no imperativo que denunciam instrução num subtítulo. */\nexport const INSTRUCTION_VERBS = [\n 'Comece',\n 'Clique',\n 'Toque',\n 'Arraste',\n 'Preencha',\n 'Use',\n 'Escolha',\n 'Selecione',\n 'Digite',\n 'Informe',\n 'Veja',\n 'Confira',\n]\n\n/** Limite do span; sem span (ou span desconhecido), vale o padrão md. */\nexport function helpLimit(span?: string): number {\n return span && span in HELP_LIMITS ? HELP_LIMITS[span as HelpSpan] : HELP_LIMITS.md\n}\n\n/** Quantidade de caracteres (por ponto de código, para acento e emoji contarem 1). */\nexport function textLength(text: string): number {\n return [...text.trim()].length\n}\n\nexport interface GuidanceViolation {\n line: number\n id: 'texto-orientativo'\n message: string\n src: string\n}\n\n/** Valor de um atributo: literal (texto) ou dinâmico (expressão), ou ausente (undefined). */\ntype AttrValue = { literal: string } | { dynamic: true }\n\ninterface JsxTag {\n start: number\n end: number\n text: string\n}\n\nconst QUOTES = new Set(['\"', \"'\", '`'])\n\n/** Pula uma string que começa em `i` (aspas); devolve o índice logo após o fechamento. */\nfunction skipString(text: string, i: number): number {\n const quote = text[i]\n let j = i + 1\n while (j < text.length && text[j] !== quote) j += text[j] === '\\\\' ? 2 : 1\n return j + 1\n}\n\n/**\n * Lê a tag de abertura JSX que começa em `start` (no \"<\") até o \">\" que a fecha, ignorando o\n * que está dentro de chaves (render={(f) => <Input />}) e de strings.\n */\nexport function readTag(text: string, start: number): JsxTag {\n let i = start + 1\n while (i < text.length && /[\\w.]/.test(text[i]!)) i++\n // Genérico do TypeScript: <FormField<Values> ...>\n if (text[i] === '<') {\n let angle = 0\n for (; i < text.length; i++) {\n if (text[i] === '<') angle++\n else if (text[i] === '>' && --angle === 0) {\n i++\n break\n }\n }\n }\n let depth = 0\n while (i < text.length) {\n const c = text[i]!\n if (QUOTES.has(c)) {\n i = skipString(text, i)\n continue\n }\n if (c === '{') depth++\n else if (c === '}') depth--\n else if (c === '>' && depth === 0) {\n i++\n break\n }\n i++\n }\n return { start, end: i, text: text.slice(start, i) }\n}\n\n/** Atributo `name` no nível de topo da tag (fora de chaves), literal ou dinâmico. */\nexport function readAttr(tag: string, name: string): AttrValue | undefined {\n let depth = 0\n let i = 0\n while (i < tag.length) {\n const c = tag[i]!\n if (depth > 0 && QUOTES.has(c)) {\n i = skipString(tag, i)\n continue\n }\n if (c === '{') depth++\n else if (c === '}') depth--\n else if (depth === 0 && QUOTES.has(c)) {\n i = skipString(tag, i)\n continue\n } else if (depth === 0 && /\\s/.test(tag[i - 1] ?? '') && tag.startsWith(`${name}=`, i)) {\n return parseValue(tag, i + name.length + 1)\n }\n i++\n }\n return undefined\n}\n\nfunction parseValue(tag: string, i: number): AttrValue {\n const c = tag[i]\n if (c === '\"' || c === \"'\") return { literal: tag.slice(i + 1, skipString(tag, i) - 1) }\n if (c !== '{') return { dynamic: true }\n let depth = 0\n let j = i\n for (; j < tag.length; j++) {\n if (depth > 0 && QUOTES.has(tag[j]!)) {\n j = skipString(tag, j) - 1\n continue\n }\n if (tag[j] === '{') depth++\n else if (tag[j] === '}' && --depth === 0) break\n }\n const inner = tag.slice(i + 1, j).trim()\n const quoted = /^([\"'`])([\\s\\S]*)\\1$/.exec(inner)\n if (quoted && !(quoted[1] === '`' && quoted[2]!.includes('${'))) return { literal: quoted[2]! }\n return { dynamic: true }\n}\n\nfunction lineOf(text: string, index: number): number {\n return text.slice(0, index).split('\\n').length\n}\n\nfunction firstLine(text: string): string {\n return text.split('\\n')[0]!.trim()\n}\n\n/** Tags de abertura de um componente (nome exato, sem pegar <FieldGroup> por <Field>). */\nfunction tagsOf(text: string, names: string[], from = 0, to = text.length): JsxTag[] {\n const re = new RegExp(`<(?:${names.join('|')})(?=[\\\\s<>/])`, 'g')\n re.lastIndex = from\n const tags: JsxTag[] = []\n for (let m = re.exec(text); m && m.index < to; m = re.exec(text)) {\n const tag = readTag(text, m.index)\n tags.push(tag)\n re.lastIndex = tag.end\n }\n return tags\n}\n\n/** help literal (não vazio) de uma tag de Field ou FormField, ou undefined. */\nfunction literalHelp(tag: string): string | undefined {\n const help = readAttr(tag, 'help')\n return help && 'literal' in help && help.literal.trim() ? help.literal : undefined\n}\n\n/** Orientação abaixo do campo acima do limite do span. */\nexport function checkFieldHelp(text: string): GuidanceViolation[] {\n const found: GuidanceViolation[] = []\n for (const tag of tagsOf(text, ['Field', 'FormField'])) {\n const help = literalHelp(tag.text)\n if (!help) continue\n const span = readAttr(tag.text, 'span')\n if (span && !('literal' in span)) continue\n const spanName = span && 'literal' in span ? span.literal : 'md'\n const limit = helpLimit(spanName)\n const size = textLength(help)\n if (size <= limit) continue\n found.push({\n line: lineOf(text, tag.start),\n id: 'texto-orientativo',\n message: `Orientação do campo com ${size} caracteres; o limite para span=\"${spanName}\" é ${limit}. Encurte, ou mova para help da seção (modal) ou um bloco recolhido.`,\n src: firstLine(tag.text),\n })\n }\n return found\n}\n\n/** Por FormSection: no máximo metade dos campos com orientação literal. */\nexport function checkSectionHelp(text: string): GuidanceViolation[] {\n const found: GuidanceViolation[] = []\n for (const section of tagsOf(text, ['FormSection'])) {\n const close = text.indexOf('</FormSection>', section.end)\n const end = close === -1 ? text.length : close\n const fields = tagsOf(text, ['Field', 'FormField'], section.end, end)\n const withHelp = fields.filter((f) => literalHelp(f.text)).length\n if (withHelp * 2 <= fields.length) continue\n found.push({\n line: lineOf(text, section.start),\n id: 'texto-orientativo',\n message: `Seção com orientação em ${withHelp} de ${fields.length} campos. No máximo metade dos campos de uma seção tem orientação.`,\n src: firstLine(section.text),\n })\n }\n return found\n}\n\n/** description literal do PageHeader acima de 150 caracteres. */\nexport function checkPageDescription(text: string): GuidanceViolation[] {\n const found: GuidanceViolation[] = []\n for (const tag of tagsOf(text, ['PageHeader'])) {\n const description = readAttr(tag.text, 'description')\n if (!description || !('literal' in description)) continue\n const size = textLength(description.literal)\n if (size <= PAGE_DESCRIPTION_LIMIT) continue\n found.push({\n line: lineOf(text, tag.start),\n id: 'texto-orientativo',\n message: `Descrição da tela com ${size} caracteres; o limite é ${PAGE_DESCRIPTION_LIMIT}. Ela diz o que a tela é; orientação vai em PageHeader help.`,\n src: firstLine(tag.text),\n })\n }\n return found\n}\n\nconst INSTRUCTION = new RegExp(\n `(?:description=\\\\{?\\\\s*[\"'\\`]|<CardDescription>\\\\s*)(?:${INSTRUCTION_VERBS.join('|')})\\\\b`,\n 'g',\n)\n\n/** Subtítulo que começa com verbo de instrução (description e CardDescription). */\nexport function checkInstruction(text: string): GuidanceViolation[] {\n return [...text.matchAll(INSTRUCTION)].map((m) => ({\n line: lineOf(text, m.index),\n id: 'texto-orientativo' as const,\n message:\n 'Instrução no subtítulo. Use help (PageHeader, CardTitle ou FormSection): ícone de informação que abre um modal.',\n src: firstLine(m[0]),\n }))\n}\n\n/** Todas as verificações de texto orientativo de uma tela, em ordem de linha. */\nexport function checkGuidance(text: string): GuidanceViolation[] {\n return [\n ...checkFieldHelp(text),\n ...checkSectionHelp(text),\n ...checkPageDescription(text),\n ...checkInstruction(text),\n ].sort((a, b) => a.line - b.line)\n}\n","/*\n * Prefixo --rendra-: toda variável CSS que é vocabulário do tema do Rendra (cor, fonte, raio,\n * sombra, degradê, gráfico, sidebar) precisa vir como --rendra-<nome>, para nunca colidir com\n * o namespace de um host que também use Tailwind. Módulo único: o verificador\n * (scripts/check-design-rules.mjs) e os testes (src/brand/palette.test.ts,\n * src/styles/tokens-prefix.test.ts) importam daqui, para nunca divergir.\n *\n * Ordem da decisão importa: primeiro perguntamos se o nome é variável própria do Rendra (a\n * lista abaixo é a fonte da verdade), e só se não for é que a exceção de namespace do\n * Tailwind (ou de terceiros) entra em jogo. Isso evita o bug em que \"radius\" (sem sufixo) ou\n * \"shadow-color\" batiam na regex de namespace do Tailwind antes de serem reconhecidos como\n * variáveis próprias do Rendra.\n *\n * Não entram nesta lista: o namespace do próprio Tailwind (--color-*, --spacing-*, --text-*,\n * --font-*, --radius-*, --shadow-*, --container-*, --breakpoint-*, --animate-*, --ease-*,\n * --tw-*, --tracking-*), variáveis de terceiros (--radix-*, do Radix UI) e as variáveis de\n * instância por elemento que os componentes escrevem via estilo inline (--progress, --otp,\n * --kanban-cols, --board-h, --delay, --from, --span, --top, --bottom, --fill, --angle,\n * --ratio, --days, --autosize-h, --h...): essas não são tokens de tema, são valor calculado\n * por instância, e ficam fora do contrato --rendra-*.\n */\n\nexport const RENDRA_VAR_EXACT = new Set([\n 'primary',\n 'primary-foreground',\n 'primary-hover',\n 'primary-hover-foreground',\n 'secondary',\n 'secondary-foreground',\n 'secondary-hover',\n 'secondary-hover-foreground',\n 'primary-soft',\n 'primary-soft-foreground',\n 'primary-text',\n 'ring',\n 'accent',\n 'accent-foreground',\n 'background',\n 'background-image',\n 'foreground',\n 'card',\n 'card-foreground',\n 'popover',\n 'popover-foreground',\n 'muted',\n 'muted-foreground',\n 'border',\n 'input',\n 'field',\n 'overlay',\n 'destructive',\n 'destructive-hover',\n 'destructive-foreground',\n 'destructive-soft',\n 'destructive-soft-foreground',\n 'success',\n 'success-foreground',\n 'success-soft',\n 'success-soft-foreground',\n 'warning',\n 'warning-foreground',\n 'warning-soft',\n 'warning-soft-foreground',\n 'info',\n 'info-foreground',\n 'info-soft',\n 'info-soft-foreground',\n 'shadow-color',\n 'brand-font',\n 'radius',\n 'sidebar',\n])\n\nexport const RENDRA_VAR_PREFIXES = [\n 'sidebar-',\n 'gradient-',\n 'chart-',\n 'elevation-',\n 'shape-',\n 'meter-',\n 'label-',\n 'help-',\n]\n\n// \"tracking\" (--tracking-tight etc.) é a escala de letter-spacing do próprio Tailwind v4,\n// declarada em @theme junto de --spacing e --text; entra na mesma exceção de namespace. O \"$\"\n// cobre o caso de degrau zerado sem sufixo (--spacing: initial;), que também é do Tailwind.\nexport const TAILWIND_NAMESPACE =\n /^(color|spacing|text|font|radius|shadow|container|breakpoint|animate|ease|tw|tracking)(-|$)/\n\n/** Fonte da verdade: `name` (sem os `--`) é vocabulário próprio do tema do Rendra? */\nexport function isRendraOwnVar(name: string): boolean {\n if (RENDRA_VAR_EXACT.has(name)) return true\n return RENDRA_VAR_PREFIXES.some((p) => name.startsWith(p))\n}\n\nexport interface VarPrefixViolation {\n line: number\n name: string\n message: string\n src: string\n}\n\n/**\n * Varre `var(--x)` do arquivo inteiro, pulando o bloco @theme / @theme inline (a ponte\n * documentada entre o nome do Tailwind e o nome do Rendra, ex.:\n * --color-primary: var(--rendra-primary)) e comentários.\n */\nexport function checkVarPrefix(text: string): VarPrefixViolation[] {\n const found: VarPrefixViolation[] = []\n const lines = text.split('\\n')\n let themeDepth = 0\n lines.forEach((line, i) => {\n if (themeDepth === 0 && /^\\s*@theme\\b/.test(line)) {\n themeDepth += (line.match(/\\{/g)?.length ?? 0) - (line.match(/\\}/g)?.length ?? 0)\n return\n }\n if (themeDepth > 0) {\n themeDepth += (line.match(/\\{/g)?.length ?? 0) - (line.match(/\\}/g)?.length ?? 0)\n if (themeDepth < 0) themeDepth = 0\n return\n }\n if (/^\\s*(\\/\\/|\\*|\\/\\*)/.test(line)) return\n for (const m of line.matchAll(/var\\(--([a-zA-Z][\\w-]*)\\)/g)) {\n const name = m[1]!\n if (name.startsWith('rendra-')) continue\n // Fonte da verdade primeiro: isRendraOwnVar decide sozinho se é vocabulário do tema. Só\n // quando a resposta é \"não\" o nome escapa (namespace do Tailwind, terceiro como\n // --radix-*, ou variável de instância por elemento) — e nem precisamos checar isso à\n // parte, porque \"não ser variável própria\" já é a própria exceção.\n if (!isRendraOwnVar(name)) continue\n found.push({\n line: i + 1,\n name,\n message: `Variável própria do Rendra sem o prefixo --rendra-. Use var(--rendra-${name}).`,\n src: line.trim(),\n })\n }\n })\n return found\n}\n\n/**\n * Varre declarações (`--nome: valor;`) num arquivo de tema (theme.css, globals.css,\n * palettes.css, o theme.css de cada modelo em src/brand/examples — usada por\n * src/styles/tokens-prefix.test.ts). Diferente\n * de `checkVarPrefix`, não precisa pular o bloco @theme: a exceção de namespace vale pelo\n * nome, não pelo bloco (globals.css redeclara --spacing-control-sm fora de @theme, em @layer\n * base, só para sobrescrever o valor em telas maiores, e isso também não é variável própria do\n * Rendra).\n *\n * Acusa quando `isRendraOwnVar(name) || !TAILWIND_NAMESPACE.test(name)`: um arquivo de tema só\n * declara variável própria do Rendra ou variável do namespace do Tailwind (dentro de @theme);\n * qualquer outro nome é um token novo inventado direto no arquivo, sem passar pelo catálogo de\n * `RENDRA_VAR_EXACT`/`RENDRA_VAR_PREFIXES` — também precisa do prefixo --rendra-, mesmo sem\n * constar nas listas acima (é por isso que a condição não usa só `isRendraOwnVar`, como em\n * `checkVarPrefix`: lá, fora de um arquivo de tema, um nome desconhecido pode ser variável de\n * instância por elemento; aqui, dentro de um arquivo de tema, não pode).\n */\nexport function findUnprefixedDeclarations(text: string): VarPrefixViolation[] {\n const found: VarPrefixViolation[] = []\n const lines = text.split('\\n')\n lines.forEach((line, i) => {\n const m = /^\\s*--([a-zA-Z][\\w-]*)\\s*:/.exec(line)\n if (!m) return\n const name = m[1]!\n if (name.startsWith('rendra-')) return\n if (!isRendraOwnVar(name) && TAILWIND_NAMESPACE.test(name)) return\n found.push({\n line: i + 1,\n name,\n message: `Variável própria do Rendra sem o prefixo --rendra-. Use --rendra-${name}.`,\n src: line.trim(),\n })\n })\n return found\n}\n","/*\n * As dez regras que vão além das sete genéricas de `auditar.ts`: as do vocabulário e da\n * convenção de pastas do Rendra. Rodam em `rendra auditar --all` e no `check:rules`\n * (scripts/check-design-rules.mjs, que chama `auditarTudo`), sempre pelo mesmo código, para as\n * duas verificações nunca divergirem.\n *\n * Funções puras: recebem o texto (ou o caminho) de UM arquivo e devolvem violações no formato\n * `AuditViolation` (`line`, `rule`, `message`, `source`). Quem decide em que arquivo cada regra\n * roda (pastas de marca, pastas de telas) é `auditar-tudo.ts`; nenhuma pasta é fixada aqui.\n *\n * Imports relativos com extensão `.ts`: o `check:rules` carrega esta cadeia direto no Node\n * (type stripping), que não resolve import sem extensão.\n */\nimport type { AuditViolation } from './auditar.ts'\nimport { checkGuidance } from './help-length.ts'\nimport { checkVarPrefix } from './var-prefix.ts'\n\n/** Identificadores das regras extras, na ordem em que a documentação as lista. */\nexport const IDS_REGRAS_EXTRAS = [\n 'var-inline',\n 'svg-marca',\n 'classe-dinamica',\n 'texto-estreito',\n 'primaria-como-texto',\n 'componente-duplicado',\n 'css-fora-do-lugar',\n 'botao-solto',\n 'texto-orientativo',\n 'variavel-sem-prefixo-rendra',\n] as const\n\nexport type IdRegraExtra = (typeof IDS_REGRAS_EXTRAS)[number]\n\ninterface RegraPorLinha {\n id: IdRegraExtra\n test: RegExp\n message: string\n skipLine?: (line: string) => boolean\n}\n\n/** As cinco regras de uma linha só, na ordem em que eram verificadas. */\nconst REGRAS_POR_LINHA: RegraPorLinha[] = [\n {\n id: 'var-inline',\n test: /var\\(--(?:color|radius|shadow|font|spacing)-/g,\n message:\n 'Variáveis --color-*, --radius-* etc. do Tailwind são inline e não existem no CSS. Em JS use as do tema: var(--rendra-primary), var(--rendra-chart-1), var(--rendra-shape-control).',\n },\n {\n id: 'svg-marca',\n test: /from\\s+['\"][^'\"]*brand\\/assets[^'\"]*['\"]/g,\n message:\n 'SVG de marca importado fora de src/brand. Leia o logotipo e o símbolo via useBrand().',\n },\n {\n id: 'classe-dinamica',\n // O Tailwind só gera classes escritas por inteiro no código: `p-${n}` não existe no CSS.\n test: /(?<![\\w-])(?:[a-z]+:)*-?(?:p[xytrbl]?|m[xytrbl]?|gap(?:-[xy])?|w|h|size|min-[wh]|max-[wh]|inset|top|left|right|bottom|z|text|bg|border(?:-[xytrbl])?|rounded(?:-[a-z]+)?|grid-cols|grid-rows|col-span|row-span|space-[xy]|translate-[xy]|opacity|font|leading|tracking|shadow|ring|fill|stroke|line-clamp|basis|order)-\\$\\{/g,\n message:\n 'Classe montada por template string não é gerada pelo Tailwind. Escreva a classe inteira (mapa de valores) ou use variável CSS.',\n skipLine: (line) => /^\\s*(\\/\\/|\\*|\\/\\*)/.test(line),\n },\n {\n id: 'texto-estreito',\n test: /<p\\s[^>]*className=[\"'{][^>]*max-w-/g,\n message:\n 'Texto ocupa 100% da largura disponível. Limite de largura (max-w-*) em parágrafo só quando o layout pedir outra medida.',\n },\n {\n id: 'primaria-como-texto',\n test: /(?<![\\w-])(?:[\\w-]+:)*text-primary(?![\\w-])/g,\n message:\n 'Primária como texto usa text-primary-text (tom que passa AA no claro e no escuro). text-primary é só para o preenchimento.',\n },\n]\n\n/**\n * Varre o texto linha a linha contra as cinco regras de uma linha (`var-inline`, `svg-marca`,\n * `classe-dinamica`, `texto-estreito`, `primaria-como-texto`). Por linha, as regras saem na\n * ordem da lista acima.\n */\nexport function regrasPorLinha(text: string): AuditViolation[] {\n const found: AuditViolation[] = []\n text.split('\\n').forEach((line, i) => {\n for (const regra of REGRAS_POR_LINHA) {\n if (regra.skipLine?.(line)) continue\n regra.test.lastIndex = 0\n if (regra.test.test(line)) {\n found.push({ line: i + 1, rule: regra.id, message: regra.message, source: line.trim() })\n }\n }\n })\n return found\n}\n\nconst NOME_PROIBIDO = /(Mobile|Simples|Simple|ComBusca|Grande|Pequeno|Small|Large)\\.(t|j)sx?$/i\nconst NOME_PROIBIDO_KEBAB = /-(mobile|simples|simple|com-busca|grande|pequeno)\\.(t|j)sx?$/i\n\n/** `componente-duplicado`: pelo NOME do arquivo (variante mobile ou paralela). Linha 0. */\nexport function componenteDuplicado(caminho: string): AuditViolation | undefined {\n if (!NOME_PROIBIDO.test(caminho) && !NOME_PROIBIDO_KEBAB.test(caminho)) return undefined\n return {\n line: 0,\n rule: 'componente-duplicado',\n message: 'Arquivo de variante paralela ou mobile. Resolva com props no componente único.',\n source: '',\n }\n}\n\n/** `css-fora-do-lugar`: quem chama já decidiu que o `.css` está fora das pastas de marca. */\nexport function cssForaDoLugar(): AuditViolation {\n return {\n line: 0,\n rule: 'css-fora-do-lugar',\n message:\n 'CSS fora de src/styles e src/brand. Estilo de componente é classe do Tailwind; token vai em globals.css; marca, em theme.css.',\n source: '',\n }\n}\n\nconst BOTAO_SOLTO =\n /<CardContent\\b[^>]*>\\s*(?:<Stack\\b[^>]*>\\s*)?<Button\\b|<Button\\b[^>]*\\bself-(?:start|end|center)\\b/g\n\n/** `botao-solto`: olha o arquivo inteiro (JSX em várias linhas); só nas telas do sistema. */\nexport function botaoSolto(text: string): AuditViolation[] {\n return [...text.matchAll(BOTAO_SOLTO)].map((m) => ({\n line: text.slice(0, m.index).split('\\n').length,\n rule: 'botao-solto',\n message:\n 'Botão solto no conteúdo. Ação de card vai em CardHeader actions; da tela, no PageHeader actions ou na ActionBar.',\n source: m[0].split('\\n')[0]!.trim(),\n }))\n}\n\n/** `texto-orientativo` (regra C7, em help-length.ts), no formato de `AuditViolation`. */\nexport function textoOrientativo(text: string): AuditViolation[] {\n return checkGuidance(text).map((p) => ({\n line: p.line,\n rule: p.id,\n message: p.message,\n source: p.src,\n }))\n}\n\n/** `variavel-sem-prefixo-rendra` (em var-prefix.ts), no formato de `AuditViolation`. */\nexport function variavelSemPrefixo(text: string): AuditViolation[] {\n return checkVarPrefix(text).map((p) => ({\n line: p.line,\n rule: 'variavel-sem-prefixo-rendra',\n message: p.message,\n source: p.src,\n }))\n}\n","/*\n * A varredura completa, com as 17 regras (as sete genéricas de `auditar.ts` mais as dez de\n * `regras-extras.ts`). É o que `rendra auditar --all` e o `check:rules` do repositório\n * (scripts/check-design-rules.mjs) chamam: a mesma lógica, em dois modos.\n *\n * - `cli`: o modo do projeto de destino. Raiz como em `auditar` (`src` se existir, senão a\n * pasta), sem `node_modules`/`dist`/`build`, sem teste nem story, `ignorar` e `pastas` do\n * projeto, pastas de marca e de telas parametrizáveis. Saída ordenada por arquivo e linha.\n * - `repositorio`: o modo do `check:rules`. Varre só `src`, sem pular nada (teste e story\n * entram), com as pastas deste repositório, e NÃO ordena: a saída segue a ordem da varredura\n * e, por arquivo, a ordem das regras abaixo, a mesma de sempre.\n *\n * Ordem das regras por arquivo (ela decide a ordem impressa no modo `repositorio`):\n * 1. `componente-duplicado` (pelo nome); 2. `variavel-sem-prefixo-rendra`; 3. arquivo de\n * marca: para aqui; 4. `.css`: `css-fora-do-lugar` e para; 5. nas telas: `texto-orientativo` e\n * `botao-solto`; 6. as sete genéricas; 7. as cinco regras de uma linha.\n *\n * Imports relativos com extensão `.ts`: o `check:rules` carrega esta cadeia direto no Node\n * (type stripping), que não resolve import sem extensão. Só `import type` para tipos, e nada\n * que o Node não apague (sem enum, namespace ou parameter property).\n */\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport {\n IDS_REGRAS_GENERICAS,\n auditLines,\n casaPrefixo,\n coletarArquivos,\n EXTENSAO_VARRIDA,\n percorrer,\n relativoA,\n} from './auditar.ts'\nimport type { FileAuditViolation, OpcoesAuditar } from './auditar.ts'\nimport {\n IDS_REGRAS_EXTRAS,\n botaoSolto,\n componenteDuplicado,\n cssForaDoLugar,\n regrasPorLinha,\n textoOrientativo,\n variavelSemPrefixo,\n} from './regras-extras.ts'\n\n/** Os 17 identificadores de regra, na ordem da documentação (genéricas e depois extras). */\nexport const IDS_TODAS_AS_REGRAS: string[] = [...IDS_REGRAS_GENERICAS, ...IDS_REGRAS_EXTRAS]\n\nexport interface OpcoesAuditarTudo extends OpcoesAuditar {\n modo?: 'cli' | 'repositorio'\n /** Pastas de marca (relativas a `cwd`): só passam pelo prefixo `--rendra-`. */\n pastasMarca?: string[]\n /** Pastas de telas do sistema (relativas a `cwd`): `texto-orientativo` e `botao-solto`. */\n pastasTelas?: string[]\n}\n\nexport interface ResultadoAuditarTudo {\n violacoes: FileAuditViolation[]\n /** Quantos arquivos foram varridos (o `check:rules` imprime esse número). */\n arquivos: number\n}\n\n/** Padrões do boilerplate Rendra, usados quando o projeto não diz outra coisa. */\nexport const PASTAS_MARCA_PADRAO = ['src/brand', 'src/styles']\nexport const PASTAS_TELAS_PADRAO = ['src/pages/app']\n// src/cli entra na exceção só no repositório do próprio Rendra: lá moram as regras, com o nome\n// e o texto de cada uma escritos por extenso, e o verificador acusaria a si mesmo.\nconst PASTAS_MARCA_REPOSITORIO = [...PASTAS_MARCA_PADRAO, 'src/cli']\n\n/** Arquivos do modo `repositorio`: tudo sob `src`, sem pular nada, na ordem do sistema. */\nfunction arquivosDoRepositorio(cwd: string): string[] {\n const src = join(cwd, 'src')\n if (!existsSync(src)) return []\n return percorrer(src, () => false).filter((f) => EXTENSAO_VARRIDA.test(f))\n}\n\n/**\n * Varre `cwd` com as 17 regras. Não lê `rendra.config.json` (quem lê é `executarAuditar`),\n * não imprime e não lança.\n */\nexport function auditarTudo(cwd: string, opcoes: OpcoesAuditarTudo = {}): ResultadoAuditarTudo {\n const repositorio = opcoes.modo === 'repositorio'\n const marca = opcoes.pastasMarca ?? (repositorio ? PASTAS_MARCA_REPOSITORIO : PASTAS_MARCA_PADRAO)\n const telas = opcoes.pastasTelas ?? PASTAS_TELAS_PADRAO\n const ligada = (id: string) => opcoes.regras?.[id] !== false\n\n // No repositório vale a semântica de sempre (`startsWith` no caminho absoluto, sem `/` final);\n // no projeto de destino, pasta de verdade (`src/brand` não casa `src/brand-novo`).\n const dentro = (arquivo: string, rel: string, pastas: string[]) =>\n repositorio ? pastas.some((p) => arquivo.startsWith(join(cwd, p))) : casaPrefixo(rel, pastas)\n\n const arquivos = repositorio ? arquivosDoRepositorio(cwd) : coletarArquivos(cwd, opcoes)\n const problemas: FileAuditViolation[] = []\n const emitir = (file: string, achados: Omit<FileAuditViolation, 'file'>[]) => {\n for (const a of achados) if (ligada(a.rule)) problemas.push({ file, ...a })\n }\n\n for (const arquivo of arquivos) {\n const rel = relativoA(cwd, arquivo)\n const duplicado = componenteDuplicado(repositorio ? arquivo : rel)\n if (duplicado) emitir(rel, [duplicado])\n const texto = readFileSync(arquivo, 'utf8')\n emitir(rel, variavelSemPrefixo(texto))\n\n if (dentro(arquivo, rel, marca)) continue\n if (arquivo.endsWith('.css')) {\n emitir(rel, [cssForaDoLugar()])\n continue\n }\n if (dentro(arquivo, rel, telas)) {\n emitir(rel, textoOrientativo(texto))\n emitir(rel, botaoSolto(texto))\n }\n emitir(rel, auditLines(texto))\n emitir(rel, regrasPorLinha(texto))\n }\n\n if (!repositorio) {\n problemas.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line)\n }\n return { violacoes: problemas, arquivos: arquivos.length }\n}\n","/*\n * Leitura dos argumentos de `rendra auditar`: função pura, para o `bin` ficar fino e a regra\n * ter teste. Aceita, em qualquer ordem:\n * pasta [pasta...] uma ou mais pastas posicionais\n * --all liga a varredura completa (as 17 regras)\n * --ignore a,b pastas a pular; vale também `--ignore a --ignore b` e\n * `--ignore=a,b`. O valor nunca vira pasta posicional.\n * --help, -h a ajuda geral\n * Qualquer outro argumento que comece com `-` é flag desconhecida: erro, nada é varrido.\n */\n\n/** As flags que `rendra auditar` entende. */\nexport const FLAGS_AUDITAR = ['--all', '--ignore', '--help'] as const\n\nexport interface ArgumentosAuditar {\n pastas: string[]\n ignorar: string[]\n todas: boolean\n ajuda: boolean\n}\n\nconst MENSAGEM_SEM_VALOR =\n 'Falta o valor de --ignore. Use --ignore a,b, --ignore a --ignore b ou --ignore=a,b.'\n\nconst itens = (valor: string) =>\n valor\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s !== '')\n\n/** Lê os argumentos que vêm depois de `auditar`. Erro volta como `{ erro }`, nunca lança. */\nexport function lerArgumentosAuditar(rest: string[]): ArgumentosAuditar | { erro: string } {\n const lido: ArgumentosAuditar = { pastas: [], ignorar: [], todas: false, ajuda: false }\n for (let i = 0; i < rest.length; i++) {\n const arg = rest[i]!\n if (arg === '--all') {\n lido.todas = true\n } else if (arg === '--help' || arg === '-h') {\n lido.ajuda = true\n } else if (arg === '--ignore' || arg.startsWith('--ignore=')) {\n let bruto: string | undefined\n if (arg === '--ignore') {\n const proximo = rest[i + 1]\n if (proximo !== undefined && !proximo.startsWith('-')) {\n bruto = proximo\n i++\n }\n } else {\n bruto = arg.slice('--ignore='.length)\n }\n const valores = bruto === undefined ? [] : itens(bruto)\n if (valores.length === 0) return { erro: MENSAGEM_SEM_VALOR }\n lido.ignorar.push(...valores)\n } else if (arg.startsWith('-')) {\n return { erro: `Flag desconhecida: ${arg}. Flags aceitas: ${FLAGS_AUDITAR.join(', ')}.` }\n } else {\n lido.pastas.push(arg)\n }\n }\n return lido\n}\n","/*\n * `rendra.config.json`: a configuração opcional do `rendra auditar`, lida da pasta base do\n * projeto de destino (nunca deste repositório). Arquivo ausente = config vazia, e o padrão da\n * CLI não muda. Erro (JSON inválido, chave desconhecida, tipo errado, regra desconhecida) volta\n * como valor `{ erro }`, em português, nunca como exceção: quem chama (`executarAuditar`) o\n * repassa ao `bin`, que imprime e sai com 1.\n *\n * Chaves (todas opcionais):\n * pastas pastas a varrer, relativas à base (substitui o atalho para `src`)\n * ignorar pastas a pular, por prefixo de pasta (sem glob)\n * regras { \"<id>\": false } desliga a regra de identificador `<id>`\n * pastasMarca pastas de marca: só passam pelo prefixo --rendra- (com `--all`)\n * pastasTelas pastas de telas do sistema: texto-orientativo e botao-solto (com `--all`)\n */\nimport { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { IDS_TODAS_AS_REGRAS } from './auditar-tudo.ts'\n\nexport const NOME_ARQUIVO_CONFIG = 'rendra.config.json'\nexport const CHAVES_CONFIG = ['pastas', 'ignorar', 'regras', 'pastasMarca', 'pastasTelas'] as const\nconst CHAVES_LISTA = ['pastas', 'ignorar', 'pastasMarca', 'pastasTelas'] as const\n\nexport interface ConfigAuditar {\n pastas?: string[]\n ignorar?: string[]\n regras?: Record<string, boolean>\n pastasMarca?: string[]\n pastasTelas?: string[]\n}\n\nexport type ResultadoConfig = { config: ConfigAuditar } | { erro: string }\n\nconst ehObjeto = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v)\n\nconst erro = (mensagem: string): { erro: string } => ({\n erro: `${NOME_ARQUIVO_CONFIG}: ${mensagem}`,\n})\n\n/** Lê e valida `rendra.config.json` em `base`. Ausente devolve `{ config: {} }`. */\nexport function carregarConfig(base: string): ResultadoConfig {\n const caminho = join(base, NOME_ARQUIVO_CONFIG)\n let texto: string\n try {\n texto = readFileSync(caminho, 'utf8')\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === 'ENOENT') return { config: {} }\n return erro(`não consegui ler o arquivo (${(e as Error).message}).`)\n }\n let dados: unknown\n try {\n dados = JSON.parse(texto.charCodeAt(0) === 0xfeff ? texto.slice(1) : texto)\n } catch (e) {\n return erro(`JSON inválido (${(e as Error).message}).`)\n }\n if (!ehObjeto(dados)) return erro('o conteúdo precisa ser um objeto JSON ({ ... }).')\n\n for (const chave of Object.keys(dados)) {\n if (!(CHAVES_CONFIG as readonly string[]).includes(chave)) {\n return erro(`chave desconhecida \"${chave}\". Chaves aceitas: ${CHAVES_CONFIG.join(', ')}.`)\n }\n }\n const config: ConfigAuditar = {}\n for (const chave of CHAVES_LISTA) {\n const valor = dados[chave]\n if (valor === undefined) continue\n if (!Array.isArray(valor) || !valor.every((x) => typeof x === 'string')) {\n return erro(`\"${chave}\" precisa ser uma lista de textos.`)\n }\n config[chave] = valor as string[]\n }\n if (dados.regras !== undefined) {\n if (!ehObjeto(dados.regras)) return erro('\"regras\" precisa ser um objeto ({ \"<id>\": false }).')\n const regras: Record<string, boolean> = {}\n for (const [id, ligada] of Object.entries(dados.regras)) {\n if (!IDS_TODAS_AS_REGRAS.includes(id)) {\n return erro(\n `regra desconhecida \"${id}\". Regras válidas: ${IDS_TODAS_AS_REGRAS.join(', ')}.`,\n )\n }\n if (typeof ligada !== 'boolean') return erro(`\"regras.${id}\" precisa ser true ou false.`)\n regras[id] = ligada\n }\n config.regras = regras\n }\n return { config }\n}\n","/*\n * Tudo o que `rendra auditar` decide, como função: argumentos, base, config, precedência e a\n * escolha entre `auditar` (sete regras genéricas) e `auditarTudo` (as 17). O `bin` só importa\n * esta função, imprime o resultado e define o código de saída; erro volta como valor, nunca\n * como exceção.\n *\n * Base e caminhos:\n * - exatamente uma pasta posicional: ela é a base (`file` sai relativo a ela e o\n * `rendra.config.json` é lido dela); o `pastas` do config dela continua valendo;\n * - zero ou duas ou mais posicionais: a base é o cwd do processo; duas ou mais substituem\n * `pastas` (do config ou o atalho para `src`);\n * - `ignorar`, `pastas`, `pastasMarca`, `pastasTelas` e `file` são relativos à base;\n * - pasta (posicional ou do config) que resolve fora da base é erro, sem varrer nada.\n * Precedência: a flag substitui a chave do config (`--ignore` substitui `ignorar`), não soma.\n */\nimport { isAbsolute, relative, resolve, sep } from 'node:path'\nimport { auditar } from './auditar.ts'\nimport type { FileAuditViolation, OpcoesAuditar } from './auditar.ts'\nimport { auditarTudo } from './auditar-tudo.ts'\nimport { lerArgumentosAuditar } from './argumentos.ts'\nimport { carregarConfig } from './config.ts'\nimport { formatHelp } from './help.ts'\n\nexport type ResultadoExecucao =\n { violacoes: FileAuditViolation[] } | { erro: string } | { ajuda: string }\n\n/**\n * Pasta relativa à base, com `/`, ou `undefined` quando resolve fora dela. Pasta absoluta\n * dentro da base vale; a própria base vira `.`.\n */\nfunction pastaNaBase(base: string, pasta: string): string | undefined {\n const rel = relative(base, resolve(base, pasta))\n if (rel === '..' || rel.startsWith('..' + sep) || isAbsolute(rel)) return undefined\n return rel === '' ? '.' : rel.split(sep).join('/')\n}\n\n/** Roda `rendra auditar` com os argumentos de `rest` (o que vem depois de `auditar`). */\nexport function executarAuditar(rest: string[], cwdProcesso: string): ResultadoExecucao {\n const args = lerArgumentosAuditar(rest)\n if ('erro' in args) return { erro: args.erro }\n if (args.ajuda) return { ajuda: formatHelp() }\n\n const base = args.pastas.length === 1 ? resolve(cwdProcesso, args.pastas[0]!) : cwdProcesso\n const lida = carregarConfig(base)\n if ('erro' in lida) return { erro: lida.erro }\n const config = lida.config\n\n const pedidas = args.pastas.length >= 2 ? args.pastas : (config.pastas ?? [])\n const pastas: string[] = []\n for (const pasta of pedidas) {\n const dentro = pastaNaBase(base, pasta)\n if (dentro === undefined) {\n return { erro: `A pasta \"${pasta}\" fica fora de ${base}. Use só pastas dentro do projeto.` }\n }\n pastas.push(dentro)\n }\n\n const opcoes: OpcoesAuditar = {\n ...(pastas.length > 0 ? { pastas } : {}),\n ignorar: args.ignorar.length > 0 ? args.ignorar : (config.ignorar ?? []),\n ...(config.regras ? { regras: config.regras } : {}),\n }\n if (args.todas) {\n const { violacoes } = auditarTudo(base, {\n ...opcoes,\n ...(config.pastasMarca ? { pastasMarca: config.pastasMarca } : {}),\n ...(config.pastasTelas ? { pastasTelas: config.pastasTelas } : {}),\n })\n return { violacoes }\n }\n return { violacoes: auditar(base, opcoes) }\n}\n"],"mappings":"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"}
package/dist/cli/help.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! Rendra Design System v2.3.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
1
+ /*! Rendra Design System v2.5.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
2
  //#region src/cli/help.ts
3
3
  /** Linha final de autoria, igual em toda saída publicável (CLI, banner do pacote). */
4
4
  var AUTHOR_LINE = "Rendra Design System, por Bruno Magalhaes: brunomagalhaes.me · instagram.com/brunomagalhaes.me";
@@ -6,7 +6,12 @@ function formatHelp() {
6
6
  return `Uso: rendra <codigos|auditar|trocar> ...
7
7
 
8
8
  rendra codigos lista o catálogo de códigos de componente
9
- rendra auditar [pasta] regras genéricas de DESIGN_RULES.md (padrão: pasta atual)
9
+ rendra auditar [pasta...] [--all] [--ignore a,b]
10
+ regras de DESIGN_RULES.md (padrão: pasta atual, sete
11
+ regras genéricas); --all liga as 17 regras do
12
+ check:rules; --ignore pula pastas; rendra.config.json
13
+ na pasta do projeto guarda pastas, ignorar, regras,
14
+ pastasMarca e pastasTelas
10
15
  rendra trocar <DE> <PARA> [--dry-run] troca a variante DE pela PARA no projeto
11
16
 
12
17
  ${AUTHOR_LINE}`;
@@ -1 +1 @@
1
- {"version":3,"file":"help.js","names":[],"sources":["../../src/cli/help.ts"],"sourcesContent":["/*\n * `rendra` sem argumento ou `rendra --help`: texto de uso dos três subcomandos, terminado\n * pela linha de autoria (decisão do autor: todo o publicável leva essa assinatura, igual ao\n * banner do CSS/JS em scripts/lib/pkg-banner.ts). Função pura: bin/rendra.mjs decide quando\n * chamar e onde imprimir.\n */\n\n/** Linha final de autoria, igual em toda saída publicável (CLI, banner do pacote). */\nexport const AUTHOR_LINE =\n 'Rendra Design System, por Bruno Magalhaes: brunomagalhaes.me · instagram.com/brunomagalhaes.me'\n\nexport function formatHelp(): string {\n return `Uso: rendra <codigos|auditar|trocar> ...\n\n rendra codigos lista o catálogo de códigos de componente\n rendra auditar [pasta] regras genéricas de DESIGN_RULES.md (padrão: pasta atual)\n rendra trocar <DE> <PARA> [--dry-run] troca a variante DE pela PARA no projeto\n\n${AUTHOR_LINE}`\n}\n"],"mappings":";;;AAQA,IAAa,cACX;AAEF,SAAgB,aAAqB;CACnC,OAAO;;;;;;EAMP;AACF"}
1
+ {"version":3,"file":"help.js","names":[],"sources":["../../src/cli/help.ts"],"sourcesContent":["/*\n * `rendra` sem argumento ou `rendra --help`: texto de uso dos três subcomandos, terminado\n * pela linha de autoria (decisão do autor: todo o publicável leva essa assinatura, igual ao\n * banner do CSS/JS em scripts/lib/pkg-banner.ts). Função pura: bin/rendra.mjs decide quando\n * chamar e onde imprimir.\n */\n\n/** Linha final de autoria, igual em toda saída publicável (CLI, banner do pacote). */\nexport const AUTHOR_LINE =\n 'Rendra Design System, por Bruno Magalhaes: brunomagalhaes.me · instagram.com/brunomagalhaes.me'\n\nexport function formatHelp(): string {\n return `Uso: rendra <codigos|auditar|trocar> ...\n\n rendra codigos lista o catálogo de códigos de componente\n rendra auditar [pasta...] [--all] [--ignore a,b]\n regras de DESIGN_RULES.md (padrão: pasta atual, sete\n regras genéricas); --all liga as 17 regras do\n check:rules; --ignore pula pastas; rendra.config.json\n na pasta do projeto guarda pastas, ignorar, regras,\n pastasMarca e pastasTelas\n rendra trocar <DE> <PARA> [--dry-run] troca a variante DE pela PARA no projeto\n\n${AUTHOR_LINE}`\n}\n"],"mappings":";;;AAQA,IAAa,cACX;AAEF,SAAgB,aAAqB;CACnC,OAAO;;;;;;;;;;;EAWP;AACF"}
@@ -1,5 +1,5 @@
1
- /*! Rendra Design System v2.3.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
- import { f as getCatalogEntry } from "../components-Cq_PmN4y.js";
1
+ /*! Rendra Design System v2.5.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
+ import { f as getCatalogEntry } from "../components-DkpspH9h.js";
3
3
  import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
4
4
  import { join, relative, sep } from "node:path";
5
5
  //#region src/cli/trocar.ts
@@ -1,4 +1,4 @@
1
- /*! Rendra Design System v2.3.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
1
+ /*! Rendra Design System v2.5.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
2
  import { join } from "node:path";
3
3
  import { createRequire } from "node:module";
4
4
  import { pathToFileURL } from "node:url";
@@ -1,4 +1,4 @@
1
- /*! Rendra Design System v2.3.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
1
+ /*! Rendra Design System v2.5.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
2
  import { clsx } from "clsx";
3
3
  import { extendTailwindMerge } from "tailwind-merge";
4
4
  //#region src/lib/cn.ts
@@ -19,4 +19,4 @@ function cn(...inputs) {
19
19
  //#endregion
20
20
  export { cn as t };
21
21
 
22
- //# sourceMappingURL=cn-DDZQKUVV.js.map
22
+ //# sourceMappingURL=cn-Cw7M5kEP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cn-DDZQKUVV.js","names":[],"sources":["../src/lib/cn.ts"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx'\nimport { extendTailwindMerge } from 'tailwind-merge'\n\n// Ensina o tailwind-merge sobre os tokens próprios, para que text-xs e text-primary-text\n// não sejam tratados como conflito, e h-control-md substitua h-12 corretamente. text-label e\n// text-help são tamanho (rótulo e orientação do campo); text-label-foreground é cor.\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [{ text: ['xs', 'sm', 'base', 'lg', 'xl', '2xl', '3xl', 'label', 'help'] }],\n },\n },\n})\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n"],"mappings":";;;;AAMA,IAAM,UAAU,oBAAoB,EAClC,QAAQ,EACN,aAAa,EACX,aAAa,CAAC,EAAE,MAAM;CAAC;CAAM;CAAM;CAAQ;CAAM;CAAM;CAAO;CAAO;CAAS;AAAM,EAAE,CAAC,EACzF,EACF,EACF,CAAC;AAED,SAAgB,GAAG,GAAG,QAAsB;CAC1C,OAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B"}
1
+ {"version":3,"file":"cn-Cw7M5kEP.js","names":[],"sources":["../src/lib/cn.ts"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx'\nimport { extendTailwindMerge } from 'tailwind-merge'\n\n// Ensina o tailwind-merge sobre os tokens próprios, para que text-xs e text-primary-text\n// não sejam tratados como conflito, e h-control-md substitua h-12 corretamente. text-label e\n// text-help são tamanho (rótulo e orientação do campo); text-label-foreground é cor.\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [{ text: ['xs', 'sm', 'base', 'lg', 'xl', '2xl', '3xl', 'label', 'help'] }],\n },\n },\n})\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n"],"mappings":";;;;AAMA,IAAM,UAAU,oBAAoB,EAClC,QAAQ,EACN,aAAa,EACX,aAAa,CAAC,EAAE,MAAM;CAAC;CAAM;CAAM;CAAQ;CAAM;CAAM;CAAO;CAAO;CAAS;AAAM,EAAE,CAAC,EACzF,EACF,EACF,CAAC;AAED,SAAgB,GAAG,GAAG,QAAsB;CAC1C,OAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B"}
@@ -1,4 +1,4 @@
1
- /*! Rendra Design System v2.3.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
1
+ /*! Rendra Design System v2.5.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
2
  //#region src/catalog/components.ts
3
3
  /** Formato do código: de 3 a 4 letras maiúsculas, hífen, três dígitos. */
4
4
  var COMPONENT_CODE_PATTERN = /^[A-Z]{3,4}-\d{3}$/;
@@ -147,8 +147,25 @@ var CATALOG = [
147
147
  name: "Grupo de botões",
148
148
  component: "ButtonGroup",
149
149
  file: "components/ui/button-group.tsx",
150
- variantProps: {},
151
- whenToUse: "Para botões encostados ou um controle segmentado de escolha única."
150
+ variantProps: { orientation: "horizontal" },
151
+ whenToUse: "Para botões encostados ou um controle segmentado de escolha única.",
152
+ isDefault: true
153
+ },
154
+ {
155
+ code: "BTNG-002",
156
+ name: "Grupo de botões vertical",
157
+ component: "ButtonGroup",
158
+ file: "components/ui/button-group.tsx",
159
+ variantProps: { orientation: "vertical" },
160
+ whenToUse: "Para botões de ação empilhados, na largura do grupo, com as bordas unidas."
161
+ },
162
+ {
163
+ code: "BTNG-003",
164
+ name: "Grupo de botões responsivo",
165
+ component: "ButtonGroup",
166
+ file: "components/ui/button-group.tsx",
167
+ variantProps: { orientation: "responsive" },
168
+ whenToUse: "Para botões que empilham no celular e ficam lado a lado a partir do tablet."
152
169
  },
153
170
  {
154
171
  code: "CAL-001",
@@ -797,4 +814,4 @@ function assertCatalogIntegrity() {
797
814
  //#endregion
798
815
  export { catalogByComponent as a, findComponentsWithoutDefault as c, findPresetCollisions as d, getCatalogEntry as f, assertCatalogIntegrity as i, findDuplicateCodes as l, CATALOG_EXCLUDED_FILES as n, filesMissingCatalogEntry as o, resolveCatalogCode as p, COMPONENT_CODE_PATTERN as r, findComponentsWithMultipleDefaults as s, CATALOG as t, findInvalidFormatCodes as u };
799
816
 
800
- //# sourceMappingURL=components-Cq_PmN4y.js.map
817
+ //# sourceMappingURL=components-DkpspH9h.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components-DkpspH9h.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 // ---------------------------------------------------------------- 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,C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"}