@rendra-ui/web 2.8.0 → 2.9.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.
- package/README.md +3 -3
- package/dist/base.css +1 -1
- package/dist/{button-CrSlVIsY.js → button-BcCBrlnt.js} +6 -6
- package/dist/{button-CrSlVIsY.js.map → button-BcCBrlnt.js.map} +1 -1
- package/dist/chart.js +7 -7
- package/dist/cli/auditar.js +1 -1
- package/dist/cli/codigos.js +2 -2
- package/dist/cli/executar-auditar.js +1 -1
- package/dist/cli/help.js +1 -1
- package/dist/cli/trocar.js +2 -2
- package/dist/cli/typescript-loader.js +1 -1
- package/dist/{cn-BlJHpkDs.js → cn-CpdCvlkP.js} +2 -2
- package/dist/{cn-BlJHpkDs.js.map → cn-CpdCvlkP.js.map} +1 -1
- package/dist/{components-6RpoJ2Od.js → components-Bus_Jh2R.js} +7 -4
- package/dist/components-Bus_Jh2R.js.map +1 -0
- package/dist/components.css +67 -26
- package/dist/document-viewer.js +4 -4
- package/dist/{dropdown-menu-BUGKtR6k.js → dropdown-menu-B3L1XSDf.js} +5 -5
- package/dist/{dropdown-menu-BUGKtR6k.js.map → dropdown-menu-B3L1XSDf.js.map} +1 -1
- package/dist/{brand-feedback-icon-CVux4pNh.js → empty-state-Bcx4M0Me.js} +64 -4
- package/dist/empty-state-Bcx4M0Me.js.map +1 -0
- package/dist/{features-max-BCIy1Ic-.js → features-max-CoyJ_kuK.js} +1 -1
- package/dist/flow.js +2818 -868
- package/dist/flow.js.map +1 -1
- package/dist/index.js +80 -465
- package/dist/index.js.map +1 -1
- package/dist/{motion-context-PJPj6X4g.js → motion-context-DWFl2xRr.js} +4 -4
- package/dist/{motion-context-PJPj6X4g.js.map → motion-context-DWFl2xRr.js.map} +1 -1
- package/dist/{motion-on-Bocf4Smc.js → motion-on-zwsBqYZL.js} +2 -2
- package/dist/{motion-on-Bocf4Smc.js.map → motion-on-zwsBqYZL.js.map} +1 -1
- package/dist/motion.js +2 -2
- package/dist/{rendra-provider-Do_qWjJC.js → rendra-provider-DuIhBatD.js} +3 -3
- package/dist/{rendra-provider-Do_qWjJC.js.map → rendra-provider-DuIhBatD.js.map} +1 -1
- package/dist/rich-text-editor.js +4 -4
- package/dist/router-bridge.js +2 -2
- package/dist/{timeline-xrMHeV92.js → toast-C7qYslCp.js} +464 -80
- package/dist/toast-C7qYslCp.js.map +1 -0
- package/dist/tokens.css +1 -1
- package/dist/{tooltip-to0h6aPe.js → tooltip-BSPO-bH4.js} +5 -5
- package/dist/{tooltip-to0h6aPe.js.map → tooltip-BSPO-bH4.js.map} +1 -1
- package/dist/types/components/ui/flow-config-panels.d.ts +10 -0
- package/dist/types/components/ui/flow-editor.d.ts +5 -0
- package/dist/types/components/ui/flow-sidebar.d.ts +21 -0
- package/dist/types/components/ui/flow-simulation-panel.d.ts +20 -0
- package/dist/types/components/ui/flow-viewer.d.ts +27 -10
- package/dist/types/flow.d.ts +1 -1
- package/dist/types/lib/flow-blocks.d.ts +122 -0
- package/dist/types/lib/flow-edit.d.ts +88 -0
- package/dist/types/lib/flow-layout.d.ts +3 -0
- package/dist/types/lib/flow-sim.d.ts +24 -0
- package/dist/types/lib/flow.d.ts +30 -80
- package/dist/{use-breakpoint-CM-yeDHJ.js → use-breakpoint-BGmY3ir-.js} +2 -2
- package/dist/{use-breakpoint-CM-yeDHJ.js.map → use-breakpoint-BGmY3ir-.js.map} +1 -1
- package/dist/{use-motion-presets-I4StrsCi.js → use-motion-presets-CmMLBQLI.js} +3 -3
- package/dist/{use-motion-presets-I4StrsCi.js.map → use-motion-presets-CmMLBQLI.js.map} +1 -1
- package/dist/widget-grid.js +2 -2
- package/package.json +2 -1
- package/dist/brand-feedback-icon-CVux4pNh.js.map +0 -1
- package/dist/components-6RpoJ2Od.js.map +0 -1
- package/dist/empty-state-i4e-LacG.js +0 -67
- package/dist/empty-state-i4e-LacG.js.map +0 -1
- package/dist/timeline-xrMHeV92.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"brand-feedback-icon-CVux4pNh.js","names":[],"sources":["../src/brand/brand-context.ts","../src/brand/use-brand.ts","../src/components/ui/brand-feedback-icon.tsx"],"sourcesContent":["import { createContext } from 'react'\nimport type { Shape } from '@/lib/shape'\nimport type { BrandConfig, PaletteConfig } from './types'\n\nexport type ColorMode = 'light' | 'dark' | 'system'\n\nexport interface BrandContextValue {\n brand: BrandConfig\n brands: BrandConfig[]\n setBrandId: (id: string) => void\n mode: ColorMode\n resolvedMode: 'light' | 'dark'\n setMode: (mode: ColorMode) => void\n /** Formato do template ativo (fixo por template). */\n shape: Shape\n /** Paleta de cores em uso (por padrão, a do próprio modelo). */\n palette: PaletteConfig\n palettes: PaletteConfig[]\n /** Usa a paleta de outro template; null volta às cores do próprio modelo. */\n setPaletteId: (id: string | null) => void\n /** Logotipo adequado para a sidebar com a paleta atual. */\n sidebarLogoVariant: 'light' | 'dark'\n}\n\nexport const BrandContext = createContext<BrandContextValue | null>(null)\n","import { useContext } from 'react'\nimport { BrandContext } from './brand-context'\n\nexport function useBrand() {\n const ctx = useContext(BrandContext)\n if (!ctx) throw new Error('useBrand precisa estar dentro de <BrandProvider>.')\n return ctx\n}\n","import { cva, type VariantProps } from 'class-variance-authority'\nimport { CircleCheck, CircleX, Info, TriangleAlert, type LucideIcon } from 'lucide-react'\nimport type { SVGProps } from 'react'\nimport { useBrand } from '@/brand/use-brand'\nimport type { FeedbackType } from '@/brand/types'\nimport { cn } from '@/lib/cn'\n\nconst sizes = {\n sm: 'size-icon-sm',\n md: 'size-icon-md',\n lg: 'size-icon-lg',\n xl: 'size-12',\n '2xl': 'size-16',\n} as const\n\nconst iconVariants = cva('relative inline-flex shrink-0', {\n variants: { size: sizes },\n defaultVariants: { size: 'md' },\n})\n\n/** Cor do estado (tinge o símbolo e, em statusBadge, o ícone ao lado). */\nconst stateText: Record<FeedbackType, string> = {\n success: 'text-success',\n error: 'text-destructive',\n warning: 'text-warning',\n info: 'text-info',\n}\n\n/** Ícone Lucide do selo ao lado do símbolo (statusBadge). */\nconst badgeIcons: Record<FeedbackType, LucideIcon> = {\n success: CircleCheck,\n error: CircleX,\n warning: TriangleAlert,\n info: Info,\n}\n\n/** Tamanho do ícone ao lado, proporcional ao do símbolo. */\nconst badgeIconSize: Record<keyof typeof sizes, string> = {\n sm: 'size-3',\n md: 'size-icon-sm',\n lg: 'size-icon-md',\n xl: 'size-icon-lg',\n '2xl': 'size-icon-lg',\n}\n\nconst badgeTone: Record<FeedbackType, string> = {\n success: 'bg-success text-success-foreground',\n error: 'bg-destructive text-destructive-foreground',\n warning: 'bg-warning text-warning-foreground',\n info: 'bg-info text-info-foreground',\n}\n\nexport const feedbackLabels: Record<FeedbackType, string> = {\n success: 'Sucesso',\n error: 'Erro',\n warning: 'Atenção',\n info: 'Informação',\n}\n\n/** Glifos universais de status desenhados em traço, herdando currentColor. */\nfunction StatusGlyph({\n type,\n animated,\n ...props\n}: { type: FeedbackType; animated?: boolean } & SVGProps<SVGSVGElement>) {\n // pathLength=1 normaliza o traço: o desenho anima de 1 a 0 em qualquer glifo.\n const draw = animated\n ? ({ pathLength: 1, strokeDasharray: 1, className: 'animate-draw' } as const)\n : {}\n const common = {\n viewBox: '0 0 12 12',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: 'round' as const,\n strokeLinejoin: 'round' as const,\n 'aria-hidden': true,\n ...props,\n }\n switch (type) {\n case 'success':\n return (\n <svg {...common}>\n <path d=\"M3 6.2 5.1 8.2 9 4\" {...draw} />\n </svg>\n )\n case 'error':\n return (\n <svg {...common}>\n <path d=\"M4 4l4 4M8 4 4 8\" {...draw} />\n </svg>\n )\n case 'warning':\n return (\n <svg {...common}>\n <path d=\"M6 3.2v3.3M6 8.8v0\" {...draw} />\n </svg>\n )\n case 'info':\n return (\n <svg {...common}>\n <path d=\"M6 3.2v0M6 5.5v3.3\" {...draw} />\n </svg>\n )\n }\n}\n\nexport interface BrandFeedbackIconProps extends VariantProps<typeof iconVariants> {\n type: FeedbackType\n /** Texto para leitores de tela. Sem ele o ícone é decorativo (o texto ao lado informa). */\n label?: string\n /**\n * Anima a entrada: o símbolo entra com mola e o glifo se desenha (check se formando,\n * X se riscando). O erro treme ao final. Respeita reduzir movimento.\n * Troque a key do componente para repetir a animação.\n */\n animated?: boolean\n /**\n * Cor do símbolo. `state` (padrão): a cor do estado (verde, vermelho, amarelo, azul).\n * `brand`: a cor primária da marca (`text-primary-text`); o selo de estado mantém a cor do\n * estado, para o significado não depender só da cor.\n */\n symbolTone?: 'state' | 'brand'\n /**\n * `false` (padrão): selo de estado sobreposto ao símbolo. `true`: o ícone do estado\n * (Lucide, na cor do estado) fica ao lado do símbolo, no lugar do selo sobreposto. Com um\n * SVG próprio em `brand.feedbackIcons[type]`, o SVG vence e nenhum selo é desenhado.\n */\n statusBadge?: boolean\n /**\n * Só vale com `animated`. `pop` (padrão): entra com mola, o glifo se desenha e o erro\n * treme. `encaixe`: entra em 240 ms, curva de saída suave, sem quique, sem desenho e sem\n * tremor. Com \"reduzir movimento\" do sistema, nenhuma animação roda.\n */\n animation?: 'pop' | 'encaixe'\n className?: string\n}\n\n/**\n * Ícone de feedback da marca: o símbolo da marca em currentColor, tingido pela cor\n * semântica, com um selo de status para que o significado não dependa só da cor.\n * Cada tipo pode ser substituído por um SVG próprio em brand.config.ts (feedbackIcons).\n */\nexport function BrandFeedbackIcon({\n type,\n size,\n label,\n animated = false,\n symbolTone = 'state',\n statusBadge = false,\n animation = 'pop',\n className,\n}: BrandFeedbackIconProps) {\n const { brand } = useBrand()\n const Custom = brand.feedbackIcons?.[type]\n const Symbol = brand.symbol\n const a11y = label\n ? ({ role: 'img', 'aria-label': label } as const)\n : ({ 'aria-hidden': true } as const)\n const encaixe = animation === 'encaixe'\n // Com `symbolTone=\"state\"` o texto do estado fica na raiz (como sempre); com `brand` sai da raiz.\n const rootTone = symbolTone === 'state' ? stateText[type] : undefined\n const symbolTonal = symbolTone === 'brand' && 'text-primary-text'\n const symbolAnim = animated && (encaixe ? 'animate-encaixe' : 'animate-pop')\n const badgeAnim = animated && (encaixe ? 'animate-encaixe' : 'animate-pop anim-delay-1')\n const BadgeIcon = badgeIcons[type]\n const sideBadge = statusBadge && !Custom\n\n return (\n <span\n data-slot=\"feedback-icon\"\n data-rendra=\"BFI-001\"\n className={cn(\n sideBadge ? 'relative inline-flex shrink-0 items-center gap-1' : iconVariants({ size }),\n rootTone,\n animated && !encaixe && type === 'error' && 'animate-shake',\n className,\n )}\n {...a11y}\n >\n {Custom ? (\n <Custom className={cn('size-full', symbolTonal, symbolAnim)} />\n ) : sideBadge ? (\n <>\n <Symbol className={cn(sizes[size ?? 'md'], symbolTonal, symbolAnim)} />\n <BadgeIcon\n aria-hidden\n className={cn('shrink-0', badgeIconSize[size ?? 'md'], stateText[type], badgeAnim)}\n />\n </>\n ) : (\n <>\n <Symbol className={cn('size-full mask-status-cutout', symbolTonal, symbolAnim)} />\n <span\n className={cn(\n 'absolute right-0 bottom-0 flex size-1/2 items-center justify-center rounded-full',\n badgeTone[type],\n badgeAnim,\n )}\n >\n <StatusGlyph type={type} animated={animated && !encaixe} className=\"size-full\" />\n </span>\n </>\n )}\n </span>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components-6RpoJ2Od.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, cada um com `confirm` também não literal), não um\n // literal de string/número/booleano, e o `rendra trocar` não tem como inventar um array,\n // então ele recusa a troca com uma mensagem clara (\"sem prop que os distinga\"), e a\n // variante certa fica documentada aqui.\n variantProps: {},\n whenToUse:\n 'Para um funil de etapas com cartões que se movem entre colunas, com status por cor ' +\n '(cadência da etapa e próxima atividade), valores empilhados no card e, com `toolbar`, ' +\n 'barra do quadro com busca, filtros, totais e Customizar.',\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.: Lixeira, Congelar, Perder, ' +\n 'Ganhar), mostrada num rodapé flutuante durante o arraste e no menu \"Mover para\", com ' +\n 'confirmação opcional por destino (e motivo, ao perder).',\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,C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"}
|
|
@@ -1,67 +0,0 @@
|
|
|
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 } from "./motion-context-PJPj6X4g.js";
|
|
4
|
-
import { t as useMotionPresets } from "./use-motion-presets-I4StrsCi.js";
|
|
5
|
-
import { t as BrandFeedbackIcon } from "./brand-feedback-icon-CVux4pNh.js";
|
|
6
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
//#region src/components/ui/empty-state.tsx
|
|
8
|
-
/** Estado vazio (e de erro) com o ícone de feedback da marca. */
|
|
9
|
-
function EmptyState({ title, description, type = "info", actions, size = "default", className }) {
|
|
10
|
-
const lib = useMotionLib();
|
|
11
|
-
const on = lib !== null;
|
|
12
|
-
const presets = useMotionPresets();
|
|
13
|
-
const Icon = on ? lib.m.span : "span";
|
|
14
|
-
const Title = on ? lib.m.p : "p";
|
|
15
|
-
const Description = on ? lib.m.p : "p";
|
|
16
|
-
const Actions = on ? lib.m.div : "div";
|
|
17
|
-
const part = (index) => {
|
|
18
|
-
if (!on) return {};
|
|
19
|
-
const enter = presets.slide("bottom", "short");
|
|
20
|
-
return {
|
|
21
|
-
...enter,
|
|
22
|
-
transition: {
|
|
23
|
-
...enter.transition,
|
|
24
|
-
...presets.stagger(index)
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
29
|
-
"data-rendra": "VAZ-001",
|
|
30
|
-
className: cn("flex flex-col items-center justify-center gap-4 text-center", size === "compact" ? "px-4 py-8" : "px-4 py-12 md:py-16", className),
|
|
31
|
-
children: [
|
|
32
|
-
/* @__PURE__ */ jsxs(Icon, {
|
|
33
|
-
className: "relative flex items-center justify-center",
|
|
34
|
-
...part(0),
|
|
35
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
36
|
-
"aria-hidden": true,
|
|
37
|
-
className: "absolute size-16 rounded-full bg-gradient-soft"
|
|
38
|
-
}), /* @__PURE__ */ jsx(BrandFeedbackIcon, {
|
|
39
|
-
type,
|
|
40
|
-
size: size === "compact" ? "xl" : "2xl",
|
|
41
|
-
className: "relative"
|
|
42
|
-
})]
|
|
43
|
-
}),
|
|
44
|
-
/* @__PURE__ */ jsxs("div", {
|
|
45
|
-
className: "flex w-full flex-col gap-1",
|
|
46
|
-
children: [/* @__PURE__ */ jsx(Title, {
|
|
47
|
-
className: "text-base font-semibold wrap-break-word",
|
|
48
|
-
...part(1),
|
|
49
|
-
children: title
|
|
50
|
-
}), description && /* @__PURE__ */ jsx(Description, {
|
|
51
|
-
className: "text-sm wrap-break-word text-muted-foreground",
|
|
52
|
-
...part(2),
|
|
53
|
-
children: description
|
|
54
|
-
})]
|
|
55
|
-
}),
|
|
56
|
-
actions && /* @__PURE__ */ jsx(Actions, {
|
|
57
|
-
className: "flex flex-wrap justify-center gap-3",
|
|
58
|
-
...part(3),
|
|
59
|
-
children: actions
|
|
60
|
-
})
|
|
61
|
-
]
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
//#endregion
|
|
65
|
-
export { EmptyState as t };
|
|
66
|
-
|
|
67
|
-
//# sourceMappingURL=empty-state-i4e-LacG.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"empty-state-i4e-LacG.js","names":[],"sources":["../src/components/ui/empty-state.tsx"],"sourcesContent":["import type { ElementType, ReactNode } from 'react'\nimport type { FeedbackType } from '@/brand/types'\nimport { BrandFeedbackIcon } from '@/components/ui/brand-feedback-icon'\nimport { cn } from '@/lib/cn'\nimport { useMotionLib, useMotionPresets } from '@/lib/motion'\n\nexport interface EmptyStateProps {\n title: string\n description?: ReactNode\n /** Tipo do ícone de feedback da marca. info para \"sem dados\", error para falha. */\n type?: FeedbackType\n /** Ações: no máximo uma principal e uma secundária. */\n actions?: ReactNode\n /** compact: dentro de tabela ou card pequeno. */\n size?: 'default' | 'compact'\n /**\n * Classes extras, que vencem as do componente. Para zerar o respiro vertical (por exemplo,\n * dentro de um card que já tem o seu) use `className=\"py-0 md:py-0\"`.\n */\n className?: string\n}\n\n/** Estado vazio (e de erro) com o ícone de feedback da marca. */\nexport function EmptyState({\n title,\n description,\n type = 'info',\n actions,\n size = 'default',\n className,\n}: EmptyStateProps) {\n const lib = useMotionLib()\n const on = lib !== null\n const presets = useMotionPresets()\n // Em `on` as quatro partes (ícone, título, descrição e ações) sobem em cascata de 60 ms, cada\n // uma com o deslize curto; a raiz em si não anima. Estado vazio é cota de encanto: ocasional,\n // sem teclado no caminho. Em `off` o HTML é o de sempre.\n const Icon: ElementType = on ? lib.m.span : 'span'\n const Title: ElementType = on ? lib.m.p : 'p'\n const Description: ElementType = on ? lib.m.p : 'p'\n const Actions: ElementType = on ? lib.m.div : 'div'\n const part = (index: number) => {\n if (!on) return {}\n const enter = presets.slide('bottom', 'short')\n return { ...enter, transition: { ...enter.transition, ...presets.stagger(index) } }\n }\n return (\n <div\n data-rendra=\"VAZ-001\"\n className={cn(\n 'flex flex-col items-center justify-center gap-4 text-center',\n size === 'compact' ? 'px-4 py-8' : 'px-4 py-12 md:py-16',\n className,\n )}\n >\n <Icon className=\"relative flex items-center justify-center\" {...part(0)}>\n <span aria-hidden className=\"absolute size-16 rounded-full bg-gradient-soft\" />\n <BrandFeedbackIcon\n type={type}\n size={size === 'compact' ? 'xl' : '2xl'}\n className=\"relative\"\n />\n </Icon>\n <div className=\"flex w-full flex-col gap-1\">\n <Title className=\"text-base font-semibold wrap-break-word\" {...part(1)}>\n {title}\n </Title>\n {description && (\n <Description className=\"text-sm wrap-break-word text-muted-foreground\" {...part(2)}>\n {description}\n </Description>\n )}\n </div>\n {actions && (\n <Actions className=\"flex flex-wrap justify-center gap-3\" {...part(3)}>\n {actions}\n </Actions>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;AAuBA,SAAgB,WAAW,EACzB,OACA,aACA,OAAO,QACP,SACA,OAAO,WACP,aACkB;CAClB,MAAM,MAAM,aAAa;CACzB,MAAM,KAAK,QAAQ;CACnB,MAAM,UAAU,iBAAiB;CAIjC,MAAM,OAAoB,KAAK,IAAI,EAAE,OAAO;CAC5C,MAAM,QAAqB,KAAK,IAAI,EAAE,IAAI;CAC1C,MAAM,cAA2B,KAAK,IAAI,EAAE,IAAI;CAChD,MAAM,UAAuB,KAAK,IAAI,EAAE,MAAM;CAC9C,MAAM,QAAQ,UAAkB;EAC9B,IAAI,CAAC,IAAI,OAAO,CAAC;EACjB,MAAM,QAAQ,QAAQ,MAAM,UAAU,OAAO;EAC7C,OAAO;GAAE,GAAG;GAAO,YAAY;IAAE,GAAG,MAAM;IAAY,GAAG,QAAQ,QAAQ,KAAK;GAAE;EAAE;CACpF;CACA,OACE,qBAAC,OAAD;EACE,eAAY;EACZ,WAAW,GACT,+DACA,SAAS,YAAY,cAAc,uBACnC,SACF;EANF,UAAA;GAQE,qBAAC,MAAD;IAAM,WAAU;IAA4C,GAAI,KAAK,CAAC;IAAtE,UAAA,CACE,oBAAC,QAAD;KAAM,eAAA;KAAY,WAAU;IAAkD,CAAA,GAC9E,oBAAC,mBAAD;KACQ;KACN,MAAM,SAAS,YAAY,OAAO;KAClC,WAAU;IACX,CAAA,CACG;;GACN,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,OAAD;KAAO,WAAU;KAA0C,GAAI,KAAK,CAAC;KAClE,UAAA;IACI,CAAA,GACN,eACC,oBAAC,aAAD;KAAa,WAAU;KAAgD,GAAI,KAAK,CAAC;KAC9E,UAAA;IACU,CAAA,CAEZ;;GACJ,WACC,oBAAC,SAAD;IAAS,WAAU;IAAsC,GAAI,KAAK,CAAC;IAChE,UAAA;GACM,CAAA;EAER;;AAET"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"timeline-xrMHeV92.js","names":[],"sources":["../src/components/app-shell/shell-context.ts","../src/components/ui/action-bar.tsx","../src/components/ui/alert.tsx","../src/components/ui/overlay-shell.tsx","../src/components/ui/modal.tsx","../src/components/ui/info-hint.tsx","../src/components/ui/card.tsx","../src/lib/lookup.ts","../src/hooks/use-lookup.ts","../src/lib/control.ts","../src/lib/masks.ts","../src/components/ui/input.tsx","../src/components/ui/picker-panel.tsx","../src/components/ui/drawer.tsx","../src/components/layout/tokens.ts","../src/components/ui/field.tsx","../src/components/ui/select.tsx","../src/hooks/use-fill-height.ts","../src/components/ui/timeline.tsx"],"sourcesContent":["import { createContext, useContext, type ReactNode } from 'react'\nimport type { ShellLayout } from './layout'\nimport type { NavigationTarget } from './navigation-utils'\nimport type {\n NavGroup,\n NavItem,\n ShellMenuItem,\n ShellNotificationsConfig,\n ShellUser,\n ShellUserMenuConfig,\n ShellWorkspacesConfig,\n} from './types'\n\nexport interface ShellContextValue {\n /** Layout efetivo: padrão interno + prop `layout` do AppShell + escolha do usuário. */\n layout: ShellLayout\n /** Altera uma opção de layout (guardada no navegador do usuário). */\n setLayout: <K extends keyof ShellLayout>(key: K, value: ShellLayout[K]) => void\n /** Altera várias opções de uma vez (ex.: um código de menu M1 a M6). */\n applyLayout: (partial: Partial<ShellLayout>) => void\n /** Volta ao layout padrão do projeto. */\n resetLayout: () => void\n /** Gaveta de navegação aberta no mobile. */\n mobileNavOpen: boolean\n setMobileNavOpen: (open: boolean) => void\n /**\n * Espaço do rodapé fixo da página, entre o conteúdo e a barra inferior. A ActionBar\n * sticky é desenhada aqui: fica sempre colada embaixo, na largura inteira.\n */\n footerSlot: HTMLElement | null\n /** Texto orientativo da tela (PageHeader help): o header mostra o ícone ao lado do título. */\n pageHelp: ReactNode\n setPageHelp: (help: ReactNode) => void\n /** Busca global (Ctrl+K). */\n searchOpen: boolean\n setSearchOpen: (open: boolean) => void\n /** Menu do sistema, recebido pela prop `navigation` do AppShell (obrigatória). */\n navigation: NavGroup[]\n /** Até 4 itens marcados `bottomNav`, calculados a partir de `navigation`. */\n bottomNavItems: NavItem[]\n /** Lista plana de destinos: busca global e cálculo do item ativo. */\n navigationTargets: NavigationTarget[]\n /** Usuário exibido no menu do avatar e no rodapé da sidebar. */\n user: ShellUser\n /** Itens do menu do avatar (ex.: \"Meu perfil\", \"Configurações\"). */\n userMenuItems: ShellMenuItem[]\n /** Chamado ao selecionar \"Sair\". Sem ele, o botão não faz nada. */\n onLogout?: () => void\n /** Rótulo do destino inicial na trilha do header. */\n homeLabel: string\n /** Ações rápidas da busca global (ex.: \"Novo cliente\"). */\n quickActions: ShellMenuItem[]\n /** Notificações do sino do header. Sem esta prop, o sino não aparece. */\n notifications?: ShellNotificationsConfig\n /** Submenus Tema, Template e Layout do menu do avatar. Sem esta prop, os três aparecem. */\n userMenu?: ShellUserMenuConfig\n /** Seletor de espaço no topo do menu do avatar. Sem esta prop, não aparece. */\n workspaces?: ShellWorkspacesConfig\n /** Logo que ocupa o lugar do título e da trilha no header, abaixo de `md`. */\n headerLogo?: ReactNode\n}\n\nexport const ShellContext = createContext<ShellContextValue | null>(null)\n\nexport function useShell() {\n const ctx = useContext(ShellContext)\n if (!ctx) throw new Error('useShell precisa estar dentro de <AppShell>.')\n return ctx\n}\n","import { MoreHorizontal } from 'lucide-react'\nimport { useContext, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\nimport { ShellContext } from '@/components/app-shell/shell-context'\nimport { Button } from '@/components/ui/button'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\nimport { cn } from '@/lib/cn'\n\nexport interface ActionBarAction {\n label: string\n onClick?: () => void\n icon?: ReactNode\n disabled?: boolean\n destructive?: boolean\n}\n\nexport interface ActionBarProps {\n /** Ação principal: sempre primária (ou destrutiva), 70% da largura. */\n primary: ActionBarAction & {\n type?: 'button' | 'submit'\n form?: string\n loading?: boolean\n loadingLabel?: string\n }\n /** Cancelar: sempre outline, 30% à esquerda. Sem ele, a principal ocupa 100%. */\n cancel?: ActionBarAction\n /** A partir da terceira ação: vão para o menu de três pontinhos. */\n secondary?: ActionBarAction[]\n /**\n * sticky: rodapé fixo das telas de formulário. Fica sempre colado embaixo, na largura\n * inteira, fora da área rolável (nunca sobe, mesmo com formulário curto). Em drawer e\n * modal o rodapé já é fixo; no wizard os botões seguem junto do card. Como o botão fica\n * fora do <form>, use primary.form com o id do formulário para enviar.\n */\n sticky?: boolean\n className?: string\n}\n\n/**\n * Barra de ações única, com a regra de botões do sistema:\n * 1 botão = 100%; 2 botões = cancelar 30% + principal 70%; 3 ou mais = extras no menu.\n * Vale para drawer, modal e formulário em página, em qualquer tamanho de tela.\n */\nexport function ActionBar({ primary, cancel, secondary, sticky, className }: ActionBarProps) {\n const slot = useContext(ShellContext)?.footerSlot\n const hasMenu = Boolean(secondary?.length)\n const layout = cancel\n ? hasMenu\n ? 'grid-actions-3'\n : 'grid-actions-2'\n : hasMenu\n ? 'grid-actions-3'\n : ''\n\n const bar = (\n <div\n data-rendra=\"ACB-001\"\n className={cn(\n sticky && 'border-t bg-card px-4 pt-4 pb-safe md:px-6',\n // Fora do AppShell (Storybook, telas soltas): fixo no fim da área rolável.\n sticky && !slot && 'sticky bottom-0 z-20',\n className,\n )}\n >\n <div className={cn('grid gap-3', layout || 'grid-cols-1', sticky && 'w-full')}>\n {hasMenu && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" iconOnly aria-label=\"Mais ações\">\n <MoreHorizontal />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" side=\"top\">\n {secondary!.map((a) => (\n <DropdownMenuItem\n key={a.label}\n onSelect={a.onClick}\n disabled={a.disabled}\n destructive={a.destructive}\n >\n {a.icon}\n {a.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n {cancel ? (\n <Button\n variant=\"outline\"\n icon={cancel.icon}\n onClick={cancel.onClick}\n disabled={cancel.disabled || primary.loading}\n fullWidth\n >\n {cancel.label}\n </Button>\n ) : hasMenu ? (\n <span aria-hidden />\n ) : null}\n <Button\n type={primary.type ?? 'button'}\n form={primary.form}\n variant={primary.destructive ? 'destructive' : 'primary'}\n icon={primary.icon}\n onClick={primary.onClick}\n disabled={primary.disabled}\n loading={primary.loading}\n fullWidth\n >\n {primary.loading ? (primary.loadingLabel ?? 'Salvando...') : primary.label}\n </Button>\n </div>\n </div>\n )\n return sticky && slot ? createPortal(bar, slot) : bar\n}\n","import { cva, type VariantProps } from 'class-variance-authority'\nimport { X } from 'lucide-react'\nimport type { ReactNode } from 'react'\nimport { useBrand } from '@/brand/use-brand'\nimport type { FeedbackType } from '@/brand/types'\nimport { BrandFeedbackIcon } from '@/components/ui/brand-feedback-icon'\nimport { cn } from '@/lib/cn'\n\n/**\n * Alert único do sistema: ícone da marca à esquerda, título em destaque e descrição.\n * O tipo é prop; o formato vem do template ativo (quadrado, meio-termo ou arredondado).\n */\nconst alertVariants = cva('flex w-full min-w-0 items-start gap-3 rounded-control border', {\n variants: {\n type: {\n success: 'border-success/25 bg-success-soft text-success-soft-foreground',\n error: 'border-destructive/25 bg-destructive-soft text-destructive-soft-foreground',\n warning: 'border-warning/25 bg-warning-soft text-warning-soft-foreground',\n info: 'border-info/25 bg-info-soft text-info-soft-foreground',\n },\n },\n defaultVariants: { type: 'info' },\n})\n\nexport interface AlertProps extends VariantProps<typeof alertVariants> {\n type: FeedbackType\n /** Título curto, em negrito. */\n title: ReactNode\n /** Texto de apoio abaixo do título. */\n description?: ReactNode\n /** Ação opcional à direita (ex.: botão \"Desfazer\"). */\n action?: ReactNode\n /** Mostra botão de fechar. */\n onDismiss?: () => void\n /** Anima o ícone na entrada (check se formando, X se riscando). */\n animated?: boolean\n className?: string\n}\n\nexport function Alert({\n type,\n title,\n description,\n action,\n onDismiss,\n animated = false,\n className,\n}: AlertProps) {\n const { shape } = useBrand()\n const pill = shape === 'pill'\n return (\n <div\n role={type === 'error' || type === 'warning' ? 'alert' : 'status'}\n data-rendra=\"ALRT-001\"\n className={cn(\n alertVariants({ type }),\n pill ? 'items-center py-3 pr-4 pl-4 md:pr-6' : 'p-4',\n className,\n )}\n >\n <BrandFeedbackIcon\n type={type}\n size=\"lg\"\n animated={animated}\n className={cn(!pill && 'mt-px')}\n />\n <div className={cn('flex min-w-0 flex-1 flex-col', !pill && 'gap-1')}>\n <p className=\"text-sm font-semibold\">{title}</p>\n {description && <p className=\"text-sm opacity-90\">{description}</p>}\n </div>\n {action && <div className=\"shrink-0 self-center\">{action}</div>}\n {onDismiss && (\n <button\n type=\"button\"\n onClick={onDismiss}\n aria-label=\"Fechar aviso\"\n className={cn(\n 'flex size-touch shrink-0 items-center justify-center rounded-full transition-colors hover:bg-card/60 md:size-8',\n pill ? '-my-2' : '-mt-2 -mr-2',\n )}\n >\n <X className=\"size-icon-sm\" aria-hidden />\n </button>\n )}\n </div>\n )\n}\n","import { X } from 'lucide-react'\nimport { Dialog } from 'radix-ui'\nimport type { ReactNode } from 'react'\nimport { cn } from '@/lib/cn'\n\n/*\n * Estrutura interna de Drawer e Modal (não usar direto nas telas):\n * header fixo (ícone, título, descrição, fechar), body como única área rolável\n * e footer fixo com borda superior, respeitando a área segura do aparelho.\n */\n\ninterface OverlayShellProps {\n title: ReactNode\n description?: ReactNode\n icon?: ReactNode\n children: ReactNode\n footer?: ReactNode\n /** Esconde o header visualmente (o título continua para leitores de tela). */\n hideHeader?: boolean\n onRequestClose: () => void\n bodyClassName?: string\n}\n\nexport function OverlayShell({\n title,\n description,\n icon,\n children,\n footer,\n hideHeader,\n onRequestClose,\n bodyClassName,\n}: OverlayShellProps) {\n const closeButton = (\n <button\n type=\"button\"\n onClick={onRequestClose}\n aria-label=\"Fechar\"\n className={cn(\n '-mt-1 -mr-2 flex size-touch shrink-0 cursor-pointer items-center justify-center rounded-item text-muted-foreground transition-colors hover:bg-accent hover:text-foreground md:size-control-md',\n // Sem cabeçalho visível, o botão sai do header oculto e fica invisível (sem clip, para\n // receber clique e foco), aparecendo só com foco de teclado.\n hideHeader &&\n 'pointer-events-auto m-0 cursor-default opacity-0 focus-visible:cursor-pointer focus-visible:opacity-100',\n )}\n >\n <X className=\"size-icon-md\" aria-hidden />\n </button>\n )\n\n return (\n <>\n {hideHeader && (\n <div className=\"pointer-events-none absolute inset-x-0 top-0 z-10 flex justify-end px-2 pt-safe md:px-4 md:pt-4\">\n {closeButton}\n </div>\n )}\n <header\n className={cn(\n 'flex shrink-0 items-start gap-3 border-b px-4 pt-safe pb-4 md:px-6 md:pt-6',\n hideHeader && 'sr-only',\n )}\n >\n {icon && (\n <span\n aria-hidden\n className=\"flex size-control-md shrink-0 items-center justify-center rounded-control bg-primary-soft text-primary-soft-foreground [&_svg]:size-icon-md\"\n >\n {icon}\n </span>\n )}\n <div className=\"flex min-w-0 flex-1 flex-col gap-1 pt-1\">\n <Dialog.Title className=\"text-lg font-semibold wrap-break-word\">{title}</Dialog.Title>\n {description ? (\n <Dialog.Description className=\"text-sm wrap-break-word text-muted-foreground\">\n {description}\n </Dialog.Description>\n ) : (\n <Dialog.Description className=\"sr-only\">{title}</Dialog.Description>\n )}\n </div>\n {!hideHeader && closeButton}\n </header>\n <div\n className={cn(\n 'min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 md:px-6',\n bodyClassName,\n )}\n >\n {children}\n </div>\n {footer && (\n <footer className=\"shrink-0 border-t bg-card px-4 pt-4 pb-safe md:px-6 md:pb-6\">\n {footer}\n </footer>\n )}\n </>\n )\n}\n","import { Dialog } from 'radix-ui'\nimport { useState, type ReactNode } from 'react'\nimport { resolveCatalogCode } from '@/catalog/components'\nimport { BrandFeedbackIcon } from '@/components/ui/brand-feedback-icon'\nimport { ActionBar } from '@/components/ui/action-bar'\nimport { cn } from '@/lib/cn'\nimport { useBreakpoint } from '@/hooks/use-breakpoint'\nimport { useMotionLib, useMotionPresets } from '@/lib/motion'\nimport { OverlayShell } from './overlay-shell'\n\n/*\n * Modal único. Só para confirmações, mensagens e formulários de até 3 campos simples.\n * Mais que isso vai em Drawer (até ~12 campos) ou em página inteira. Nunca modal dentro de modal.\n * type confirm pergunta com ícone de info e ação principal primária\n * type destructive ação irreversível: ícone de erro e ação principal destrutiva\n * type info só informa: um botão de largura total\n * type form até 3 campos no body, ações no rodapé\n */\n\nexport type ModalType = 'confirm' | 'destructive' | 'info' | 'form'\n\nconst sizes = { sm: 'md:max-w-sm', md: 'md:max-w-lg', lg: 'md:max-w-2xl' } as const\n\nexport interface ModalProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n title: string\n description?: ReactNode\n type?: ModalType\n size?: keyof typeof sizes\n /** Conteúdo do body (em form, os campos). */\n children?: ReactNode\n confirmLabel?: string\n /**\n * Rótulo do botão de cancelar. Em `confirm` e `destructive` o padrão é \"Cancelar\". Em `info`\n * não há botão de cancelar: o segundo botão só aparece quando `cancelLabel` é passado.\n */\n cancelLabel?: string\n /** Pode ser assíncrono: o botão mostra carregamento até terminar. */\n onConfirm?: () => void | Promise<void>\n /** id do <form> quando type=\"form\" (o botão principal vira submit dele). */\n formId?: string\n /** Estado de envio controlado de fora (ex.: isSubmitting do React Hook Form). */\n loading?: boolean\n}\n\n// Classes do Tailwind do caminho `off`; em `on` o Motion anima e `tw-animate-css` sai.\nconst overlayCls = 'fixed inset-0 z-50 bg-overlay'\nconst overlayOffCls = cn(\n overlayCls,\n 'data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0',\n)\nconst contentCls = cn(\n // Mobile: tela inteira. Desktop: centralizado.\n 'fixed inset-0 z-50 flex h-dvh flex-col bg-card text-card-foreground outline-none',\n 'md:inset-auto md:top-1/2 md:left-1/2 md:h-auto md:max-h-sheet md:w-full md:-translate-x-1/2 md:-translate-y-1/2 md:rounded-surface md:border md:shadow-lg',\n)\n\nconst feedback = { confirm: 'info', destructive: 'error', info: 'info' } as const\n\nexport function Modal({\n open,\n onOpenChange,\n title,\n description,\n type = 'confirm',\n size = 'sm',\n children,\n confirmLabel = type === 'destructive' ? 'Excluir' : type === 'info' ? 'Entendi' : 'Confirmar',\n cancelLabel,\n onConfirm,\n formId,\n loading,\n}: ModalProps) {\n const [busy, setBusy] = useState(false)\n const close = () => onOpenChange(false)\n const confirm = async () => {\n if (!onConfirm) return close()\n try {\n setBusy(true)\n await onConfirm()\n close()\n } finally {\n setBusy(false)\n }\n }\n const isForm = type === 'form'\n const lib = useMotionLib()\n const presets = useMotionPresets()\n const { isMobile } = useBreakpoint()\n\n // destructive tem o mesmo formato do confirm (só muda a cor): mesmo código, MOD-001.\n // O desvio fica explícito de propósito: sem ele, destructive só cairia em MOD-001\n // pelo fallback de resolveCatalogCode (o primeiro código do Modal no catálogo), ou\n // seja, dependeria da ordem das entradas em src/catalog/components.ts.\n const code = resolveCatalogCode('Modal', {\n type: type === 'destructive' ? 'confirm' : type,\n })\n const sizeCls = sizes[size]\n const shell = (\n <OverlayShell\n title={title}\n description={isForm ? description : undefined}\n hideHeader={!isForm}\n onRequestClose={close}\n bodyClassName={cn(!isForm && 'flex flex-col items-center justify-center gap-4 text-center')}\n footer={\n <ActionBar\n primary={{\n label: confirmLabel,\n destructive: type === 'destructive',\n loading: busy || loading,\n loadingLabel: `${confirmLabel}...`,\n type: isForm && formId ? 'submit' : 'button',\n form: isForm ? formId : undefined,\n onClick: isForm && formId ? undefined : confirm,\n }}\n cancel={\n type === 'info' && cancelLabel === undefined\n ? undefined\n : { label: cancelLabel ?? 'Cancelar', onClick: close }\n }\n />\n }\n >\n {!isForm && (\n <>\n <BrandFeedbackIcon type={feedback[type as keyof typeof feedback]} size=\"2xl\" animated />\n <div className=\"flex flex-col gap-2\">\n <p className=\"text-lg font-semibold wrap-anywhere\">{title}</p>\n {description && (\n <p className=\"text-sm wrap-anywhere text-muted-foreground\">{description}</p>\n )}\n </div>\n {children}\n </>\n )}\n {isForm && <div className=\"flex flex-col gap-2\">{children}</div>}\n </OverlayShell>\n )\n\n // `on`: o conteúdo só existe enquanto aberto ou saindo (AnimatePresence); o Radix fica com\n // forceMount e o `m.div` entra por asChild, preservando data-rendra e o foco do Dialog.\n if (lib) {\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <lib.AnimatePresence>\n {open && (\n <Dialog.Portal forceMount key=\"modal\">\n <Dialog.Overlay forceMount asChild>\n <lib.m.div className={overlayCls} {...presets.fade} />\n </Dialog.Overlay>\n <Dialog.Content\n forceMount\n asChild\n data-rendra={code}\n className={cn(contentCls, sizeCls)}\n >\n {/* Em tela cheia (celular) a escala do centro perde o sentido: entra de baixo, 8 px. */}\n <lib.m.div {...presets.open(isMobile ? { y: 8 } : undefined)}>{shell}</lib.m.div>\n </Dialog.Content>\n </Dialog.Portal>\n )}\n </lib.AnimatePresence>\n </Dialog.Root>\n )\n }\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className={overlayOffCls} />\n <Dialog.Content\n data-rendra={code}\n className={cn(\n contentCls,\n 'data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 md:data-[state=open]:zoom-in-95',\n sizeCls,\n )}\n >\n {shell}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n )\n}\n","import { Info } from 'lucide-react'\nimport { useState, type ReactNode } from 'react'\nimport { Button } from '@/components/ui/button'\nimport { Modal } from '@/components/ui/modal'\nimport { cn } from '@/lib/cn'\n\n/*\n * Texto orientativo (como usar a tela, o que um campo faz, de onde vem um número). Nunca fica\n * solto no corpo da tela nem num botão \"Saiba mais\" avulso: é um ícone de informação discreto,\n * ao lado do título a que se refere, que abre um Modal informativo.\n * Onde aparece: PageHeader help (ao lado do título da tela, no header fixo), CardTitle help e\n * FormSection help (ao lado do título do card). Use direto só quando nenhum desses servir.\n */\n\nexport interface InfoHintProps {\n /** Título do modal (em geral, o título da tela ou da seção). */\n title: string\n /** O texto orientativo. Pode ter parágrafos e listas. */\n children: ReactNode\n className?: string\n}\n\nexport function InfoHint({ title, children, className }: InfoHintProps) {\n const [open, setOpen] = useState(false)\n return (\n // Wrapper sem layout próprio (display: contents): o botão é o único elemento sempre\n // presente (o Modal só monta o próprio conteúdo quando aberto), então o data-rendra\n // do InfoHint vive aqui, não no botão (que já carrega o código do Button).\n <span className=\"contents\" data-rendra=\"INFO-001\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n aria-label={`Sobre: ${title}`}\n onClick={() => setOpen(true)}\n className={cn(\n 'shrink-0 text-muted-foreground hover:text-primary-text max-md:size-touch',\n className,\n )}\n >\n <Info aria-hidden />\n </Button>\n <Modal open={open} onOpenChange={setOpen} type=\"info\" title={title} size=\"md\">\n <div className=\"flex flex-col gap-3 text-sm text-muted-foreground\">{children}</div>\n </Modal>\n </span>\n )\n}\n","import type { HTMLAttributes, ReactNode } from 'react'\nimport { InfoHint } from '@/components/ui/info-hint'\nimport { cn } from '@/lib/cn'\n\n/**\n * Card: agrupa conteúdo de página. Borda de 1px, sem sombra pesada.\n * Nunca aninhe Card dentro de Card: para hierarquia interna use Separator ou título de seção.\n * Nunca coloque rolagem dentro de Card.\n */\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Uso interno: quando outro componente catalogado (Calendar, FormSection, StatCard,\n * Table) usa o Card como o próprio elemento raiz, ele passa o seu código aqui para que\n * o data-rendra mostre a variante certa, não CARD-001. Sem essa prop, o Card se\n * identifica como CARD-001, o próprio código dele no catálogo.\n */\n 'data-rendra'?: string\n}\n\nexport function Card({ className, 'data-rendra': dataRendra, ...props }: CardProps) {\n return (\n <div\n data-slot=\"card\"\n data-rendra={dataRendra ?? 'CARD-001'}\n className={cn(\n 'flex min-w-0 flex-col rounded-surface border bg-card text-card-foreground',\n className,\n )}\n {...props}\n />\n )\n}\n\nexport interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Ações do card, no canto do cabeçalho (ex.: Ligar, Restaurar padrão). É o lugar das ações\n * de um card: nunca um botão solto no meio do conteúdo.\n */\n actions?: ReactNode\n}\n\nexport function CardHeader({ className, actions, children, ...props }: CardHeaderProps) {\n if (!actions)\n return (\n <div\n data-slot=\"card-header\"\n className={cn('flex flex-col gap-1 p-4 md:p-6', className)}\n {...props}\n >\n {children}\n </div>\n )\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n 'flex flex-wrap items-start justify-between gap-x-4 gap-y-3 p-4 md:p-6',\n className,\n )}\n {...props}\n >\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">{children}</div>\n <div className=\"flex shrink-0 items-center gap-2\">{actions}</div>\n </div>\n )\n}\n\nexport interface CardTitleProps extends HTMLAttributes<HTMLHeadingElement> {\n /** Texto orientativo da seção: ícone de informação ao lado do título, que abre um modal. */\n help?: ReactNode\n}\n\nexport function CardTitle({ className, children, help, ...props }: CardTitleProps) {\n const heading = (\n <h3 data-slot=\"card-title\" className={cn('text-lg font-semibold', className)} {...props}>\n {children}\n </h3>\n )\n if (!help) return heading\n return (\n <div className=\"flex min-w-0 items-center gap-1\">\n {heading}\n <InfoHint title={typeof children === 'string' ? children : 'Sobre esta seção'}>\n {help}\n </InfoHint>\n </div>\n )\n}\n\nexport function CardDescription({ className, ...props }: HTMLAttributes<HTMLParagraphElement>) {\n return (\n <p\n data-slot=\"card-description\"\n className={cn('text-sm text-muted-foreground', className)}\n {...props}\n />\n )\n}\n\nexport function CardContent({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn('p-4 md:p-6 [[data-slot=card-header]+&]:pt-0', className)}\n {...props}\n />\n )\n}\n\nexport function CardFooter({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn('flex items-center gap-3 border-t px-4 py-3 md:px-6', className)}\n {...props}\n />\n )\n}\n","/*\n * Buscas que preenchem o formulário, direto do navegador (APIs públicas e gratuitas, com\n * CORS liberado, sem backend):\n * CEP ViaCEP https://viacep.com.br\n * CNPJ BrasilAPI https://brasilapi.com.br\n * Regra de tela: o campo que faz a busca vem primeiro (25% da linha) e os campos que ele\n * preenche ficam abaixo, para a pessoa saber da busca antes de digitar o resto.\n */\n\nconst digits = (v: string) => v.replace(/\\D/g, '')\n\nexport interface Address {\n cep: string\n logradouro: string\n complemento: string\n bairro: string\n cidade: string\n uf: string\n}\n\n/** Endereço do CEP (8 dígitos). null se não existir; lança erro se a busca falhar. */\nexport async function lookupCep(cep: string, signal?: AbortSignal): Promise<Address | null> {\n const d = digits(cep)\n if (d.length !== 8) return null\n const res = await fetch(`https://viacep.com.br/ws/${d}/json/`, { signal })\n if (!res.ok) throw new Error('Não foi possível buscar o CEP agora.')\n const data = (await res.json()) as Record<string, string | boolean>\n if (data.erro) return null\n return {\n cep: String(data.cep ?? ''),\n logradouro: String(data.logradouro ?? ''),\n complemento: String(data.complemento ?? ''),\n bairro: String(data.bairro ?? ''),\n cidade: String(data.localidade ?? ''),\n uf: String(data.uf ?? ''),\n }\n}\n\nexport interface Company {\n razaoSocial: string\n nomeFantasia: string\n email: string\n telefone: string\n situacao: string\n endereco: Address & { numero: string }\n}\n\n/** Dados públicos do CNPJ (14 dígitos). null se não existir; lança erro se a busca falhar. */\nexport async function lookupCnpj(cnpj: string, signal?: AbortSignal): Promise<Company | null> {\n const d = digits(cnpj)\n if (d.length !== 14) return null\n const res = await fetch(`https://brasilapi.com.br/api/cnpj/v1/${d}`, { signal })\n if (res.status === 404) return null\n if (!res.ok) throw new Error('Não foi possível buscar o CNPJ agora.')\n const data = (await res.json()) as Record<string, string | number | null>\n const s = (k: string) => (data[k] == null ? '' : String(data[k]))\n const fone = digits(s('ddd_telefone_1'))\n return {\n razaoSocial: s('razao_social'),\n nomeFantasia: s('nome_fantasia'),\n email: s('email').toLowerCase(),\n telefone:\n fone.length >= 10 ? `(${fone.slice(0, 2)}) ${fone.slice(2, -4)}-${fone.slice(-4)}` : '',\n situacao: s('descricao_situacao_cadastral'),\n endereco: {\n cep: s('cep'),\n logradouro: [s('descricao_tipo_de_logradouro'), s('logradouro')].filter(Boolean).join(' '),\n numero: s('numero'),\n complemento: s('complemento'),\n bairro: s('bairro'),\n cidade: s('municipio'),\n uf: s('uf'),\n },\n }\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { lookupCep, lookupCnpj, type Address, type Company } from '@/lib/lookup'\n\n/** Resultado da busca embutida no Input (CEP e CNPJ). */\nexport type LookupResult =\n | { status: 'loading'; kind: 'cep' | 'cnpj' }\n | { status: 'found'; kind: 'cep'; data: Address; message: string }\n | { status: 'found'; kind: 'cnpj'; data: Company; message: string }\n | { status: 'not-found'; kind: 'cep' | 'cnpj'; message: string }\n | { status: 'error'; kind: 'cep' | 'cnpj'; message: string }\n\n/**\n * Busca CEP (8 dígitos) ou CNPJ (14 dígitos) assim que o valor fica completo. Cancela a\n * busca anterior quando o valor muda. `kind` 'auto' decide pelo tamanho (CPF ou CNPJ: só\n * o CNPJ busca). Sem `onResult`, não faz nada.\n */\nexport function useLookup(\n kind: 'cep' | 'cnpj' | 'auto' | undefined,\n value: string,\n onResult: ((r: LookupResult) => void) | undefined,\n) {\n const [loading, setLoading] = useState(false)\n const cb = useRef(onResult)\n cb.current = onResult\n const digits = value.replace(/\\D/g, '')\n const target =\n kind === 'cep' && digits.length === 8\n ? 'cep'\n : (kind === 'cnpj' || kind === 'auto') && digits.length === 14\n ? 'cnpj'\n : null\n const enabled = Boolean(onResult) && target !== null\n\n useEffect(() => {\n if (!enabled || !target) return\n const ctrl = new AbortController()\n const send = (r: LookupResult) => {\n if (!ctrl.signal.aborted) cb.current?.(r)\n }\n setLoading(true)\n send({ status: 'loading', kind: target })\n const run =\n target === 'cep'\n ? lookupCep(digits, ctrl.signal).then((data) =>\n data\n ? send({\n status: 'found',\n kind: 'cep',\n data,\n message: 'Endereço preenchido pelo CEP.',\n })\n : send({\n status: 'not-found',\n kind: 'cep',\n message: 'CEP não encontrado. Preencha o endereço.',\n }),\n )\n : lookupCnpj(digits, ctrl.signal).then((data) =>\n data\n ? send({\n status: 'found',\n kind: 'cnpj',\n data,\n message: `${data.situacao ? `Situação: ${data.situacao}. ` : ''}Dados preenchidos pelo CNPJ.`,\n })\n : send({\n status: 'not-found',\n kind: 'cnpj',\n message: 'CNPJ não encontrado. Preencha os dados abaixo.',\n }),\n )\n run\n .catch((e: unknown) =>\n send({\n status: 'error',\n kind: target,\n message: e instanceof Error ? e.message : 'Não foi possível buscar agora.',\n }),\n )\n .finally(() => {\n if (!ctrl.signal.aborted) setLoading(false)\n })\n return () => {\n ctrl.abort()\n setLoading(false)\n }\n }, [enabled, target, digits])\n\n return loading\n}\n","import { cva, type VariantProps } from 'class-variance-authority'\n\n/**\n * Moldura única dos campos (Input, Select, DatePicker, Textarea). Mesma altura dos botões\n * em cada tamanho; fonte de 16px no mobile para o iOS não dar zoom ao focar.\n */\n/** Marque o elemento com data-slot=\"control\": o teste de toque mede a moldura, não o input. */\nexport const controlFrame = cva(\n 'group/control flex w-full min-w-0 items-center gap-2 rounded-control border border-input bg-field text-base text-foreground transition-[border-color,box-shadow] duration-150 focus-within:border-ring focus-within:bg-card focus-within:ring-2 focus-within:ring-ring/25 hover:border-foreground/40 has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-60 has-[:disabled]:hover:border-input md:text-sm',\n {\n variants: {\n size: {\n sm: 'h-control-sm px-3',\n md: 'h-control-md px-3',\n lg: 'h-control-lg px-4',\n },\n invalid: {\n true: 'border-destructive focus-within:border-destructive focus-within:ring-destructive/25 hover:border-destructive',\n false: '',\n },\n },\n defaultVariants: { size: 'md', invalid: false },\n },\n)\n\nexport type ControlSize = NonNullable<VariantProps<typeof controlFrame>['size']>\n\n/** Classe do <input> nativo dentro da moldura. */\nexport const controlInput =\n 'h-full min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed'\n\n/** Botão pequeno dentro da moldura (limpar, mostrar senha). */\nexport const controlAdornmentButton =\n '-mr-2 flex size-control-sm shrink-0 cursor-pointer items-center justify-center rounded-item text-muted-foreground transition-colors outline-none hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring md:-mr-1 md:size-8 [&_svg]:size-icon-sm'\n\n/**\n * Reserva, dentro de um gatilho, o espaço do botão sobreposto (limpar do Select e do\n * DatePicker), para o texto não passar por baixo dele.\n */\nexport const controlAdornmentSpace = 'size-control-sm shrink-0 md:size-8'\n","import type { FactoryArg } from 'imask'\n\n/** Máscaras disponíveis na prop mask do Input. Cada uma já define o teclado certo no mobile. */\nexport type MaskName =\n 'cpf' | 'cnpj' | 'cpfCnpj' | 'phone' | 'cep' | 'date' | 'time' | 'currency' | 'percent'\n\ntype InputMode = 'numeric' | 'tel' | 'decimal'\n\nconst numberBlock = (scale: number, max?: number) => ({\n mask: Number,\n scale,\n thousandsSeparator: '.',\n radix: ',',\n mapToRadix: ['.'],\n padFractionalZeros: true,\n normalizeZeros: true,\n min: 0,\n ...(max !== undefined ? { max } : {}),\n})\n\nexport const masks: Record<\n MaskName,\n { options: FactoryArg; inputMode: InputMode; placeholder: string }\n> = {\n cpf: { options: { mask: '000.000.000-00' }, inputMode: 'numeric', placeholder: '000.000.000-00' },\n cnpj: {\n options: { mask: '00.000.000/0000-00' },\n inputMode: 'numeric',\n placeholder: '00.000.000/0000-00',\n },\n // CPF até 11 dígitos, CNPJ a partir do 12º: a máscara troca sozinha.\n cpfCnpj: {\n options: { mask: [{ mask: '000.000.000-00' }, { mask: '00.000.000/0000-00' }] },\n inputMode: 'numeric',\n placeholder: 'CPF ou CNPJ',\n },\n phone: {\n options: { mask: [{ mask: '(00) 0000-0000' }, { mask: '(00) 00000-0000' }] },\n inputMode: 'tel',\n placeholder: '(00) 00000-0000',\n },\n cep: { options: { mask: '00000-000' }, inputMode: 'numeric', placeholder: '00000-000' },\n date: { options: { mask: '00/00/0000' }, inputMode: 'numeric', placeholder: 'DD/MM/AAAA' },\n time: { options: { mask: '00:00' }, inputMode: 'numeric', placeholder: '00:00' },\n currency: {\n options: { mask: 'R$ num', lazy: false, blocks: { num: numberBlock(2) } } as FactoryArg,\n inputMode: 'decimal',\n placeholder: 'R$ 0,00',\n },\n percent: {\n options: { mask: 'num %', lazy: false, blocks: { num: numberBlock(2, 100) } } as FactoryArg,\n inputMode: 'decimal',\n placeholder: '0,00 %',\n },\n}\n\n/** Máscara de percentual com teto configurável (padrão 100), para o Input com unidades (A9). */\nexport function percentMask(max = 100) {\n return {\n options: { mask: 'num %', lazy: false, blocks: { num: numberBlock(2, max) } } as FactoryArg,\n inputMode: 'decimal' as InputMode,\n placeholder: '0,00 %',\n }\n}\n\n/** País para o seletor de DDI do telefone. */\nexport interface PhoneCountry {\n /** DDI sem o \"+\", ex.: \"55\". */\n ddi: string\n /** Nome em português, mostrado na lista. */\n name: string\n}\n\n/** DDI padrão do campo de telefone. */\nexport const DEFAULT_DDI = '55'\n\n/** Lista padrão do seletor de DDI (Brasil primeiro). Troque com a prop ddiOptions do Input. */\nexport const phoneCountries: PhoneCountry[] = [\n { ddi: '55', name: 'Brasil' },\n { ddi: '54', name: 'Argentina' },\n { ddi: '56', name: 'Chile' },\n { ddi: '57', name: 'Colômbia' },\n { ddi: '595', name: 'Paraguai' },\n { ddi: '598', name: 'Uruguai' },\n { ddi: '52', name: 'México' },\n { ddi: '1', name: 'Estados Unidos e Canadá' },\n { ddi: '351', name: 'Portugal' },\n { ddi: '34', name: 'Espanha' },\n { ddi: '33', name: 'França' },\n { ddi: '39', name: 'Itália' },\n { ddi: '49', name: 'Alemanha' },\n { ddi: '44', name: 'Reino Unido' },\n]\n\n/** Máscara do número fora do Brasil: só dígitos, em grupos, até 15 (limite do padrão E.164). */\nexport const internationalPhoneMask = {\n options: { mask: '000 000 000 000 000' } as FactoryArg,\n inputMode: 'tel' as InputMode,\n placeholder: 'Número com DDD',\n}\n\n/** Número completo no padrão internacional: toE164(\"55\", \"(11) 91234-5678\") = \"+5511912345678\". */\nexport function toE164(ddi: string, national: string) {\n const digits = national.replace(/\\D/g, '')\n return digits ? `+${ddi}${digits}` : ''\n}\n\n/** Converte \"R$ 1.250,00\" ou \"12,5 %\" em número. */\nexport function parseLocaleNumber(masked: string): number | null {\n const clean = masked.replace(/[^\\d,-]/g, '').replace(',', '.')\n if (!clean) return null\n const n = Number(clean)\n return Number.isFinite(n) ? n : null\n}\n\n/**\n * Moeda em centavos inteiros, sem erro de arredondamento de ponto flutuante:\n * \"R$ 1.250,50\" -> 125050. Vazio -> null. Use centavos para guardar e somar dinheiro.\n */\nexport function toCents(masked: string): number | null {\n const d = masked.replace(/\\D/g, '')\n if (!d) return null\n const hasDecimals = /,\\d{1,2}\\s*$/.test(masked.replace(/\\s*%$/, ''))\n if (!hasDecimals) return Number(d) * 100\n const [int = '', dec = ''] = masked.replace(/[^\\d,]/g, '').split(',')\n return Number(int || '0') * 100 + Number(dec.padEnd(2, '0').slice(0, 2))\n}\n\n/** Centavos para o texto do campo de moeda: 125050 -> \"R$ 1.250,50\". */\nexport function formatCents(cents: number) {\n return formatCurrency(cents / 100)\n}\n\n/** Formata número como moeda brasileira: 1250 -> \"R$ 1.250,00\". */\nexport function formatCurrency(value: number) {\n return value.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' })\n}\n","import IMask, { type FactoryArg, type InputMask } from 'imask'\nimport { ChevronDown, Eye, EyeOff, X } from 'lucide-react'\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type ChangeEvent,\n type InputHTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { Button } from '@/components/ui/button'\nimport { Spinner } from '@/components/ui/spinner'\nimport { useLookup, type LookupResult } from '@/hooks/use-lookup'\nimport { cn } from '@/lib/cn'\nimport { controlAdornmentButton, controlFrame, controlInput, type ControlSize } from '@/lib/control'\nimport {\n DEFAULT_DDI,\n internationalPhoneMask,\n masks,\n percentMask,\n phoneCountries,\n toCents,\n type MaskName,\n type PhoneCountry,\n} from '@/lib/masks'\n\n/** Uma unidade do seletor embutido do Input (A9). */\nexport interface InputUnitOption {\n /** \"percent\" e \"currency\" ligam a máscara de percentual e de moeda automaticamente. */\n id: string\n label: string\n}\n\nexport interface InputProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'onChange'\n> {\n size?: ControlSize\n /** Máscara brasileira. Define também o teclado do celular (inputMode). */\n mask?: MaskName\n /** Ícone à esquerda. */\n icon?: ReactNode\n /** Conteúdo fixo à direita (ex.: \"kg\", \"dias\"). Ignorado quando `units` está presente. */\n suffix?: ReactNode\n /** Mostra botão para limpar quando há valor. */\n clearable?: boolean\n /** Estado de erro (normalmente vem do Field). */\n invalid?: boolean\n value?: string\n /** Recebe o valor como aparece no campo (com máscara). */\n onChange?: (value: string) => void\n /** Recebe o valor sem máscara (só dígitos, ou número para moeda e percentual). */\n onValueChange?: (unmasked: string, masked: string) => void\n /**\n * Telefone (mask=\"phone\"): DDI escolhido no seletor embutido à esquerda, sem o \"+\".\n * Padrão \"55\". Com +55 a máscara é a brasileira; com outro DDI, só dígitos.\n * O valor do campo continua sendo o número nacional; o completo sai de toE164(ddi, valor).\n */\n ddi?: string\n onDdiChange?: (ddi: string) => void\n /** Países do seletor de DDI. Padrão: phoneCountries (Brasil primeiro). */\n ddiOptions?: PhoneCountry[]\n /** Esconde o seletor de DDI do telefone (só números brasileiros). */\n hideDdi?: boolean\n /**\n * Moeda (mask=\"currency\"): recebe o valor em centavos inteiros (R$ 1.250,50 -> 125050),\n * ou null quando vazio. Guarde e some dinheiro sempre em centavos.\n */\n onCentsChange?: (cents: number | null) => void\n /**\n * CEP, CNPJ e CPF ou CNPJ (mask=\"cep\", \"cnpj\" ou \"cpfCnpj\"): busca os dados assim que o\n * campo fica completo (ViaCEP e BrasilAPI), mostra o carregamento no campo e entrega o\n * resultado. A tela decide o que preencher; use `result.message` como ajuda do Field.\n */\n onLookup?: (result: LookupResult) => void\n /**\n * Unidades (A9): seletor embutido à direita, no mesmo padrão do seletor de DDI. O id\n * \"percent\" liga a máscara de percentual (teto configurável por `percentMax`); \"currency\"\n * liga a máscara de moeda (R$ 1.250,00). Qualquer outro id não aplica máscara, só rótulo.\n * Trocar de unidade sempre limpa o valor do campo.\n */\n units?: InputUnitOption[]\n /** Unidade escolhida (controlada). Sem ela, usa a primeira de `units`. */\n unit?: string\n onUnitChange?: (unit: string) => void\n /** Teto do percentual quando a unidade escolhida é \"percent\". Padrão 100. */\n percentMax?: number\n /**\n * Variante de valor guardado (A10): mostra `maskedHint` no lugar do valor real, que nunca\n * chega a existir no DOM. \"Trocar\" abre um campo vazio (`isEditing`); cancelar volta à\n * máscara. O componente é controlado pela tela: `isEditing`, `onStartEdit`, `onCancelEdit`.\n */\n variant?: 'secret'\n /** Há um valor salvo (mesmo sem mostrá-lo). */\n hasValue?: boolean\n /** Texto mascarado mostrado no lugar do valor, ex.: \"••••••a1b2c3\". */\n maskedHint?: string\n /** Campo aberto para digitar um valor novo. */\n isEditing?: boolean\n onStartEdit?: () => void\n onCancelEdit?: () => void\n /** Remove o valor salvo. Sem essa prop, o botão \"Remover\" não aparece. */\n onRemove?: () => void\n /** Remoção em andamento: desabilita e mostra o carregamento no botão \"Remover\". */\n removing?: boolean\n className?: string\n /**\n * Classe extra no próprio elemento `<input>` (className vai no quadro em volta). Uso raro:\n * hoje só o texto riscado de um item marcado no Checklist.\n */\n inputClassName?: string\n}\n\n/**\n * Input único. Tipos, máscaras, ícone, limpar, senha, unidades e valor guardado são props:\n * nunca crie InputCPF, InputTelefone, InputSenha ou InputSegredo.\n */\nexport const Input = forwardRef<HTMLInputElement, InputProps>(function Input(\n {\n size,\n mask,\n icon,\n suffix,\n clearable,\n invalid,\n type = 'text',\n value,\n defaultValue,\n onChange,\n onValueChange,\n disabled,\n className,\n inputClassName,\n inputMode,\n placeholder,\n ddi: ddiProp,\n onDdiChange,\n ddiOptions = phoneCountries,\n hideDdi,\n onCentsChange,\n onLookup,\n units,\n unit: unitProp,\n onUnitChange,\n percentMax,\n variant,\n hasValue,\n maskedHint,\n isEditing,\n onStartEdit,\n onCancelEdit,\n onRemove,\n removing,\n ...props\n },\n ref,\n) {\n const inputRef = useRef<HTMLInputElement>(null)\n useImperativeHandle(ref, () => inputRef.current as HTMLInputElement)\n const maskRef = useRef<InputMask<FactoryArg> | null>(null)\n const [showPassword, setShowPassword] = useState(false)\n const [inner, setInner] = useState(String(value ?? defaultValue ?? ''))\n const current = value ?? inner\n // variant=\"secret\" em edição: o campo nunca deriva de `value` do consumidor (o valor salvo\n // não pode aparecer nem acionar o \"Limpar campo\"); o rascunho é próprio e abre vazio.\n const [secretDraft, setSecretDraft] = useState('')\n const [lastIsEditing, setLastIsEditing] = useState(isEditing)\n if (isEditing !== lastIsEditing) {\n setLastIsEditing(isEditing)\n if (isEditing) setSecretDraft('')\n }\n const cb = useRef({ onChange, onValueChange, onCentsChange })\n cb.current = { onChange, onValueChange, onCentsChange }\n const lookupKind =\n mask === 'cep' ? 'cep' : mask === 'cnpj' ? 'cnpj' : mask === 'cpfCnpj' ? 'auto' : undefined\n const searching = useLookup(lookupKind, current, onLookup)\n\n // Telefone: seletor de DDI embutido. Controlado pela prop ddi ou interno.\n const isPhone = mask === 'phone'\n const [innerDdi, setInnerDdi] = useState(ddiProp ?? DEFAULT_DDI)\n const ddi = ddiProp ?? innerDdi\n const showDdi = isPhone && !hideDdi\n const intl = isPhone && ddi !== DEFAULT_DDI\n\n // Unidades (A9): seletor embutido à direita. A unidade escolhida decide a máscara.\n const hasUnits = Boolean(units && units.length > 0)\n const [innerUnit, setInnerUnit] = useState(unitProp ?? units?.[0]?.id ?? '')\n const unit = hasUnits ? (unitProp ?? innerUnit) : undefined\n const unitMaskName = unit === 'percent' ? 'percent' : unit === 'currency' ? 'currency' : undefined\n\n const def = intl\n ? internationalPhoneMask\n : hasUnits\n ? unitMaskName === 'percent'\n ? percentMask(percentMax)\n : unitMaskName === 'currency'\n ? masks.currency\n : undefined\n : mask\n ? masks[mask]\n : undefined\n const maskKey = !def\n ? undefined\n : intl\n ? 'phone-intl'\n : hasUnits\n ? `unit-${unitMaskName}-${percentMax ?? ''}`\n : mask\n\n // Máscara: criada uma vez por tipo de máscara, sincronizada com o valor controlado.\n useEffect(() => {\n if (!maskKey || !def || !inputRef.current) return\n const m = IMask(inputRef.current, def.options)\n maskRef.current = m\n m.on('accept', () => {\n setInner(m.value)\n cb.current.onChange?.(m.value)\n cb.current.onValueChange?.(m.unmaskedValue, m.value)\n if (mask === 'currency' || unitMaskName === 'currency')\n cb.current.onCentsChange?.(toCents(m.value))\n })\n return () => {\n m.destroy()\n maskRef.current = null\n }\n // A máscara só muda com o tipo (maskKey); def acompanha o maskKey.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [maskKey])\n\n useEffect(() => {\n const m = maskRef.current\n if (m && value !== undefined && value !== m.value) m.value = value\n }, [value])\n\n const isPassword = type === 'password'\n const country = ddiOptions.find((c) => c.ddi === ddi)\n const isSecret = variant === 'secret'\n // id e aria-* que o Field injeta no controle (não removidos de props: o <input> normal\n // continua recebendo pelo {...props}). No modo leitura do secret não há <input>; sem\n // repassar para o botão Trocar, o Label do Field fica apontando para um id inexistente.\n const {\n id: fieldId,\n 'aria-describedby': fieldDescribedBy,\n 'aria-required': fieldRequired,\n } = props\n\n // Esvazia o valor (máscara, estado interno e os callbacks): usado por \"Limpar campo\" e\n // por trocar de unidade, que nunca deve carregar o número de uma unidade para outra.\n const resetValue = () => {\n if (maskRef.current) maskRef.current.value = ''\n setInner('')\n setSecretDraft('')\n onChange?.('')\n onValueChange?.('', '')\n onCentsChange?.(null)\n }\n\n const clear = () => {\n resetValue()\n inputRef.current?.focus()\n }\n\n // Trocar de unidade sempre limpa o valor (a máscara muda junto).\n const changeUnit = (id: string) => {\n setInnerUnit(id)\n onUnitChange?.(id)\n resetValue()\n }\n\n // ---------------------------------------------------------------- variant=\"secret\" (A10)\n if (isSecret && !isEditing) {\n return (\n <div\n data-slot=\"control\"\n data-rendra=\"CAMP-001\"\n className={cn(controlFrame({ size, invalid }), className)}\n >\n <span className=\"min-w-0 flex-1 truncate font-mono text-sm text-muted-foreground\">\n {hasValue ? (maskedHint ?? '••••••••') : 'Nenhum valor salvo'}\n </span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onStartEdit}\n disabled={disabled}\n id={fieldId}\n aria-describedby={fieldDescribedBy}\n aria-required={fieldRequired}\n >\n Trocar\n </Button>\n {hasValue && onRemove && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onRemove}\n disabled={disabled || removing}\n loading={removing}\n >\n Remover\n </Button>\n )}\n </div>\n )\n }\n\n return (\n <div\n data-slot=\"control\"\n data-rendra=\"CAMP-001\"\n className={cn(controlFrame({ size, invalid }), className)}\n >\n {showDdi && (\n // Seletor nativo transparente sobre o \"+55\": no celular abre a lista do sistema.\n <span className=\"relative -ml-1 flex h-full min-w-touch shrink-0 items-center gap-1 border-r pr-2 text-sm font-medium\">\n <span aria-hidden>+{ddi}</span>\n <ChevronDown className=\"size-icon-sm text-muted-foreground\" aria-hidden />\n <select\n aria-label={`Código do país (DDI): ${country?.name ?? ''} +${ddi}`}\n value={ddi}\n disabled={disabled}\n onChange={(e) => {\n setInnerDdi(e.target.value)\n onDdiChange?.(e.target.value)\n }}\n className=\"absolute inset-0 cursor-pointer bg-popover text-popover-foreground opacity-0 disabled:cursor-not-allowed\"\n >\n {ddiOptions.map((c) => (\n <option key={c.ddi} value={c.ddi} className=\"bg-popover text-popover-foreground\">\n {c.name} (+{c.ddi})\n </option>\n ))}\n </select>\n </span>\n )}\n {icon && (\n <span className=\"flex shrink-0 text-muted-foreground [&_svg]:size-icon-sm\" aria-hidden>\n {icon}\n </span>\n )}\n <input\n key={hasUnits ? `unit-${unit}` : undefined}\n ref={inputRef}\n type={\n isSecret\n ? showPassword\n ? 'text'\n : 'password'\n : isPassword && showPassword\n ? 'text'\n : type\n }\n inputMode={inputMode ?? def?.inputMode}\n placeholder={placeholder ?? def?.placeholder}\n disabled={disabled}\n aria-invalid={invalid || undefined}\n aria-busy={searching || undefined}\n className={cn(controlInput, inputClassName)}\n {...(isSecret\n ? {\n // \"Trocar\" sempre abre vazio: o valor salvo nunca chega a existir no DOM.\n value: secretDraft,\n onChange: (e: ChangeEvent<HTMLInputElement>) => {\n setSecretDraft(e.target.value)\n onChange?.(e.target.value)\n onValueChange?.(e.target.value, e.target.value)\n },\n }\n : maskKey\n ? { defaultValue: current }\n : {\n value: current,\n onChange: (e: ChangeEvent<HTMLInputElement>) => {\n setInner(e.target.value)\n onChange?.(e.target.value)\n onValueChange?.(e.target.value, e.target.value)\n },\n })}\n {...props}\n />\n {searching && (\n <Spinner size=\"sm\" label=\"Buscando…\" className=\"shrink-0 text-muted-foreground\" />\n )}\n {hasUnits && (\n // Mesmo padrão do seletor de DDI, à direita: rótulo visível e select nativo por cima.\n <span className=\"relative -mr-1 flex h-full min-w-touch shrink-0 items-center gap-1 border-l pl-2 text-sm font-medium\">\n <span aria-hidden>{units?.find((u) => u.id === unit)?.label ?? unit}</span>\n <ChevronDown className=\"size-icon-sm text-muted-foreground\" aria-hidden />\n <select\n aria-label={`Unidade: ${units?.find((u) => u.id === unit)?.label ?? unit}`}\n value={unit}\n disabled={disabled}\n onChange={(e) => changeUnit(e.target.value)}\n className=\"absolute inset-0 cursor-pointer bg-popover text-popover-foreground opacity-0 disabled:cursor-not-allowed\"\n >\n {units?.map((u) => (\n <option key={u.id} value={u.id} className=\"bg-popover text-popover-foreground\">\n {u.label}\n </option>\n ))}\n </select>\n </span>\n )}\n {!hasUnits && suffix && (\n <span className=\"shrink-0 text-sm text-muted-foreground\">{suffix}</span>\n )}\n {clearable && (isSecret ? secretDraft : current) && !disabled && (\n <button\n type=\"button\"\n onClick={clear}\n aria-label=\"Limpar campo\"\n className={controlAdornmentButton}\n >\n <X aria-hidden />\n </button>\n )}\n {(isPassword || isSecret) && (\n <button\n type=\"button\"\n onClick={() => setShowPassword((s) => !s)}\n aria-label={showPassword ? 'Ocultar senha' : 'Mostrar senha'}\n aria-pressed={showPassword}\n className={controlAdornmentButton}\n >\n {showPassword ? <EyeOff aria-hidden /> : <Eye aria-hidden />}\n </button>\n )}\n {isSecret && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onCancelEdit} disabled={disabled}>\n Cancelar\n </Button>\n )}\n </div>\n )\n})\n","import { X } from 'lucide-react'\nimport { Dialog, Popover } from 'radix-ui'\nimport { useRef, type ReactNode } from 'react'\nimport { useBreakpoint } from '@/hooks/use-breakpoint'\nimport { cn } from '@/lib/cn'\nimport { useLayoutReady, useMotionLib, useMotionOn, useMotionPresets } from '@/lib/motion'\n\n/*\n * Painel de escolha usado por Select e DatePicker (não é para uso direto nas telas).\n * Desktop: popover ancorado no campo, na largura dele.\n * Mobile (< 768px): o mesmo conteúdo reconstruído como bottom sheet, com título,\n * área rolável e rodapé fixo que respeita a área segura do aparelho.\n */\n\ninterface PickerPanelProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n /** O gatilho (renderizado com asChild). */\n trigger: ReactNode\n /** Título do bottom sheet no mobile (normalmente o rótulo do campo). */\n title: string\n /** Topo fixo (ex.: campo de busca). */\n header?: ReactNode\n children: ReactNode\n /** Rodapé fixo (ex.: Limpar / Aplicar). */\n footer?: ReactNode\n /** Largura no desktop: do gatilho ou automática (calendário). */\n width?: 'trigger' | 'auto'\n /**\n * Botão sobreposto ao gatilho (ex.: limpar). Fica como irmão do gatilho, nunca dentro\n * dele: botão dentro de botão é HTML inválido e confunde leitores de tela.\n */\n adornment?: ReactNode\n align?: 'start' | 'center' | 'end'\n}\n\n/** A folha fecha se o arraste passou de 40% da altura ou se foi um arremesso (> 0,11 px/ms). */\nconst DISMISS_FRACTION = 0.4\nconst DISMISS_VELOCITY = 110\n\ninterface MobileSheetProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n trigger: ReactNode\n adornment?: ReactNode\n /** Alça e título: a única área que começa o arraste (o resto rola). */\n head: ReactNode\n /** Busca, lista e rodapé. */\n rest: ReactNode\n}\n\n/**\n * A folha do celular em `on`: entra de baixo, acompanha o dedo (arraste vertical pela alça, com\n * fricção ao puxar para cima), fecha por distância ou por arremesso e, se o dedo solta antes\n * disso, volta à origem com a mola da folha (a velocidade do dedo entra na mola, sem costura). O\n * fundo escurecido acompanha a distância. Só a alça arrasta: o corpo rola sem disputar o gesto.\n * Nenhum valor passa por `style`: o Motion guarda a posição do arraste, e o escurecimento do\n * fundo é gravado direto no elemento (sem render por quadro).\n */\nfunction MobileSheet({ open, onOpenChange, trigger, adornment, head, rest }: MobileSheetProps) {\n const { AnimatePresence, animate, m, useDragControls } = useMotionOn()\n const presets = useMotionPresets()\n const ready = useLayoutReady()\n const controls = useDragControls()\n const sheetRef = useRef<HTMLDivElement>(null)\n const dimRef = useRef<HTMLDivElement>(null)\n const height = useRef(1)\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Anchor adornment={adornment}>\n <Dialog.Trigger asChild>{trigger}</Dialog.Trigger>\n </Anchor>\n <AnimatePresence>\n {open && (\n <Dialog.Portal forceMount key=\"sheet\">\n <Dialog.Overlay forceMount asChild>\n <m.div className=\"fixed inset-0 z-40\" {...presets.fade}>\n <div ref={dimRef} className=\"absolute inset-0 bg-overlay\" />\n </m.div>\n </Dialog.Overlay>\n <Dialog.Content\n forceMount\n asChild\n aria-describedby={undefined}\n className=\"fixed inset-x-0 bottom-0 z-50 flex max-h-sheet flex-col rounded-t-surface border-t bg-popover text-popover-foreground shadow-lg outline-none\"\n >\n <m.div\n ref={sheetRef}\n {...presets.sheet('bottom')}\n drag={ready ? 'y' : false}\n dragControls={controls}\n dragListener={false}\n dragConstraints={{ top: 0 }}\n dragElastic={{ top: 0.2, bottom: 0 }}\n dragSnapToOrigin\n dragTransition={presets.sheetBounce}\n onDragStart={() => {\n height.current = sheetRef.current?.offsetHeight || 1\n }}\n onDrag={(_, info) => {\n const dim = dimRef.current\n if (dim)\n dim.style.opacity = String(\n 1 - Math.min(1, Math.max(0, info.offset.y / height.current)),\n )\n }}\n onDragEnd={(_, info) => {\n if (\n info.offset.y > height.current * DISMISS_FRACTION ||\n info.velocity.y > DISMISS_VELOCITY\n ) {\n onOpenChange(false)\n return\n }\n // Soltou antes: o fundo volta a escurecer por inteiro junto com a folha.\n if (dimRef.current) animate(dimRef.current, { opacity: 1 }, presets.springSheet)\n }}\n >\n <div\n data-sheet-handle\n onPointerDown={(e) => controls.start(e)}\n className=\"touch-none\"\n >\n {head}\n </div>\n {rest}\n </m.div>\n </Dialog.Content>\n </Dialog.Portal>\n )}\n </AnimatePresence>\n </Dialog.Root>\n )\n}\n\nfunction Anchor({ adornment, children }: { adornment?: ReactNode; children: ReactNode }) {\n if (!adornment) return children\n return (\n <div className=\"relative w-full min-w-0\">\n {children}\n {adornment}\n </div>\n )\n}\n\nexport function PickerPanel({\n open,\n onOpenChange,\n trigger,\n title,\n header,\n children,\n footer,\n width = 'trigger',\n adornment,\n align = 'start',\n}: PickerPanelProps) {\n const { isMobile } = useBreakpoint()\n const lib = useMotionLib()\n const presets = useMotionPresets()\n const on = lib !== null\n\n // Conteúdo interno do sheet (mobile) e do painel (desktop), igual nos dois modos. A alça e o\n // título ficam à parte porque, em `on`, só eles começam o arraste da folha.\n const sheetHead = (\n <>\n <div className=\"flex shrink-0 flex-col items-center pt-2\">\n <span aria-hidden className=\"h-1 w-12 rounded-full bg-border\" />\n </div>\n <div className=\"flex shrink-0 items-center justify-between gap-2 pr-2 pl-4\">\n <Dialog.Title className=\"truncate text-base font-semibold\">{title}</Dialog.Title>\n <Dialog.Close\n aria-label=\"Fechar\"\n className=\"flex size-touch items-center justify-center rounded-item text-muted-foreground hover:bg-accent\"\n >\n <X className=\"size-icon-md\" aria-hidden />\n </Dialog.Close>\n </div>\n </>\n )\n const sheetRest = (\n <>\n {header && <div className=\"shrink-0 border-b px-4 pb-3\">{header}</div>}\n <div className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain p-2\">{children}</div>\n {footer && <div className=\"shrink-0 border-t px-4 pt-3 pb-safe\">{footer}</div>}\n </>\n )\n const sheetBody = (\n <>\n {sheetHead}\n {sheetRest}\n </>\n )\n // O painel nasce do campo, não do centro (W6): a origem vem do Radix (é um Popover).\n const panelCls = cn(\n 'z-50 flex max-h-command origin-(--radix-popover-content-transform-origin) flex-col overflow-hidden rounded-surface border bg-popover text-popover-foreground shadow-md outline-none',\n width === 'trigger' ? 'w-trigger max-w-popover' : 'w-auto max-w-popover md:max-w-none',\n )\n const panelBody = (\n <>\n {header && <div className=\"shrink-0 border-b p-2\">{header}</div>}\n <div className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain p-1\">{children}</div>\n {footer && <div className=\"shrink-0 border-t p-2\">{footer}</div>}\n </>\n )\n\n if (on && isMobile) {\n return (\n <MobileSheet\n open={open}\n onOpenChange={onOpenChange}\n trigger={trigger}\n adornment={adornment}\n head={sheetHead}\n rest={sheetRest}\n />\n )\n }\n\n if (on) {\n return (\n <Popover.Root open={open} onOpenChange={onOpenChange}>\n <Anchor adornment={adornment}>\n <Popover.Trigger asChild>{trigger}</Popover.Trigger>\n </Anchor>\n <lib.AnimatePresence>\n {open && (\n <Popover.Portal forceMount key=\"panel\">\n <Popover.Content\n forceMount\n asChild\n align={align}\n sideOffset={6}\n collisionPadding={16}\n className={panelCls}\n >\n <lib.m.div {...presets.open()}>{panelBody}</lib.m.div>\n </Popover.Content>\n </Popover.Portal>\n )}\n </lib.AnimatePresence>\n </Popover.Root>\n )\n }\n\n if (isMobile) {\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Anchor adornment={adornment}>\n <Dialog.Trigger asChild>{trigger}</Dialog.Trigger>\n </Anchor>\n <Dialog.Portal>\n <Dialog.Overlay className=\"fixed inset-0 z-40 bg-overlay data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0\" />\n <Dialog.Content\n aria-describedby={undefined}\n className=\"fixed inset-x-0 bottom-0 z-50 flex max-h-sheet flex-col rounded-t-surface border-t bg-popover text-popover-foreground shadow-lg outline-none data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:slide-out-to-bottom data-[state=open]:animate-in data-[state=open]:slide-in-from-bottom\"\n >\n {sheetBody}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n )\n }\n\n return (\n <Popover.Root open={open} onOpenChange={onOpenChange}>\n <Anchor adornment={adornment}>\n <Popover.Trigger asChild>{trigger}</Popover.Trigger>\n </Anchor>\n <Popover.Portal>\n <Popover.Content\n align={align}\n sideOffset={6}\n collisionPadding={16}\n className={cn(\n 'z-50 flex max-h-command origin-(--radix-popover-content-transform-origin) flex-col overflow-hidden rounded-surface border bg-popover text-popover-foreground shadow-md outline-none',\n 'data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',\n width === 'trigger' ? 'w-trigger max-w-popover' : 'w-auto max-w-popover md:max-w-none',\n )}\n >\n {panelBody}\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n )\n}\n","import { Dialog } from 'radix-ui'\nimport { useState, type ReactNode } from 'react'\nimport { Modal } from '@/components/ui/modal'\nimport { cn } from '@/lib/cn'\nimport { useMotionLib, useMotionPresets } from '@/lib/motion'\nimport { OverlayShell } from './overlay-shell'\n\n/*\n * Drawer único, componente central do sistema. Desliza da direita para a esquerda.\n * Para formulários e detalhes de volume médio (até ~12 campos).\n * Header fixo: ícone, título, descrição e fechar.\n * Body: única área com rolagem.\n * Footer fixo: ações (use <ActionBar>), com borda superior.\n * Mobile: tela inteira (100dvh), footer acima da área segura e do teclado.\n * Fecha por Esc e clique fora; com dirty, pede confirmação antes.\n */\n\n/*\n * Largura no desktop, em porcentagem da tela: 30 (padrão), 40, 50 ou 75. Nunca menos que\n * 28rem (para caber o formulário em telas médias); no celular, sempre tela inteira.\n * sm, md, lg e xl são os nomes antigos e valem 30, 30, 50 e 75.\n */\nconst sizes = {\n '30': 'md:w-sheet-30',\n '40': 'md:w-sheet-40',\n '50': 'md:w-sheet-50',\n '75': 'md:w-sheet-75',\n full: 'md:w-full',\n sm: 'md:w-sheet-30',\n md: 'md:w-sheet-30',\n lg: 'md:w-sheet-50',\n xl: 'md:w-sheet-75',\n} as const\n\nconst overlayCls = 'fixed inset-0 z-50 bg-overlay'\nconst panelCls =\n 'fixed inset-y-0 right-0 z-50 flex h-dvh w-full flex-col bg-card text-card-foreground shadow-lg outline-none md:border-l'\n\nexport interface DrawerProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n title: ReactNode\n description?: ReactNode\n icon?: ReactNode\n size?: keyof typeof sizes\n children: ReactNode\n /** Rodapé fixo. Normalmente um <ActionBar>. */\n footer?: ReactNode\n /** Há alterações não salvas: fechar pede confirmação. */\n dirty?: boolean\n /** Textos da confirmação de descarte. */\n discardTitle?: string\n discardDescription?: string\n}\n\nexport function Drawer({\n open,\n onOpenChange,\n title,\n description,\n icon,\n size = '30',\n children,\n footer,\n dirty,\n discardTitle = 'Descartar alterações?',\n discardDescription = 'As informações preenchidas neste painel serão perdidas.',\n}: DrawerProps) {\n const [confirming, setConfirming] = useState(false)\n const requestClose = () => (dirty ? setConfirming(true) : onOpenChange(false))\n const lib = useMotionLib()\n const presets = useMotionPresets()\n\n const keepOpenIfDirty = (e: { preventDefault: () => void }) => {\n if (dirty) {\n e.preventDefault()\n setConfirming(true)\n }\n }\n const shell = (\n <OverlayShell\n title={title}\n description={description}\n icon={icon}\n footer={footer}\n onRequestClose={requestClose}\n >\n {children}\n </OverlayShell>\n )\n\n return (\n <>\n <Dialog.Root open={open} onOpenChange={(o) => (o ? onOpenChange(true) : requestClose())}>\n {lib ? (\n // `on`: o painel só existe enquanto aberto ou saindo; o Radix fica com forceMount.\n <lib.AnimatePresence>\n {open && (\n <Dialog.Portal forceMount key=\"drawer\">\n <Dialog.Overlay forceMount asChild>\n <lib.m.div className={overlayCls} {...presets.fade} />\n </Dialog.Overlay>\n <Dialog.Content\n forceMount\n asChild\n onEscapeKeyDown={keepOpenIfDirty}\n onPointerDownOutside={keepOpenIfDirty}\n data-rendra=\"GAV-001\"\n className={cn(panelCls, sizes[size])}\n >\n <lib.m.div {...presets.sheet('right')}>{shell}</lib.m.div>\n </Dialog.Content>\n </Dialog.Portal>\n )}\n </lib.AnimatePresence>\n ) : (\n <Dialog.Portal>\n <Dialog.Overlay\n className={cn(\n overlayCls,\n 'data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0',\n )}\n />\n <Dialog.Content\n onEscapeKeyDown={keepOpenIfDirty}\n onPointerDownOutside={keepOpenIfDirty}\n data-rendra=\"GAV-001\"\n className={cn(\n panelCls,\n 'data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:slide-out-to-right data-[state=open]:animate-in data-[state=open]:slide-in-from-right',\n sizes[size],\n )}\n >\n {shell}\n </Dialog.Content>\n </Dialog.Portal>\n )}\n </Dialog.Root>\n <Modal\n open={confirming}\n onOpenChange={setConfirming}\n type=\"destructive\"\n title={discardTitle}\n description={discardDescription}\n confirmLabel=\"Descartar\"\n cancelLabel=\"Continuar editando\"\n onConfirm={() => onOpenChange(false)}\n />\n </>\n )\n}\n","/**\n * Mapas de classes das primitivas de layout. Classes completas e estáticas,\n * para o Tailwind encontrá-las. Só os degraus da escala permitida.\n */\nexport type Space =\n '0' | '1' | '2' | '3' | '4' | '6' | '8' | '12' | '16' | '24' | 'section' | 'fields'\n\nexport const gapClass: Record<Space, string> = {\n '0': 'gap-0',\n '1': 'gap-1',\n '2': 'gap-2',\n '3': 'gap-3',\n '4': 'gap-4',\n '6': 'gap-6',\n '8': 'gap-8',\n '12': 'gap-12',\n '16': 'gap-16',\n '24': 'gap-24',\n // Espaço entre seções de página: menor no mobile, cheio no desktop.\n section: 'gap-8 md:gap-12',\n // Entre campos de formulário (Field): 16px do fim de um campo ao rótulo do próximo.\n fields: 'gap-x-4 gap-y-4 md:gap-x-6',\n}\n\n/**\n * Grade de formulário, pela largura do próprio bloco (container query), não da tela:\n * 1 coluna estreito, 6 colunas a partir de 28rem, 12 colunas a partir de 48rem.\n * No largo, o padrão é 3 campos por linha (md = 4/12). Nunca 2 por linha por padrão.\n */\nexport const fieldGridClass = 'grid grid-cols-1 @md:grid-cols-6 @3xl:grid-cols-12'\n\n/** Largura do Field na grade de formulário (no largo, em 12 colunas). */\nexport const fieldSpanClass = {\n /** 2/12, cerca de 17%: UF, número, DDD. */\n xs: '@md:col-span-2 @3xl:col-span-2',\n /** 3/12 = 25%: CEP, CNPJ, CPF, datas curtas. */\n sm: '@md:col-span-2 @3xl:col-span-3',\n /** 4/12 = 33%: o padrão, 3 campos por linha. */\n md: '@md:col-span-3 @3xl:col-span-4',\n /** 6/12 = 50%. */\n lg: '@md:col-span-3 @3xl:col-span-6',\n /** 8/12 = 67%: nome, logradouro longo. */\n xl: '@md:col-span-6 @3xl:col-span-8',\n /** Linha inteira. */\n full: '@md:col-span-6 @3xl:col-span-12',\n} as const\n\nexport type FieldSpan = keyof typeof fieldSpanClass\n\nexport const alignClass = {\n start: 'items-start',\n center: 'items-center',\n end: 'items-end',\n stretch: 'items-stretch',\n baseline: 'items-baseline',\n} as const\n\nexport const justifyClass = {\n start: 'justify-start',\n center: 'justify-center',\n end: 'justify-end',\n between: 'justify-between',\n} as const\n\nexport type Align = keyof typeof alignClass\nexport type Justify = keyof typeof justifyClass\n","import { Label as L } from 'radix-ui'\nimport {\n cloneElement,\n createContext,\n isValidElement,\n useContext,\n useId,\n type ComponentProps,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport { fieldSpanClass, type FieldSpan } from '@/components/layout/tokens'\nimport { cn } from '@/lib/cn'\n\n/*\n * Rótulo, ajuda e erro padronizados.\n * Regras: rótulo sempre acima; obrigatório marcado no rótulo; erro abaixo do campo em\n * espaço reservado (a tela não pula quando o erro aparece).\n */\n\nexport function Label({\n className,\n required,\n children,\n ...props\n}: ComponentProps<typeof L.Root> & { required?: boolean }) {\n return (\n <L.Root\n data-rendra=\"FLD-002\"\n className={cn('text-label text-label-foreground label-case', className)}\n {...props}\n >\n {children}\n {required && (\n <span className=\"text-destructive\" aria-hidden>\n {' '}\n *\n </span>\n )}\n {required && <span className=\"sr-only\"> (obrigatório)</span>}\n </L.Root>\n )\n}\n\ninterface FieldContextValue {\n id: string\n describedBy: string\n invalid: boolean\n}\nconst FieldContext = createContext<FieldContextValue | null>(null)\n\n/** Liga um controle ao Field mais próximo (id, aria-describedby, aria-invalid). */\nexport function useFieldControl() {\n return useContext(FieldContext)\n}\n\nexport interface FieldProps {\n label?: ReactNode\n required?: boolean\n /** Texto de ajuda sempre visível (substitui tooltip no mobile). */\n help?: ReactNode\n /** Mensagem de erro, abaixo do controle, no lugar da ajuda. */\n error?: ReactNode\n /**\n * Largura na grade de formulário (Grid form ou FormSection): xs (17%), sm (25%),\n * md (33%, padrão: 3 por linha), lg (50%), xl (67%), full. half é o antigo e vale md.\n */\n span?: FieldSpan | 'half'\n /** Começa uma linha nova (ex.: os campos que vêm depois do CEP ou do CNPJ). */\n newRow?: boolean\n /**\n * Reserva a linha da mensagem mesmo vazia, para o erro não empurrar o que vem abaixo\n * (útil em formulários em grid de 2 colunas com validação ao digitar). Padrão: não\n * reserva, e os campos ficam mais próximos.\n */\n reserveMessage?: boolean\n /** Obsoleto: sem reserva já é o padrão. Mantido para não quebrar telas existentes. */\n compact?: boolean\n /** id do controle; gerado automaticamente se omitido. */\n id?: string\n className?: string\n children: ReactNode\n}\n\nexport function Field({\n label,\n required,\n help,\n error,\n span = 'md',\n newRow,\n reserveMessage = false,\n id,\n className,\n children,\n}: FieldProps) {\n const auto = useId()\n const controlId = id ?? `campo${auto}`\n const messageId = `${controlId}-mensagem`\n const invalid = Boolean(error)\n const message = error ?? help\n\n // Repassa id e acessibilidade ao controle filho quando ele é um elemento simples.\n const child =\n isValidElement(children) && typeof children.type !== 'string'\n ? cloneElement(children as ReactElement<Record<string, unknown>>, {\n id: (children.props as { id?: string }).id ?? controlId,\n // Só repassa invalid quando há erro, para não vazar o atributo em elementos comuns.\n ...(invalid\n ? { invalid: (children.props as { invalid?: boolean }).invalid ?? true }\n : {}),\n 'aria-describedby': message ? messageId : undefined,\n 'aria-required': required || undefined,\n })\n : children\n\n return (\n <FieldContext.Provider\n value={{ id: controlId, describedBy: message ? messageId : '', invalid }}\n >\n <div\n data-slot=\"field\"\n data-rendra=\"FLD-001\"\n className={cn(\n 'flex min-w-0 flex-col gap-2',\n fieldSpanClass[span === 'half' ? 'md' : span],\n newRow && '@md:col-start-1 @3xl:col-start-1',\n className,\n )}\n >\n {label && (\n <Label htmlFor={controlId} required={required}>\n {label}\n </Label>\n )}\n {child}\n {(reserveMessage || message) && (\n <p\n id={messageId}\n role={invalid ? 'alert' : undefined}\n className={cn(\n '-mt-1 min-h-4 text-help',\n invalid ? 'font-medium text-destructive' : 'text-help-foreground',\n )}\n >\n {message}\n </p>\n )}\n </div>\n </FieldContext.Provider>\n )\n}\n","import { Command } from 'cmdk'\nimport { Check, ChevronDown, Plus, Search, X } from 'lucide-react'\nimport { forwardRef, useEffect, useId, useMemo, useRef, useState, type ReactNode } from 'react'\nimport { Button } from '@/components/ui/button'\nimport { Spinner } from '@/components/ui/spinner'\nimport { useBreakpoint } from '@/hooks/use-breakpoint'\nimport { cn } from '@/lib/cn'\nimport {\n controlAdornmentButton,\n controlAdornmentSpace,\n controlFrame,\n type ControlSize,\n} from '@/lib/control'\nimport { PickerPanel } from './picker-panel'\n\nexport interface SelectOption {\n value: string\n label: string\n description?: string\n icon?: ReactNode\n disabled?: boolean\n /** Agrupa opções sob um título. */\n group?: string\n}\n\ninterface BaseProps {\n options?: SelectOption[]\n placeholder?: string\n /**\n * Nome do campo: título do painel no mobile e, quando o Select não está dentro de um\n * Field (sem id ligado a um rótulo visível), nome acessível do gatilho.\n */\n label?: string\n size?: ControlSize\n invalid?: boolean\n disabled?: boolean\n /** Campo de busca no topo da lista. */\n searchable?: boolean\n /** Permite criar uma opção nova a partir do texto buscado. */\n creatable?: boolean\n onCreate?: (label: string) => SelectOption | Promise<SelectOption>\n /** Busca remota: recebe o texto e devolve as opções. Liga a busca automaticamente. */\n loadOptions?: (query: string) => Promise<SelectOption[]>\n /** Mostra indicador de carregamento na lista. */\n loading?: boolean\n /** Botão de limpar no campo. */\n clearable?: boolean\n emptyText?: string\n id?: string\n className?: string\n 'aria-describedby'?: string\n}\n\n/** Acima deste número de opções, o \"Selecionar todos\" aparece sem a prop `selectAll`. */\nconst SELECT_ALL_AUTO_MIN = 5\n\ninterface SingleProps extends BaseProps {\n multiple?: false\n value?: string | null\n onChange?: (value: string | null) => void\n selectAll?: never\n showCount?: never\n maxChips?: never\n}\n\ninterface MultipleProps extends BaseProps {\n /** Seleção múltipla com checkbox e chips. */\n multiple: true\n value?: string[]\n onChange?: (value: string[]) => void\n /**\n * Linha \"Selecionar todos\" no topo da lista (vira \"Desmarcar todos\" com tudo marcado).\n * Padrão: aparece sozinha com mais de 5 opções; `false` desliga, `true` força com 5 ou menos.\n */\n selectAll?: boolean\n /** Mostra \"3 selecionados\" no lugar dos chips. */\n showCount?: boolean\n /** Máximo de chips visíveis antes de \"+N\". */\n maxChips?: number\n}\n\nexport type SelectProps = SingleProps | MultipleProps\n\n/**\n * Select único do sistema. Busca, múltiplo, selecionar todos, contador, criar opção,\n * busca remota e carregamento são props. No mobile abre como bottom sheet.\n */\nexport const Select = forwardRef<HTMLButtonElement, SelectProps>(function Select(props, ref) {\n const {\n options: staticOptions = [],\n placeholder = 'Selecione',\n label,\n size,\n invalid,\n disabled,\n searchable,\n creatable,\n onCreate,\n loadOptions,\n loading,\n clearable,\n emptyText = 'Nenhuma opção encontrada.',\n id,\n className,\n } = props\n const multiple = props.multiple === true\n const { isMobile } = useBreakpoint()\n const [open, setOpen] = useState(false)\n const listId = `${useId()}-lista`\n const [query, setQuery] = useState('')\n const [remote, setRemote] = useState<SelectOption[] | null>(null)\n const [remoteLoading, setRemoteLoading] = useState(false)\n const [created, setCreated] = useState<SelectOption[]>([])\n const [innerSingle, setInnerSingle] = useState<string | null>(null)\n const [innerMulti, setInnerMulti] = useState<string[]>([])\n // No mobile, o múltiplo só aplica ao confirmar.\n const [draft, setDraft] = useState<string[]>([])\n\n const selectedSingle = multiple ? null : ((props as SingleProps).value ?? innerSingle)\n const selectedMulti = multiple ? ((props as MultipleProps).value ?? innerMulti) : []\n\n // Busca remota com espera curta entre teclas.\n const seq = useRef(0)\n useEffect(() => {\n if (!loadOptions || !open) return\n const n = ++seq.current\n setRemoteLoading(true)\n const t = window.setTimeout(async () => {\n const res = await loadOptions(query)\n if (n === seq.current) {\n setRemote(res)\n setRemoteLoading(false)\n }\n }, 250)\n return () => window.clearTimeout(t)\n }, [loadOptions, query, open])\n\n const all = useMemo(() => {\n const base = remote ?? staticOptions\n const map = new Map<string, SelectOption>()\n ;[...base, ...created].forEach((o) => map.set(o.value, o))\n return [...map.values()]\n }, [remote, staticOptions, created])\n\n const byValue = (v: string) => all.find((o) => o.value === v)\n const isSearchable = searchable || creatable || Boolean(loadOptions)\n const busy = loading || remoteLoading\n const multiValue = isMobile && multiple ? draft : selectedMulti\n\n const commitSingle = (v: string | null) => {\n setInnerSingle(v)\n ;(props as SingleProps).onChange?.(v)\n }\n const commitMulti = (v: string[]) => {\n setInnerMulti(v)\n ;(props as MultipleProps).onChange?.(v)\n }\n\n const toggle = (v: string) => {\n if (!multiple) {\n commitSingle(v)\n setOpen(false)\n return\n }\n const next = multiValue.includes(v) ? multiValue.filter((x) => x !== v) : [...multiValue, v]\n if (isMobile) setDraft(next)\n else commitMulti(next)\n }\n\n const enabled = all.filter((o) => !o.disabled)\n const allSelected = enabled.length > 0 && enabled.every((o) => multiValue.includes(o.value))\n const showSelectAll =\n multiple && ((props as MultipleProps).selectAll ?? all.length > SELECT_ALL_AUTO_MIN)\n const toggleAll = () => {\n const next = allSelected ? [] : enabled.map((o) => o.value)\n if (isMobile) setDraft(next)\n else commitMulti(next)\n }\n\n const create = async () => {\n const text = query.trim()\n if (!text) return\n const opt = onCreate ? await onCreate(text) : { value: text, label: text }\n setCreated((c) => [...c, opt])\n setQuery('')\n toggle(opt.value)\n }\n\n const onOpenChange = (o: boolean) => {\n setOpen(o)\n if (o) setDraft(selectedMulti)\n else setQuery('')\n }\n\n // ------------------------------------------------ gatilho\n const hasValue = multiple ? selectedMulti.length > 0 : selectedSingle != null\n const maxChips = (props as MultipleProps).maxChips ?? 2\n let display: ReactNode = <span className=\"truncate text-muted-foreground\">{placeholder}</span>\n if (!multiple && selectedSingle != null) {\n const o = byValue(selectedSingle)\n display = (\n <span className=\"flex min-w-0 items-center gap-2\">\n {o?.icon}\n <span className=\"truncate\">{o?.label ?? selectedSingle}</span>\n </span>\n )\n } else if (multiple && selectedMulti.length > 0) {\n display = (props as MultipleProps).showCount ? (\n <span className=\"truncate\">\n {selectedMulti.length} {selectedMulti.length === 1 ? 'selecionado' : 'selecionados'}\n </span>\n ) : (\n <span className=\"flex min-w-0 items-center gap-1 overflow-hidden\">\n {selectedMulti.slice(0, maxChips).map((v) => (\n <span\n key={v}\n className=\"max-w-3xs shrink-0 truncate rounded-item bg-primary-soft px-2 py-1 text-xs leading-none font-medium text-primary-soft-foreground\"\n >\n {byValue(v)?.label ?? v}\n </span>\n ))}\n {selectedMulti.length > maxChips && (\n <span className=\"shrink-0 rounded-item bg-muted px-2 py-1 text-xs leading-none font-medium\">\n +{selectedMulti.length - maxChips}\n </span>\n )}\n </span>\n )\n }\n\n const showClear = clearable && hasValue && !disabled\n const clear = showClear ? (\n <button\n type=\"button\"\n aria-label=\"Limpar seleção\"\n className={cn(\n controlAdornmentButton,\n 'absolute top-1/2 right-8 mr-0 -translate-y-1/2 md:mr-0',\n )}\n onClick={() => (multiple ? commitMulti([]) : commitSingle(null))}\n >\n <X aria-hidden />\n </button>\n ) : undefined\n\n const trigger = (\n <button\n ref={ref}\n id={id}\n type=\"button\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listId}\n aria-haspopup=\"listbox\"\n aria-invalid={invalid || undefined}\n aria-describedby={props['aria-describedby']}\n aria-label={id ? undefined : label}\n disabled={disabled}\n data-rendra=\"SEL-001\"\n // Teclas no gatilho não chegam à lista (Enter não seleciona opção com o painel fechado).\n onKeyDown={(e) => e.stopPropagation()}\n className={cn(\n controlFrame({ size, invalid }),\n 'cursor-pointer text-left disabled:cursor-not-allowed disabled:opacity-60',\n className,\n )}\n >\n <span className=\"flex min-w-0 flex-1 items-center\">{display}</span>\n {showClear && <span aria-hidden className={cn(controlAdornmentSpace, '-mr-1')} />}\n <ChevronDown\n aria-hidden\n className={cn(\n 'size-icon-sm shrink-0 text-muted-foreground transition-transform duration-(--rendra-duration-base) ease-move',\n open && 'rotate-180',\n )}\n />\n </button>\n )\n\n // ------------------------------------------------ lista\n const groups = all.reduce<Record<string, SelectOption[]>>((acc, o) => {\n ;(acc[o.group ?? ''] ??= []).push(o)\n return acc\n }, {})\n const q = query.trim().toLowerCase()\n const showCreate = creatable && q && !all.some((o) => o.label.toLowerCase() === q)\n\n const itemClass =\n 'relative flex min-h-touch cursor-pointer items-center gap-3 rounded-item px-3 text-sm outline-none select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent md:min-h-0 md:py-2'\n\n const checkbox = (checked: boolean) => (\n <span\n aria-hidden\n className={cn(\n 'flex size-icon-sm shrink-0 items-center justify-center rounded-item border transition-colors',\n checked ? 'border-primary bg-primary text-primary-foreground' : 'border-input bg-card',\n )}\n >\n {checked && <Check className=\"size-3\" strokeWidth={3} />}\n </span>\n )\n\n const list = (\n <Command.List id={listId} aria-label={label ?? placeholder}>\n {busy && (\n <Command.Loading>\n <div className=\"flex items-center gap-2 px-3 py-4 text-sm text-muted-foreground\">\n <Spinner size=\"sm\" />\n Carregando opções...\n </div>\n </Command.Loading>\n )}\n {!busy && (\n <Command.Empty className=\"px-3 py-6 text-center text-sm text-muted-foreground\">\n {emptyText}\n </Command.Empty>\n )}\n {showCreate && (\n <Command.Item value={`__criar__${query}`} onSelect={create} className={itemClass}>\n <Plus className=\"size-icon-sm shrink-0 text-primary-text\" aria-hidden />\n <span className=\"truncate\">\n Criar <strong className=\"font-semibold\">“{query.trim()}”</strong>\n </span>\n </Command.Item>\n )}\n {showSelectAll && !q && enabled.length > 0 && (\n <Command.Item\n value=\"__todos__\"\n onSelect={toggleAll}\n className={cn(itemClass, 'font-medium')}\n >\n {checkbox(allSelected)}\n {allSelected ? 'Desmarcar todos' : 'Selecionar todos'}\n </Command.Item>\n )}\n {Object.entries(groups).map(([group, opts]) => (\n <Command.Group\n key={group || 'sem-grupo'}\n heading={group || undefined}\n className=\"[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground\"\n >\n {opts.map((o) => {\n const checked = multiple ? multiValue.includes(o.value) : selectedSingle === o.value\n return (\n <Command.Item\n key={o.value}\n value={`${o.label} ${o.description ?? ''} ${o.value}`}\n disabled={o.disabled}\n onSelect={() => toggle(o.value)}\n aria-selected={checked}\n className={itemClass}\n >\n {multiple && checkbox(checked)}\n {o.icon && <span className=\"flex shrink-0 [&_svg]:size-icon-sm\">{o.icon}</span>}\n <span className=\"flex min-w-0 flex-1 flex-col\">\n <span className={cn('truncate', checked && !multiple && 'font-medium')}>\n {o.label}\n </span>\n {o.description && (\n <span className=\"truncate text-xs text-muted-foreground\">{o.description}</span>\n )}\n </span>\n {!multiple && checked && (\n <Check className=\"size-icon-sm shrink-0 text-primary-text\" aria-hidden />\n )}\n </Command.Item>\n )\n })}\n </Command.Group>\n ))}\n </Command.List>\n )\n\n const search = isSearchable ? (\n <div className={cn(controlFrame({ size: 'md' }), 'bg-background')}>\n <Search className=\"size-icon-sm shrink-0 text-muted-foreground\" aria-hidden />\n <Command.Input\n value={query}\n onValueChange={setQuery}\n placeholder={creatable ? 'Buscar ou criar...' : 'Buscar...'}\n className=\"h-full min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground\"\n />\n </div>\n ) : null\n\n const count = multiValue.length\n const footer =\n multiple && (isMobile || count > 0) ? (\n <div className=\"grid grid-actions-2 gap-3\">\n <Button\n variant=\"outline\"\n onClick={() => (isMobile ? setDraft([]) : commitMulti([]))}\n disabled={count === 0}\n >\n Limpar\n </Button>\n {isMobile ? (\n <Button\n onClick={() => {\n commitMulti(draft)\n setOpen(false)\n }}\n >\n Aplicar{count ? ` (${count})` : ''}\n </Button>\n ) : (\n <Button variant=\"secondary\" onClick={() => setOpen(false)}>\n Pronto ({count})\n </Button>\n )}\n </div>\n ) : undefined\n\n return (\n <Command shouldFilter={!loadOptions} loop className=\"contents\" label={label ?? placeholder}>\n <PickerPanel\n open={open}\n onOpenChange={onOpenChange}\n trigger={trigger}\n adornment={clear}\n title={label ?? placeholder}\n header={search}\n footer={footer}\n >\n {list}\n </PickerPanel>\n </Command>\n )\n})\n","import { useLayoutEffect, useRef } from 'react'\n\n/**\n * Mede o espaço que sobra na área de conteúdo (o <main>) abaixo do elemento e grava em\n * --board-h. Com a classe h-board, o elemento ocupa exatamente essa altura: a página não\n * rola e a rolagem acontece dentro dele (kanban, chat).\n */\nexport function useFillHeight<T extends HTMLElement = HTMLDivElement>() {\n const ref = useRef<T>(null)\n useLayoutEffect(() => {\n const el = ref.current\n if (!el) return\n const main = el.closest('main')\n const measure = () => {\n // O quadro fica com a altura que sobra na área de conteúdo depois de tudo o que está\n // acima e abaixo dele (título, ações, respiro da página): a página nunca rola por ele.\n // Nunca menos que 20rem, para caber ao menos alguns cards.\n const h = el.getBoundingClientRect().height\n // Altura real do conteúdo da página (o primeiro filho do <main>), não a de rolagem.\n const page = main?.firstElementChild as HTMLElement | null\n const room =\n main && page\n ? main.clientHeight - (page.getBoundingClientRect().height - h)\n : window.innerHeight - el.getBoundingClientRect().top\n el.style.setProperty('--board-h', `${Math.max(320, Math.floor(room))}px`)\n }\n measure()\n const ro = new ResizeObserver(measure)\n ro.observe(document.documentElement)\n if (main) ro.observe(main)\n return () => ro.disconnect()\n }, [])\n return ref\n}\n","import { CheckCircle2, SkipForward, XCircle } from 'lucide-react'\nimport type { ComponentType, ElementType, ReactNode } from 'react'\nimport type { FeedbackType } from '@/brand/types'\nimport { cn } from '@/lib/cn'\nimport { useMotionLib, useMotionPresets } from '@/lib/motion'\n\nexport interface TimelineEvent {\n id: string\n title: ReactNode\n description?: ReactNode\n /** Data em formato curto (ex.: \"22/09/2026 14:30\"). */\n date: string\n tone?: FeedbackType | 'neutral'\n icon?: ReactNode\n /** Resultado do evento: mostrado com ícone e texto, nunca só pela cor. */\n status?: 'succeeded' | 'failed' | 'skipped'\n}\n\nconst dot: Record<NonNullable<TimelineEvent['tone']>, string> = {\n neutral: 'bg-muted text-muted-foreground',\n info: 'bg-info-soft text-info-soft-foreground',\n success: 'bg-success-soft text-success-soft-foreground',\n warning: 'bg-warning-soft text-warning-soft-foreground',\n error: 'bg-destructive-soft text-destructive-soft-foreground',\n}\n\nconst statusTone: Record<\n NonNullable<TimelineEvent['status']>,\n NonNullable<TimelineEvent['tone']>\n> = {\n succeeded: 'success',\n failed: 'error',\n skipped: 'neutral',\n}\n\nconst statusIcon: Record<\n NonNullable<TimelineEvent['status']>,\n ComponentType<{ className?: string }>\n> = {\n succeeded: CheckCircle2,\n failed: XCircle,\n skipped: SkipForward,\n}\n\nconst statusLabel: Record<NonNullable<TimelineEvent['status']>, string> = {\n succeeded: 'Concluído',\n failed: 'Falhou',\n skipped: 'Ignorado',\n}\n\nconst statusTextTone: Record<NonNullable<TimelineEvent['status']>, string> = {\n succeeded: 'text-success-soft-foreground',\n failed: 'text-destructive-soft-foreground',\n skipped: 'text-muted-foreground',\n}\n\n/** Linha do tempo única, com eventos em ordem e tom semântico por evento. */\nexport function Timeline({ events, className }: { events: TimelineEvent[]; className?: string }) {\n const lib = useMotionLib()\n const on = lib !== null\n const presets = useMotionPresets()\n // Em `on` cada evento entra com slide curto e atraso escalonado (no máximo 10 itens).\n const Item: ElementType = on ? lib.m.li : 'li'\n const enter = presets.slide('bottom', 'short')\n return (\n <ol data-rendra=\"TLN-001\" className={cn('@container flex flex-col', className)}>\n {events.map((e, i) => {\n const StatusIcon = e.status ? statusIcon[e.status] : null\n const tone = e.tone ?? (e.status ? statusTone[e.status] : 'neutral')\n return (\n <Item\n key={e.id}\n className=\"relative flex gap-3 pb-6 last:pb-0\"\n {...(on\n ? { ...enter, transition: { ...enter.transition, ...presets.stagger(i) } }\n : {})}\n >\n {i < events.length - 1 && (\n <span\n aria-hidden\n className=\"absolute top-8 bottom-0 left-4 w-px -translate-x-1/2 bg-border\"\n />\n )}\n <span\n aria-hidden\n className={cn(\n 'relative flex size-8 shrink-0 items-center justify-center rounded-full [&_svg]:size-icon-sm',\n dot[tone],\n )}\n >\n {e.icon ?? (StatusIcon && <StatusIcon />) ?? (\n <span className=\"size-2 rounded-full bg-current\" />\n )}\n </span>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1 pt-1\">\n <div className=\"flex min-w-0 flex-col gap-1 @sm:flex-row @sm:items-baseline @sm:justify-between @sm:gap-3\">\n <span className=\"text-sm font-medium wrap-break-word\">{e.title}</span>\n <time className=\"shrink-0 text-xs text-muted-foreground tabular-nums\">\n {e.date}\n </time>\n </div>\n {e.description && (\n <p className=\"text-sm wrap-break-word text-muted-foreground\">{e.description}</p>\n )}\n {e.status && StatusIcon && (\n <span\n className={cn(\n 'inline-flex w-fit items-center gap-1 text-xs font-medium [&_svg]:size-icon-sm',\n statusTextTone[e.status],\n )}\n >\n <StatusIcon />\n {statusLabel[e.status]}\n </span>\n )}\n </div>\n </Item>\n )\n })}\n </ol>\n )\n}\n"],"mappings":"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"}
|