@snksergio/design-system 0.52.0 → 0.53.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/dist-lib/chunks/{panel-Bly-rNP9.cjs → panel-CTbiCa0_.cjs} +105 -3
- package/dist-lib/chunks/panel-CTbiCa0_.cjs.map +1 -0
- package/dist-lib/chunks/{panel-DA6K3a3n.mjs → panel-DsOKm4Im.mjs} +155 -53
- package/dist-lib/chunks/panel-DsOKm4Im.mjs.map +1 -0
- package/dist-lib/index.cjs +4 -1
- package/dist-lib/index.cjs.map +1 -1
- package/dist-lib/index.mjs +54 -51
- package/dist-lib/preview/clientes.cjs +1 -1
- package/dist-lib/preview/clientes.mjs +1 -1
- package/dist-lib/src/components/ui/avatar-ig/avatar-group-context.d.ts +24 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar-group-context.d.ts.map +1 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar-group.d.ts +52 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar-group.d.ts.map +1 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar.d.ts +9 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar.d.ts.map +1 -1
- package/dist-lib/src/components/ui/avatar-ig/avatar.styles.d.ts +93 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar.styles.d.ts.map +1 -1
- package/dist-lib/src/components/ui/avatar-ig/avatar.types.d.ts +37 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar.types.d.ts.map +1 -1
- package/dist-lib/src/components/ui/avatar-ig/index.d.ts +3 -2
- package/dist-lib/src/components/ui/avatar-ig/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist-lib/chunks/panel-Bly-rNP9.cjs.map +0 -1
- package/dist-lib/chunks/panel-DA6K3a3n.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel-DsOKm4Im.mjs","sources":["../../src/components/ui/AlertModal/alert-modal.styles.ts","../../src/components/ui/AlertModal/alert-modal.tsx","../../src/utils/color-contrast.ts","../../src/components/ui/avatar-ig/avatar-group-context.ts","../../src/components/ui/avatar-ig/avatar.styles.ts","../../src/components/ui/avatar-ig/avatar.tsx","../../src/components/ui/avatar-ig/avatar-group.tsx","../../src/components/ui/ButtonGroup/button-group.styles.ts","../../src/components/ui/ButtonGroup/button-group.tsx","../../src/components/ui/FormField/form-field.styles.ts","../../src/components/ui/FormField/form-field.tsx","../../src/components/ui/FormField/form-field-input.tsx","../../src/components/ui/FormField/form-field-textarea.tsx","../../src/components/ui/FormField/form-field-select.tsx","../../src/components/ui/FormField/form-field-checkbox.tsx","../../src/components/ui/FormField/form-field-switch.tsx","../../src/components/ui/Combobox/combobox.styles.ts","../../src/components/ui/Combobox/combobox.tsx","../../src/components/ui/Table/table.styles.ts","../../src/components/ui/Table/use-column-resize.ts","../../src/components/ui/Table/table.tsx","../../src/components/ui/Table/table-card-row.tsx","../../src/components/ui/Table/use-column-widths.ts","../../src/components/ui/Table/table.constants.ts","../../src/components/ui/TableToolbar/table-toolbar.styles.ts","../../src/components/ui/TableToolbar/parts/toolbar-divider.tsx","../../src/components/ui/TableToolbar/table-toolbar.tsx","../../src/components/ui/TableToolbar/parts/toolbar-search.tsx","../../src/components/ui/TableToolbar/parts/toolbar-segmented.tsx","../../src/components/ui/TableToolbar/parts/toolbar-tabs.tsx","../../src/components/ui/TableToolbar/parts/toolbar-tool-button.tsx","../../src/components/ui/TableToolbar/parts/toolbar-applied.tsx","../../src/components/ui/TableToolbar/parts/toolbar-actions.tsx","../../src/components/ui/TableToolbar/parts/toolbar-filter-button.tsx","../../src/components/ui/TableToolbar/parts/bulk-actions-bar.tsx","../../src/components/ui/TableToolbar/popovers/more-menu.tsx","../../src/components/ui/TableToolbar/popovers/cols-popover.tsx","../../src/components/ui/TableToolbar/popovers/sort-popover.tsx","../../src/components/ui/TableToolbar/popovers/views-popover.tsx","../../src/components/ui/TableToolbar/popovers/add-view-modal.styles.ts","../../src/components/ui/TableToolbar/popovers/add-view-modal.tsx","../../src/components/ui/TableToolbar/parts/table-toolbar-views.tsx","../../src/components/ui/TableToolbar/popovers/filter-sql-parser.ts","../../src/components/ui/TableToolbar/popovers/filter-popover.tsx","../../src/components/ui/TableToolbar/parts/toolbar-settings-menu.tsx","../../src/components/ui/FloatingPanel/floating-panel.styles.ts","../../src/components/ui/FloatingPanel/use-floating-panel-resize.ts","../../src/components/ui/FloatingPanel/floating-panel.tsx","../../src/components/ui/FloatingPanel/floating-panel-parts.tsx","../../src/components/ui/DataTable/column-types/column-type-registry.ts","../../src/components/ui/DataTable/column-types/_filter-field.tsx","../../src/components/ui/DataTable/column-types/definitions/text-column-type.tsx","../../src/components/ui/DataTable/column-types/_shared.ts","../../src/components/ui/DataTable/column-types/definitions/number-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/date-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/select-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/multi-select-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/boolean-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/currency-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/percentage-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/email-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/phone-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/url-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/user-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/badge-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/tags-column-type.tsx","../../src/components/ui/DataTable/column-types/definitions/datetime-column-type.tsx","../../src/components/ui/DataTable/column-types/index.ts","../../src/components/ui/DataTable/utils/filter-ops.ts","../../src/components/ui/TableToolbar/parts/toolbar-simple-filter-drawer.tsx","../../src/components/ui/FooterTable/footer-table.tsx","../../src/components/ui/Kanban/kanban.styles.ts","../../src/components/ui/Kanban/hooks/use-kanban-dnd.ts","../../src/components/ui/Kanban/kanban.tsx","../../src/components/ui/List/list.styles.ts","../../src/components/ui/List/list-item.tsx","../../src/components/ui/List/layouts/_sortable-item.tsx","../../src/components/ui/List/layouts/standard-layout.tsx","../../src/components/ui/List/layouts/grouped-layout.tsx","../../src/components/ui/List/utils/flatten-tree.ts","../../src/components/ui/List/layouts/hierarchical-layout.tsx","../../src/components/ui/List/hooks/use-selection-set.ts","../../src/components/ui/List/hooks/use-disclosure-set.ts","../../src/components/ui/List/utils/group-items.ts","../../src/components/ui/List/list.tsx","../../src/components/ui/DataTable/data-table.styles.ts","../../src/components/ui/DataTable/data-table.constants.ts","../../src/components/ui/DataTable/context/data-table-context.tsx","../../src/components/ui/DataTable/hooks/use-data-table-columns.ts","../../src/components/ui/DataTable/utils/measure-text.ts","../../src/components/ui/DataTable/utils/action-slots.ts","../../src/components/ui/DataTable/utils/resolve-value.ts","../../src/components/ui/DataTable/utils/calculate-column-widths.ts","../../src/components/ui/DataTable/hooks/use-column-auto-width.ts","../../src/components/ui/DataTable/hooks/use-data-table-sort.ts","../../src/components/ui/DataTable/hooks/use-data-table-pagination.ts","../../src/components/ui/DataTable/hooks/use-data-table-selection.ts","../../src/components/ui/DataTable/hooks/use-data-table-density.ts","../../src/components/ui/DataTable/hooks/use-data-table-search.ts","../../src/components/ui/DataTable/hooks/use-data-table-filters.ts","../../src/components/ui/DataTable/hooks/use-data-table-processor.ts","../../src/components/ui/DataTable/hooks/use-data-table-query.ts","../../src/components/ui/DataTable/hooks/use-data-table-export.ts","../../src/components/ui/DataTable/hooks/state-persistence-utils.ts","../../src/components/ui/DataTable/hooks/use-data-table-state-persistence.ts","../../src/components/ui/DataTable/services/saved-views-mock-service.ts","../../src/components/ui/DataTable/hooks/use-data-table-saved-views.ts","../../src/components/ui/DataTable/utils/tree-rows.ts","../../src/components/ui/DataTable/hooks/use-data-table-controller.ts","../../src/components/ui/DataTable/hooks/use-grab-to-scroll.ts","../../src/components/ui/DataTable/parts/data-table-empty.tsx","../../src/components/ui/DataTable/parts/data-table-loading.tsx","../../src/components/ui/DataTable/parts/data-table-no-results.tsx","../../src/components/ui/DataTable/parts/data-table-column-menu.tsx","../../src/components/ui/DataTable/parts/data-table-actions-cell.tsx","../../src/components/ui/DataTable/parts/sortable-head-cell.tsx","../../src/components/ui/DataTable/utils/aggregate.ts","../../src/components/ui/DataTable/parts/data-table-totalizer-row.tsx","../../src/components/ui/DataTable/parts/data-table-edit-cell.tsx","../../src/components/ui/DataTable/parts/data-table-tree-toggle.tsx","../../src/components/ui/DataTable/parts/data-table-cell-addons.styles.ts","../../src/components/ui/DataTable/parts/data-table-cell-addons.tsx","../../src/components/ui/DataTable/parts/data-table-row.tsx","../../src/components/ui/DataTable/parts/data-table-group-header-row.tsx","../../src/components/ui/DataTable/parts/data-table-group-content-row.tsx","../../src/components/ui/DataTable/utils/group-rows.ts","../../src/components/ui/DataTable/parts/data-table-row-expansion.tsx","../../src/components/ui/DataTable/utils/expand-rows.ts","../../src/components/ui/DataTable/hooks/use-sort-popover-adapter.ts","../../src/components/ui/DataTable/hooks/use-cols-popover-adapter.ts","../../src/components/ui/DataTable/hooks/use-filter-popover-adapter.ts","../../src/components/ui/DataTable/hooks/use-data-table-view-mode.ts","../../src/components/ui/DataTable/data-table.tsx","../../src/components/ui/DataTable/parts/data-table-floating-bulk-bar.tsx","../../src/components/ui/DataTable/builders/preset-view.ts","../../src/components/ui/Panel/panel.styles.ts","../../src/components/ui/Panel/panel-header.tsx","../../src/components/ui/Panel/panel-body.tsx","../../src/components/ui/Panel/panel-footer.tsx","../../src/components/ui/Panel/panel.tsx"],"sourcesContent":["import { tv } from \"@/utils/tv\";\n\n/**\n * Ícone circular (56x56) com bg-tone-muted + fg-tone.\n * Alinhado com `.tbl-confirm-icon` do sandbox.\n */\nexport const alertModalIcon = tv({\n base: [\n \"inline-flex items-center justify-center\",\n \"size-[56px] shrink-0 rounded-radius-full\",\n \"[&_svg]:size-[26px]\",\n ],\n variants: {\n tone: {\n default: \"bg-bg-brand-subtle text-fg-brand\",\n neutral: \"bg-bg-muted text-fg-muted\",\n danger: \"bg-bg-danger-muted text-fg-danger\",\n warning: \"bg-bg-warning-muted text-fg-warning\",\n success: \"bg-bg-success-muted text-fg-success\",\n },\n },\n defaultVariants: { tone: \"default\" },\n});\n","import { AlertTriangle, AlertCircle, CheckCircle2, Info, X } from \"lucide-react\";\r\nimport {\r\n AlertDialog,\r\n AlertDialogAction,\r\n AlertDialogCancel,\r\n AlertDialogContent,\r\n AlertDialogDescription,\r\n AlertDialogFooter,\r\n AlertDialogHeader,\r\n AlertDialogTitle,\r\n} from \"@/components/shadcn/alert-dialog\";\r\nimport { Button } from \"@/components/ui/Button/button\";\r\nimport { alertModalIcon } from \"./alert-modal.styles\";\r\nimport type { AlertModalProps, AlertModalTone } from \"./alert-modal.types\";\r\n\r\n/**\r\n * AlertModal — wrapper \"one-shot\" pro AlertDialog do shadcn.\r\n *\r\n * Cobre o caso comum de \"confirmação destrutiva\" (ex: excluir cliente):\r\n * <AlertModal\r\n * open={confirmDelete}\r\n * onOpenChange={setConfirmDelete}\r\n * tone=\"danger\"\r\n * title=\"Excluir cliente?\"\r\n * description='Esta ação não pode ser desfeita. O cliente \"Maria Silva\" será removido permanentemente.'\r\n * confirmLabel=\"Excluir cliente\"\r\n * onConfirm={handleDelete}\r\n * />\r\n *\r\n * Pra layouts customizados (sem ícone, com input dentro, etc), use o\r\n * <AlertDialog> primitive direto.\r\n */\r\n\r\nconst TONE_ICON: Record<AlertModalTone, React.ReactNode> = {\r\n default: null,\r\n neutral: <Info strokeWidth={2.2} />,\r\n danger: <AlertTriangle strokeWidth={2.2} />,\r\n warning: <AlertCircle strokeWidth={2.2} />,\r\n success: <CheckCircle2 strokeWidth={2.2} />,\r\n};\r\n\r\nconst TONE_BUTTON_COLOR: Record<\r\n AlertModalTone,\r\n \"primary\" | \"critical\" | \"warning\" | \"success\"\r\n> = {\r\n default: \"primary\",\r\n neutral: \"primary\",\r\n danger: \"critical\",\r\n warning: \"warning\",\r\n success: \"success\",\r\n};\r\n\r\nexport function AlertModal({\r\n open,\r\n onOpenChange,\r\n tone = \"default\",\r\n title,\r\n description,\r\n confirmLabel = \"Confirmar\",\r\n cancelLabel = \"Cancelar\",\r\n hideCancel,\r\n hideClose,\r\n onConfirm,\r\n icon,\r\n loading,\r\n className,\r\n}: AlertModalProps) {\r\n const iconNode = icon === undefined ? TONE_ICON[tone] : icon;\r\n\r\n const handleConfirm = (e: React.MouseEvent<HTMLButtonElement>) => {\r\n // Previne o close default do AlertDialogAction se loading — quem chamar\r\n // controla onOpenChange após o async terminar.\r\n if (loading) {\r\n e.preventDefault();\r\n return;\r\n }\r\n onConfirm?.();\r\n };\r\n\r\n return (\r\n <AlertDialog open={open} onOpenChange={onOpenChange}>\r\n <AlertDialogContent\r\n className={className}\r\n // O 4º caminho de dismiss. Os outros 3 já eram travados no `loading` — Confirmar\r\n // por `preventDefault`, Cancelar e X por `disabled` — e o ESC escapava porque é o\r\n // único que não passa por um botão: ia direto pro DismissableLayer do Radix.\r\n //\r\n // Sem isto, num delete assíncrono o usuário aperta ESC, o modal desaparece e a\r\n // requisição segue em voo: a exclusão acontece depois, sem feedback ligado à ação.\r\n // E quebrava duas promessas escritas do USAGE — \"trava interação durante async\" e\r\n // \"modal não fecha automaticamente\".\r\n //\r\n // `preventDefault` no ESC (e não um guard no `onOpenChange`) é a saída idiomática:\r\n // barra o dismiss na origem, então o `onOpenChange` do consumidor não é chamado —\r\n // quem faz `onOpenChange={(o) => { setOpen(o); telemetria(o); }}` não recebe evento\r\n // fantasma. É o mesmo mecanismo que o gotcha do `alert-dialog` já indicava para\r\n // decisão inescapável.\r\n onEscapeKeyDown={(e) => {\r\n if (loading) e.preventDefault();\r\n }}\r\n >\r\n {!hideClose && (\r\n <button\r\n type=\"button\"\r\n onClick={() => onOpenChange(false)}\r\n disabled={loading}\r\n aria-label=\"Fechar\"\r\n className=\"absolute top-pad-lg right-pad-lg z-10 grid place-items-center size-form-sm rounded-radius-md bg-transparent text-fg-muted opacity-55 transition-[background-color,color,opacity] outline-none hover:bg-bg-muted hover:text-fg-default hover:opacity-100 focus-visible:opacity-100 focus-visible:shadow-sh-ring disabled:pointer-events-none\"\r\n >\r\n <X className=\"size-4\" />\r\n </button>\r\n )}\r\n <AlertDialogHeader>\r\n {iconNode && (\r\n <div className={alertModalIcon({ tone })} aria-hidden=\"true\">\r\n {iconNode}\r\n </div>\r\n )}\r\n <AlertDialogTitle>{title}</AlertDialogTitle>\r\n {description && (\r\n <AlertDialogDescription>{description}</AlertDialogDescription>\r\n )}\r\n </AlertDialogHeader>\r\n <AlertDialogFooter>\r\n {!hideCancel && (\r\n <AlertDialogCancel asChild>\r\n <Button\r\n type=\"button\"\r\n color=\"secondary\"\r\n variant=\"outline\"\r\n size=\"md\"\r\n fullWidth\r\n disabled={loading}\r\n >\r\n {cancelLabel}\r\n </Button>\r\n </AlertDialogCancel>\r\n )}\r\n <AlertDialogAction asChild>\r\n <Button\r\n type=\"button\"\r\n color={TONE_BUTTON_COLOR[tone]}\r\n variant=\"filled\"\r\n size=\"md\"\r\n fullWidth\r\n loading={loading}\r\n onClick={handleConfirm}\r\n >\r\n {confirmLabel}\r\n </Button>\r\n </AlertDialogAction>\r\n </AlertDialogFooter>\r\n </AlertDialogContent>\r\n </AlertDialog>\r\n );\r\n}\r\n","/**\r\n * Color contrast utilities — WCAG 2.x relative luminance.\r\n *\r\n * Used by components que aplicam bg arbitrário (hex/css color) e precisam\r\n * escolher cor de texto que tenha contraste mínimo (white vs black).\r\n *\r\n * Caso real (v0.7.1): Avatar com `colorHex={bankColor}` antes aplicava\r\n * `text-white` cego — quebra contraste em cores claras (BB amarelo #FAE128\r\n * + branco = ratio 1.29:1, falha WCAG AA 4.5:1). Agora escolhe preto/branco\r\n * baseado em luminância calculada.\r\n */\r\n\r\n/* ── Tipo público ──────────────────────────────────────────────────────────── */\r\n\r\nexport type ContrastTextColor = \"white\" | \"black\";\r\n\r\n/* ── Internals ─────────────────────────────────────────────────────────────── */\r\n\r\ntype RGB = { r: number; g: number; b: number };\r\n\r\n/**\r\n * Converte hex (#RGB, #RRGGBB ou #RRGGBBAA — alpha ignorado) pra RGB 0-255.\r\n * Retorna null se inválido.\r\n */\r\nfunction hexToRgb(hex: string): RGB | null {\r\n if (typeof hex !== \"string\") return null;\r\n let h = hex.trim().replace(/^#/, \"\");\r\n if (h.length === 3) {\r\n h = h.split(\"\").map((c) => c + c).join(\"\");\r\n } else if (h.length === 8) {\r\n h = h.slice(0, 6);\r\n }\r\n if (h.length !== 6 || !/^[0-9a-fA-F]{6}$/.test(h)) return null;\r\n return {\r\n r: parseInt(h.slice(0, 2), 16),\r\n g: parseInt(h.slice(2, 4), 16),\r\n b: parseInt(h.slice(4, 6), 16),\r\n };\r\n}\r\n\r\n/**\r\n * Relative luminance per WCAG 2.x — fórmula oficial com gamma correction.\r\n * Retorna valor entre 0 (preto) e 1 (branco puro).\r\n *\r\n * https://www.w3.org/WAI/GL/wiki/Relative_luminance\r\n */\r\nfunction relativeLuminance({ r, g, b }: RGB): number {\r\n const channel = (c: number) => {\r\n const s = c / 255;\r\n return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);\r\n };\r\n return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);\r\n}\r\n\r\n/**\r\n * Contrast ratio entre 2 luminâncias (WCAG fórmula `(L1+0.05)/(L2+0.05)`).\r\n */\r\nfunction contrastRatio(l1: number, l2: number): number {\r\n const [hi, lo] = l1 > l2 ? [l1, l2] : [l2, l1];\r\n return (hi + 0.05) / (lo + 0.05);\r\n}\r\n\r\n/* ── Public API ────────────────────────────────────────────────────────────── */\r\n\r\n/**\r\n * Escolhe a cor de texto (branco ou preto) com MAIOR contraste sobre um bg.\r\n *\r\n * Comportamento:\r\n * - Compara `(white, bg)` vs `(black, bg)` via contrast ratio WCAG\r\n * - Retorna o vencedor — sempre o que tem ratio mais alto\r\n * - Default \"white\" pra cores escuras (luminância baixa), \"black\" pra cores\r\n * claras (luminância alta). Threshold dinâmico ~50% (não fixo)\r\n *\r\n * Fallback: hex inválido → \"white\" (preserva comportamento legado de\r\n * `text-white` cego — caller deve garantir hex válido).\r\n *\r\n * Exemplos:\r\n * - \"#FAE128\" (BB amarelo) → \"black\" (white ratio 1.29, black ratio 16.3)\r\n * - \"#820AD1\" (Nubank roxo) → \"white\" (white ratio 6.2, black ratio 3.4)\r\n * - \"#EC7000\" (Itaú laranja)→ \"black\" (white ratio 2.7, black ratio 7.8)\r\n * - \"#FFFFFF\" (branco) → \"black\"\r\n * - \"#000000\" (preto) → \"white\"\r\n *\r\n * @param bgColor - hex string (#RGB, #RRGGBB ou #RRGGBBAA)\r\n * @returns \"white\" | \"black\" — cor de texto recomendada\r\n */\r\nexport function getContrastTextColor(bgColor: string): ContrastTextColor {\r\n const rgb = hexToRgb(bgColor);\r\n if (!rgb) return \"white\";\r\n const bgLum = relativeLuminance(rgb);\r\n const whiteContrast = contrastRatio(1, bgLum);\r\n const blackContrast = contrastRatio(0, bgLum);\r\n return whiteContrast >= blackContrast ? \"white\" : \"black\";\r\n}\r\n\r\n/**\r\n * Retorna `true` se o contraste entre texto/bg passa WCAG AA pra texto\r\n * normal (4.5:1) ou texto large (3:1).\r\n *\r\n * Útil pra validação em desenvolvimento (avisar quando alguém configurou\r\n * `colorHex` com contraste insuficiente mesmo após auto-pick).\r\n *\r\n * @param textColor - hex do texto\r\n * @param bgColor - hex do bg\r\n * @param size - \"normal\" (4.5:1) | \"large\" (3:1, >=18pt ou >=14pt bold)\r\n */\r\nexport function meetsWCAG_AA(\r\n textColor: string,\r\n bgColor: string,\r\n size: \"normal\" | \"large\" = \"normal\",\r\n): boolean {\r\n const text = hexToRgb(textColor);\r\n const bg = hexToRgb(bgColor);\r\n if (!text || !bg) return false;\r\n const ratio = contrastRatio(relativeLuminance(text), relativeLuminance(bg));\r\n return ratio >= (size === \"large\" ? 3 : 4.5);\r\n}\r\n","import { createContext } from \"react\";\r\nimport type { AvatarSize, AvatarSurface } from \"./avatar.types\";\r\n\r\n/**\r\n * Contexto do `AvatarGroup` — é assim que o `size` chega nos filhos.\r\n *\r\n * ## Por que num arquivo só dele\r\n *\r\n * Evita ciclo de import: o `AvatarGroup` precisa do `Avatar` (renderiza o `+N`) e o `Avatar`\r\n * precisa do contexto (lê o `size`). Com o contexto dentro do `avatar-group.tsx`, os dois\r\n * módulos se importariam mutuamente — funciona em ESM na maioria dos casos, mas depende da\r\n * ordem de avaliação e alguns bundlers avisam. Arquivo próprio corta a dependência.\r\n *\r\n * ## Por que contexto e não `cloneElement`\r\n *\r\n * Mesmo mecanismo do `ChipGroup`, do `KpiGroup` e do `CardOptionGroup`. Clonar filhos quebra\r\n * quando eles vêm de um `map`, de um fragmento ou de um wrapper — que é exatamente como uma\r\n * lista de responsáveis costuma ser montada.\r\n *\r\n * `undefined` = sem grupo em volta, e aí o `Avatar` mantém o default dele (`md`).\r\n */\r\nexport const AvatarGroupContext = createContext<\r\n { size?: AvatarSize; surface: AvatarSurface } | undefined\r\n>(undefined);\r\n","import { tv, type VariantProps } from \"@/utils/tv\";\r\n\r\n/**\r\n * Avatar styles — iGreen DS\r\n *\r\n * Circular badge with initials. No interactive states (no hover, no focus, no disabled).\r\n *\r\n * Size uses `size-comp-*` tokens (square: width = height):\r\n * xs = 20px (comp-2xs) | sm = 24px (comp-xs) | md = 28px (comp-sm)\r\n * lg = 32px (comp-md) | xl = 40px (comp-xl)\r\n *\r\n * Color applies bg + fg pairs from semantic tokens.\r\n * `_custom` is an internal-only variant used when `colorHex` overrides the\r\n * background via inline style — it intentionally applies no bg/fg so the\r\n * component can set them manually.\r\n *\r\n * Typography scales with size to keep initials proportional inside the circle.\r\n */\r\nexport const avatarVariants = tv({\r\n base: [\r\n \"inline-flex items-center justify-center\",\r\n \"shrink-0\",\r\n \"rounded-radius-full\",\r\n \"overflow-hidden\",\r\n \"leading-none\",\r\n \"font-bold\",\r\n \"select-none\",\r\n ],\r\n\r\n variants: {\r\n size: {\r\n xs: \"size-comp-2xs text-caption-sm\", // 20px / 11px\r\n sm: \"size-comp-xs text-caption-sm\", // 24px / 11px\r\n md: \"size-comp-sm text-caption-sm\", // 28px / 11px — default\r\n lg: \"size-comp-md text-body-sm font-normal\", // 32px / 13px\r\n xl: \"size-comp-xl text-body-md font-medium\", // 40px / 14px\r\n },\r\n\r\n color: {\r\n brand: \"bg-bg-brand text-fg-on-brand\",\r\n success: \"bg-bg-success text-fg-on-success\",\r\n warning: \"bg-bg-warning text-fg-on-warning\",\r\n critical: \"bg-bg-danger text-fg-on-danger\",\r\n info: \"bg-bg-info text-fg-on-info\",\r\n muted: \"bg-bg-muted text-fg-muted\",\r\n /** Internal: used by colorHex override — no bg/fg applied. */\r\n _custom: \"\",\r\n },\r\n },\r\n\r\n defaultVariants: {\r\n size: \"md\",\r\n color: \"muted\",\r\n },\r\n});\r\n\r\nexport type AvatarVariantProps = VariantProps<typeof avatarVariants>;\r\n\r\n/**\r\n * Item da pilha do `AvatarGroup` — o wrapper que sobrepõe e desenha o anel de separação.\r\n *\r\n * ## Por que o anel mora AQUI e não no `Avatar`\r\n *\r\n * `ring` acompanha o `border-radius` do elemento em que está. Num wrapper quadrado ele\r\n * traçaria um quadrado em volta do círculo — daí o `rounded-radius-full` no próprio wrapper.\r\n * E ficar no wrapper (e não no `Avatar`) mantém o `Avatar` solto sem anel nenhum: o anel só\r\n * existe porque há sobreposição.\r\n *\r\n * ## A sobreposição escala com o tamanho\r\n *\r\n * Não é constante: 6px num avatar de 20px é **30%** de sobreposição, e no de 40px é **15%** —\r\n * visualmente são arranjos diferentes. O mapa abaixo mantém ~25% em toda a escala, e cada\r\n * valor é token de spacing (`sp-*`), não px na unha.\r\n *\r\n * ## O `surface` existe porque o anel é da cor do que está ATRÁS\r\n *\r\n * `ring-bg-surface` num painel funciona; na linha de uma tabela (`bg-bg-table`) apareceria um\r\n * halo claro em volta de cada avatar. Quem sabe o que está atrás é quem compõe — daí ser prop.\r\n */\r\n/**\r\n * Container da pilha. É um `tv()` de uma linha só de propósito: sem ele o `className` do\r\n * consumidor entraria por concatenação crua, e `items-start` não venceria o `items-center`\r\n * daqui (é o `twMerge` embutido no `tv` que resolve conflito de classe). Também mantém o\r\n * `avatar-ig` dependendo só de `@igreen/tv` — usar o `cn` de `@/lib/utils` acrescentaria uma\r\n * `registryDependency` ao item por causa de duas classes.\r\n */\r\nexport const avatarGroupRoot = tv({ base: \"flex items-center\" });\r\n\r\nexport const avatarGroupItem = tv({\r\n base: [\"relative inline-flex rounded-radius-full ring-2\"],\r\n\r\n variants: {\r\n /** Deslocamento negativo ≈ 25% do diâmetro, em token. Ver o bloco acima. */\r\n size: {\r\n xs: \"-ml-sp-xs\", // 20px → 4\r\n sm: \"-ml-sp-sm\", // 24px → 6\r\n md: \"-ml-sp-sm\", // 28px → 6\r\n lg: \"-ml-sp-md\", // 32px → 8\r\n xl: \"-ml-sp-lg\", // 40px → 10\r\n },\r\n\r\n /** Cor do anel = superfície de trás. */\r\n surface: {\r\n surface: \"ring-bg-surface\",\r\n canvas: \"ring-bg-canvas\",\r\n subtle: \"ring-bg-subtle\",\r\n muted: \"ring-bg-muted\",\r\n table: \"ring-bg-table\",\r\n },\r\n\r\n /** O primeiro não desloca — senão a pilha inteira sai da margem esquerda. */\r\n primeiro: { true: \"ml-0\" },\r\n },\r\n\r\n defaultVariants: {\r\n size: \"md\",\r\n surface: \"surface\",\r\n },\r\n});\r\n","import { forwardRef, useContext, useState } from \"react\";\r\nimport { getContrastTextColor } from \"@/utils/color-contrast\";\r\nimport { AvatarGroupContext } from \"./avatar-group-context\";\r\nimport { avatarVariants } from \"./avatar.styles\";\r\nimport type { AvatarProps } from \"./avatar.types\";\r\n\r\n/**\r\n * Avatar — circular badge with initials.\r\n *\r\n * Supports semantic `color` presets (brand, success, warning, critical, info, muted)\r\n * and a `colorHex` override for person-specific hex colors.\r\n *\r\n * Auto contrast (v0.7.1, L-027): quando `colorHex` é fornecido, calcula o\r\n * contraste WCAG entre branco/preto e o bg, escolhendo a cor de texto com\r\n * MAIOR ratio. Antes aplicava `text-white` cego — quebrava em cores claras\r\n * (ex: BB amarelo #FAE128 → ratio 1.29:1, falha WCAG AA). Agora respeita\r\n * o threshold dinâmico baseado em luminância (Y > 0.5 → preto, else branco).\r\n *\r\n * Override: pra forçar uma cor específica (caso de marca que exige X), passe\r\n * `className` com classe Tailwind `text-X` — ela sobrescreve a auto-pickada\r\n * pela ordem de cascade.\r\n *\r\n * Foto (v0.53.0): passe `src` e mantenha as iniciais em `children` — elas são o\r\n * **fallback** quando a URL falha. A imagem interna é `alt=\"\"`; o nome da pessoa mora no\r\n * `aria-label` do avatar, pra não ser anunciado duas vezes.\r\n *\r\n * ⚠️ Quando usar o `Avatar` compound do shadcn (`avatar`, com `AvatarImage`/`AvatarFallback`)\r\n * em vez deste: quando o fallback não é iniciais (ícone, skeleton) ou você precisa controlar\r\n * o estado de carregamento. Pra foto de pessoa dentro do DS — e sempre dentro de\r\n * `AvatarGroup`, que propaga `size` por contexto — o certo é este.\r\n *\r\n * Accessibility:\r\n * - With `aria-label` → role=\"img\" (semantic avatar)\r\n * - Without `aria-label` → aria-hidden=\"true\" (decorative, inside a card/cell)\r\n */\r\nexport const Avatar = forwardRef<HTMLDivElement, AvatarProps>(\r\n function Avatar(\r\n {\r\n size,\r\n color,\r\n colorHex,\r\n src,\r\n children,\r\n className,\r\n style,\r\n \"aria-label\": ariaLabel,\r\n ...rest\r\n },\r\n ref,\r\n ) {\r\n /**\r\n * Dentro de um `<AvatarGroup>`, o tamanho vem do grupo — mas o `size` passado aqui\r\n * VENCE. É escape hatch: sem ele não haveria como destacar um avatar do conjunto.\r\n * Fora do grupo o contexto é `undefined` e nada muda (o default `md` do tv() vale).\r\n */\r\n const grupo = useContext(AvatarGroupContext);\r\n const sizeEfetivo = size ?? grupo?.size;\r\n\r\n /**\r\n * Foto que falha volta pras iniciais — e é por isso que o estado existe: `onError` do\r\n * `<img>` não desmonta nada sozinho, ele só avisa. Sem o fallback, URL quebrada deixa\r\n * um buraco na pilha (o alt de uma imagem quebrada não se parece com um avatar).\r\n *\r\n * O estado guarda QUAL url falhou, não um booleano: com booleano, trocar a `src` por\r\n * uma boa manteria o avatar em modo iniciais pro resto da vida do componente (o React\r\n * reusa a instância) — e daria pra \"consertar\" isso só com um `useEffect` de reset,\r\n * que é uma renderização a mais pra guardar a mesma informação.\r\n */\r\n const [urlQueFalhou, setUrlQueFalhou] = useState<string | null>(null);\r\n const mostraFoto = typeof src === \"string\" && src !== \"\" && urlQueFalhou !== src;\r\n\r\n const isHex = typeof colorHex === \"string\" && colorHex.startsWith(\"#\");\r\n\r\n // Cor de texto auto-calculada quando hex é fornecido — sempre o maior\r\n // contraste WCAG entre white/black. Fallback \"white\" pra hex inválido\r\n // (preserva comportamento legado).\r\n const autoTextClass = isHex\r\n ? getContrastTextColor(colorHex) === \"black\"\r\n ? \"text-black\"\r\n : \"text-white\"\r\n : null;\r\n\r\n const computedClassName = avatarVariants({\r\n size: sizeEfetivo,\r\n color: isHex ? \"_custom\" : color,\r\n className: isHex\r\n ? [autoTextClass, className].filter(Boolean).join(\" \")\r\n : className,\r\n });\r\n\r\n const computedStyle = isHex\r\n ? { ...style, backgroundColor: colorHex }\r\n : style;\r\n\r\n return (\r\n <div\r\n ref={ref}\r\n className={computedClassName}\r\n style={computedStyle}\r\n {...(ariaLabel\r\n ? { role: \"img\", \"aria-label\": ariaLabel }\r\n : { \"aria-hidden\": true as const })}\r\n {...rest}\r\n >\r\n {mostraFoto ? (\r\n <img\r\n src={src}\r\n /* `alt=\"\"`: o nome da pessoa está no `aria-label` do avatar. Repetir aqui faria\r\n o leitor de tela anunciar duas vezes. */\r\n alt=\"\"\r\n className=\"size-full object-cover\"\r\n draggable={false}\r\n onError={() => setUrlQueFalhou(src ?? null)}\r\n />\r\n ) : (\r\n children\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\n\r\nAvatar.displayName = \"Avatar\";\r\n","import { Children, forwardRef, isValidElement } from \"react\";\r\nimport { Avatar } from \"./avatar\";\r\nimport { AvatarGroupContext } from \"./avatar-group-context\";\r\nimport { avatarGroupItem, avatarGroupRoot } from \"./avatar.styles\";\r\nimport type { AvatarGroupProps } from \"./avatar.types\";\r\n\r\n/**\r\n * `AvatarGroup` — pilha de avatares sobrepostos, com `size` propagado e excedente resumido.\r\n *\r\n * ## Por que existe\r\n *\r\n * A pilha era feita na mão em cada tela (`-ml-…` + `ring` escolhidos no olho), e três coisas\r\n * saíam diferentes toda vez: quanto sobrepor, qual cor de anel, e o que fazer quando são 12\r\n * pessoas. As três viram decisão do componente aqui.\r\n *\r\n * ## As quatro decisões, e por quê\r\n *\r\n * **1. A sobreposição escala com o tamanho.** Não é constante: 6px num avatar de 20px é 30% de\r\n * sobreposição, e no de 40px é 15% — visualmente são arranjos diferentes. O mapa em\r\n * `avatar.styles.ts` mantém ~25% em toda a escala.\r\n *\r\n * **2. O anel é da cor da SUPERFÍCIE DE TRÁS**, e é aqui que se erra. O anel separa um avatar\r\n * do outro pintando o que está atrás; com o token errado ele deixa de separar e vira um halo.\r\n * Por isso `surface` é **prop**, não constante.\r\n *\r\n * ⚠️ `table` e `surface` resolvem pro MESMO valor hoje (medido: `oklch(1 0 0)` no claro,\r\n * `oklch(0.225 0 0)` no escuro). Dentro de tabela a escolha é **semântica**, não visual —\r\n * declare `table` assim mesmo, pra a pilha seguir certa se um dia divergirem. Onde a diferença\r\n * é visível hoje é em `canvas`, `subtle` e `muted`.\r\n *\r\n * **3. O primeiro fica por cima.** O empilhamento natural do DOM põe o último por cima; aqui o\r\n * z-index é decrescente, porque a leitura é da esquerda pra direita e o primeiro avatar é o\r\n * principal. É a convenção de Material e Ant, e é o que faz a pilha parecer uma fila.\r\n *\r\n * **4. O grupo fala, os avatares calam.** Três avatares soltos fazem o leitor de tela ler três\r\n * nomes sem dizer que são um conjunto. O container leva `role=\"group\"` + `aria-label`, e o\r\n * `+N` é `aria-hidden` — o número já está no rótulo do grupo.\r\n *\r\n * ## Gotchas\r\n *\r\n * - **`size` no filho vence o do grupo.** É escape hatch pro caso de um avatar destacado; sem\r\n * ele, não haveria como quebrar a uniformidade quando o desenho pede.\r\n * - **`total` existe pra contagem do SERVIDOR.** Sem ele o `+N` conta só o que foi renderizado\r\n * — e uma lista paginada em 5 mostraria `+0` tendo 40 pessoas.\r\n * - **Não use pra 2 avatares sem sobreposição.** Aí é um `flex gap-gp-sm` comum: a pilha\r\n * comunica \"muitos, e o conjunto importa mais que cada um\".\r\n *\r\n * @example\r\n * <AvatarGroup size=\"sm\" max={3} total={12} aria-label=\"12 responsáveis\">\r\n * <Avatar colorHex=\"#2563EB\">MD</Avatar>\r\n * <Avatar colorHex=\"#CC092F\">AC</Avatar>\r\n * <Avatar colorHex=\"#7C3AED\">JS</Avatar>\r\n * <Avatar colorHex=\"#0891B2\">TK</Avatar>\r\n * </AvatarGroup>\r\n */\r\nexport const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(\r\n function AvatarGroup(\r\n {\r\n size = \"md\",\r\n max,\r\n total,\r\n surface = \"surface\",\r\n children,\r\n className,\r\n \"aria-label\": ariaLabel,\r\n ...rest\r\n },\r\n ref,\r\n ) {\r\n const itens = Children.toArray(children).filter(isValidElement);\r\n const visiveis = typeof max === \"number\" ? itens.slice(0, max) : itens;\r\n const escondidos = (total ?? itens.length) - visiveis.length;\r\n\r\n return (\r\n <AvatarGroupContext.Provider value={{ size, surface }}>\r\n <div\r\n ref={ref}\r\n className={avatarGroupRoot({ className })}\r\n role=\"group\"\r\n aria-label={ariaLabel}\r\n {...rest}\r\n >\r\n {visiveis.map((filho, i) => (\r\n <span\r\n key={i}\r\n /* z-index decrescente: o primeiro por cima (decisão 3). O wrapper existe pra\r\n não depender de o filho aceitar `style` — `Avatar` aceita, mas um consumidor\r\n pode passar outro elemento aqui. */\r\n className={avatarGroupItem({ size, surface, primeiro: i === 0 })}\r\n style={{ zIndex: visiveis.length - i }}\r\n >\r\n {filho}\r\n </span>\r\n ))}\r\n\r\n {escondidos > 0 && (\r\n /* O `+N` é `aria-hidden`: a contagem real já está no `aria-label` do grupo, e\r\n anunciar \"mais 9\" solto não diz de quê. */\r\n <span\r\n className={avatarGroupItem({ size, surface, primeiro: false })}\r\n style={{ zIndex: 0 }}\r\n >\r\n <Avatar size={size} color=\"muted\" aria-hidden>\r\n +{escondidos}\r\n </Avatar>\r\n </span>\r\n )}\r\n </div>\r\n </AvatarGroupContext.Provider>\r\n );\r\n },\r\n);\r\n\r\nAvatarGroup.displayName = \"AvatarGroup\";\r\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * ButtonGroup wrapper styles — agrupa visualmente os slots Primary + Chevron.\r\n *\r\n * Comportamento:\r\n * - inline-flex: 2 botões lado a lado\r\n * - radius: aplicado no group via slots (Primary herda left, Chevron herda right)\r\n * - divider: border interno emerge naturalmente do Button outline; pra filled/soft\r\n * usamos collapse via `-ml-px` no Chevron + ring divider via `before:` no slot\r\n *\r\n * Não tem variants próprias — color/variant/size vêm via ButtonGroupContext.\r\n * O wrapper só agrupa visualmente; aparência sai dos filhos.\r\n */\r\nexport const buttonGroupVariants = tv({\r\n base: [\r\n \"inline-flex items-stretch\",\r\n // Permite focus ring de cada filho aparecer (z-index relativo no slot focused).\r\n \"isolate\",\r\n ],\r\n});\r\n\r\n/**\r\n * Override de radius nos slots — neutraliza o radius da `size` do Button no\r\n * lado interno do group (entre Primary e Chevron) e mantém apenas no lado\r\n * externo (left do Primary, right do Chevron).\r\n *\r\n * Usa `!` pra sobrescrever a regra do Button (size define rounded-radius-X).\r\n */\r\nexport const buttonGroupSlot = tv({\r\n variants: {\r\n position: {\r\n // Primary: arredondado só na esquerda; direita reta pra \"encostar\" no chevron\r\n primary: \"!rounded-r-none\",\r\n // Chevron: arredondado só na direita; esquerda reta. -ml-px colapsa o border\r\n // duplicado entre os 2 botões (cada um tem border de 1px → vira 2px no meio).\r\n chevron: \"!rounded-l-none -ml-px\",\r\n },\r\n },\r\n});\r\n\r\n/**\r\n * Dimensões do Chevron por size — QUADRADO (width = height), alinhado com\r\n * a `size` correspondente do Button no Primary. Pad reduzido pro chevron\r\n * preencher o espaço sem ficar acanhado.\r\n *\r\n * Tabela de equivalência (size do Button → dimensão chevron):\r\n * 2xs (28px) → 28x28 (size-form-xs)\r\n * xs (32px) → 32x32 (size-form-sm)\r\n * sm (36px) → 36x36 (size-form-md)\r\n * md (40px) → 40x40 (size-form-lg)\r\n * lg (44px) → 44x44 (size-form-xl)\r\n *\r\n * Visual coeso: o chevron parece um \"espelho\" quadrado do Primary, não um\r\n * appendice estreito. Pattern Shadcn/Linear/Notion segue essa proporção.\r\n */\r\nexport const buttonGroupChevronSize = tv({\r\n variants: {\r\n size: {\r\n \"2xs\": \"size-form-xs px-0\",\r\n xs: \"size-form-sm px-0\",\r\n sm: \"size-form-md px-0\",\r\n md: \"size-form-lg px-0\",\r\n lg: \"size-form-xl px-0\",\r\n },\r\n },\r\n defaultVariants: {\r\n size: \"md\",\r\n },\r\n});\r\n","import { createContext, forwardRef, useContext } from \"react\";\r\nimport { ChevronDown } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Button } from \"@/components/ui/Button\";\r\nimport type { ButtonProps } from \"@/components/ui/Button/button.types\";\r\nimport {\r\n buttonGroupVariants,\r\n buttonGroupSlot,\r\n buttonGroupChevronSize,\r\n} from \"./button-group.styles\";\r\nimport type {\r\n ButtonGroupProps,\r\n ButtonGroupPrimaryProps,\r\n ButtonGroupChevronProps,\r\n ButtonGroupSharedProps,\r\n} from \"./button-group.types\";\r\n\r\n/**\r\n * Context interno — propaga color/variant/size/disabled do group pros slots\r\n * sem prop drilling. Filhos podem dar override passando essas props explicitamente.\r\n */\r\nconst ButtonGroupContext = createContext<ButtonGroupSharedProps | null>(null);\r\n\r\n/**\r\n * ButtonGroup — split button pattern.\r\n *\r\n * @example\r\n * ```tsx\r\n * <ButtonGroup color=\"primary\" variant=\"outline\" size=\"md\">\r\n * <ButtonGroup.Primary onClick={handleSimpleFilter} iconLeft={<Filter />}>\r\n * Filtrar\r\n * </ButtonGroup.Primary>\r\n * <ButtonGroup.Chevron\r\n * onClick={handleAdvancedOpen}\r\n * aria-label=\"Filtros avançados\"\r\n * />\r\n * </ButtonGroup>\r\n * ```\r\n *\r\n * Props color/variant/size propagam aos slots via context. Cada slot pode\r\n * dar override passando essas props explicitamente.\r\n */\r\nconst ButtonGroupRoot = forwardRef<HTMLDivElement, ButtonGroupProps>(\r\n function ButtonGroupRoot(\r\n { color, variant, size, disabled, children, className },\r\n ref,\r\n ) {\r\n return (\r\n <ButtonGroupContext.Provider value={{ color, variant, size, disabled }}>\r\n <div\r\n ref={ref}\r\n role=\"group\"\r\n className={cn(buttonGroupVariants(), className)}\r\n >\r\n {children}\r\n </div>\r\n </ButtonGroupContext.Provider>\r\n );\r\n },\r\n);\r\n\r\n/**\r\n * Slot Primary — botão da ação principal. Aceita todas as props do Button.\r\n * Color/variant/size vêm do ButtonGroup pai por default; override permitido.\r\n */\r\nconst ButtonGroupPrimary = forwardRef<HTMLButtonElement, ButtonGroupPrimaryProps>(\r\n function ButtonGroupPrimary({ className, ...props }, ref) {\r\n const ctx = useContext(ButtonGroupContext);\r\n const merged = mergeWithContext(ctx, props);\r\n return (\r\n <Button\r\n ref={ref}\r\n {...merged}\r\n className={cn(buttonGroupSlot({ position: \"primary\" }), className)}\r\n />\r\n );\r\n },\r\n);\r\n\r\n/**\r\n * Slot Chevron — icon button compacto com chevron-down default.\r\n * Mais estreito que um icon button size-* normal (pra parecer um \"split\" do primary).\r\n * `aria-label` obrigatório (icon-only requer descrição pra leitor de tela).\r\n */\r\nconst ButtonGroupChevron = forwardRef<HTMLButtonElement, ButtonGroupChevronProps>(\r\n function ButtonGroupChevron({ icon, className, ...props }, ref) {\r\n const ctx = useContext(ButtonGroupContext);\r\n // Não passa `size` (icon button) pro Button — usamos size com label vazio e\r\n // override de width via buttonGroupChevronSize pra fazer o chevron mais estreito.\r\n const merged = mergeWithContext(ctx, props);\r\n const effectiveSize = (merged.size ?? \"md\") as NonNullable<ButtonProps[\"size\"]>;\r\n return (\r\n <Button\r\n ref={ref}\r\n {...merged}\r\n // Override pad/width sem tocar height — alinha com primary mas estreito.\r\n className={cn(\r\n buttonGroupSlot({ position: \"chevron\" }),\r\n buttonGroupChevronSize({ size: effectiveSize as \"2xs\" | \"xs\" | \"sm\" | \"md\" | \"lg\" }),\r\n // Anula gap do Button (não tem children) + reset svg size pra default 14px\r\n \"!px-0\",\r\n className,\r\n )}\r\n >\r\n {icon ?? <ChevronDown />}\r\n </Button>\r\n );\r\n },\r\n);\r\n\r\n/**\r\n * Merge defensivo das props do slot com o context do group.\r\n * Slot pode dar OVERRIDE — se passou color/variant/size explicitamente, ganha do context.\r\n */\r\nfunction mergeWithContext<T extends ButtonGroupSharedProps>(\r\n ctx: ButtonGroupSharedProps | null,\r\n props: T,\r\n): T {\r\n if (!ctx) return props;\r\n return {\r\n ...props,\r\n color: props.color ?? ctx.color,\r\n variant: props.variant ?? ctx.variant,\r\n size: props.size ?? ctx.size,\r\n disabled: props.disabled ?? ctx.disabled,\r\n };\r\n}\r\n\r\n/**\r\n * Export como compound component — `<ButtonGroup>` é a raiz, e os slots\r\n * `<ButtonGroup.Primary>` / `<ButtonGroup.Chevron>` são namespaced.\r\n */\r\nexport const ButtonGroup = Object.assign(ButtonGroupRoot, {\r\n Primary: ButtonGroupPrimary,\r\n Chevron: ButtonGroupChevron,\r\n});\r\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * Form field styles — alinhado com `.tbl-form-field` do sandbox.\r\n *\r\n * Spec: flex column gap 7px (label / field / message).\r\n */\r\nexport const formFieldRoot = tv({\r\n base: \"flex flex-col gap-[7px] w-full\",\r\n});\r\n\r\nexport const formFieldLabel = tv({\r\n base: [\r\n \"text-body-sm font-semibold tracking-[0.01em] leading-none\",\r\n \"text-fg-default dark:text-fg-muted\",\r\n \"select-none\",\r\n ],\r\n variants: {\r\n disabled: {\r\n true: \"opacity-50 cursor-not-allowed\",\r\n },\r\n },\r\n});\r\n\r\nexport const formFieldRequired = tv({\r\n base: \"ml-[2px] text-fg-danger\",\r\n});\r\n\r\nexport const formFieldMessage = tv({\r\n base: \"text-caption-sm leading-snug\",\r\n variants: {\r\n state: {\r\n default: \"text-fg-muted\",\r\n error: \"text-fg-danger\",\r\n warning: \"text-fg-warning\",\r\n success: \"text-fg-success\",\r\n },\r\n },\r\n defaultVariants: { state: \"default\" },\r\n});\r\n","import { useId } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport {\n formFieldRoot,\n formFieldLabel,\n formFieldRequired,\n formFieldMessage,\n} from \"./form-field.styles\";\nimport type { FormFieldBaseProps, FieldState } from \"./form-field.types\";\n\nexport type FormFieldProps = FormFieldBaseProps & {\n /** O field em si (Input, Select, Textarea, Checkbox, Switch, etc) — recebe id automático */\n children: (ctx: { id: string; state: FieldState }) => ReactNode;\n /** Hide quando o field é \"self-contained\" (ex: Checkbox com label inline) */\n hideLabel?: boolean;\n /** Marcar field como disabled (afeta cor do label) */\n disabled?: boolean;\n};\n\n/**\n * FormField — base wrapper compartilhado por FormFieldInput, FormFieldSelect, etc.\n *\n * Estrutura:\n * [Label + required asterisk] (top)\n * [Field (passado via children render-prop)]\n * [Helper text OR error/warning/success message] (bottom)\n *\n * Mensagem é decidida pela prioridade: error → warning → success → helperText.\n * O `id` gerado é passado ao child via render-prop pra linkar `htmlFor` no label.\n */\nexport function FormField({\n label,\n required,\n helperText,\n state = \"default\",\n errorMessage,\n warningMessage,\n successMessage,\n className,\n id: idProp,\n children,\n hideLabel,\n disabled,\n}: FormFieldProps) {\n const autoId = useId();\n const id = idProp ?? autoId;\n\n // Priority: error → warning → success → helper\n let message: ReactNode = helperText;\n let messageState: FieldState = \"default\";\n if (state === \"error\" && errorMessage) {\n message = errorMessage;\n messageState = \"error\";\n } else if (state === \"warning\" && warningMessage) {\n message = warningMessage;\n messageState = \"warning\";\n } else if (state === \"success\" && successMessage) {\n message = successMessage;\n messageState = \"success\";\n }\n\n return (\n <div className={cn(formFieldRoot(), className)}>\n {label && !hideLabel && (\n <label\n htmlFor={id}\n className={formFieldLabel({ disabled })}\n >\n {label}\n {required && <span className={formFieldRequired()} aria-hidden=\"true\">*</span>}\n </label>\n )}\n {children({ id, state })}\n {message && (\n <p\n className={formFieldMessage({ state: messageState })}\n role={messageState === \"error\" ? \"alert\" : undefined}\n >\n {message}\n </p>\n )}\n </div>\n );\n}\n","import { forwardRef, type ReactNode } from \"react\";\r\nimport { Input, type InputProps } from \"@/components/shadcn/input\";\r\nimport {\r\n InputGroup,\r\n InputGroupAddon,\r\n InputGroupInput,\r\n InputGroupText,\r\n} from \"@/components/shadcn/input-group\";\r\nimport { FormField } from \"./form-field\";\r\nimport type { FormFieldBaseProps } from \"./form-field.types\";\r\n\r\n/**\r\n * FormFieldInput — wrapper \"one-shot\" pra um campo de texto.\r\n *\r\n * Renderização condicional:\r\n * - sem addon → renderiza <Input> puro\r\n * - com `startAddon` ou `endAddon` → renderiza <InputGroup> com InputGroupInput\r\n *\r\n * Os addons aceitam string (renderiza como InputGroupText, ex \"R$\") ou ReactNode\r\n * (ícone, botão — passa direto). Não há mais startIcon vs startAdornment: o\r\n * InputGroup trata ambos via composição.\r\n */\r\nexport type FormFieldInputProps = FormFieldBaseProps &\r\n Omit<InputProps, \"state\" | \"id\"> & {\r\n /** Conteúdo à esquerda. String vira `<InputGroupText>`, ReactNode (ícone/botão) passa direto. */\r\n startAddon?: ReactNode;\r\n /** Conteúdo à direita. Mesma regra do startAddon. */\r\n endAddon?: ReactNode;\r\n };\r\n\r\nfunction renderAddon(content: ReactNode, key: string): ReactNode {\r\n if (typeof content === \"string\") {\r\n return (\r\n <InputGroupAddon key={key} align={key === \"start\" ? \"inline-start\" : \"inline-end\"}>\r\n <InputGroupText>{content}</InputGroupText>\r\n </InputGroupAddon>\r\n );\r\n }\r\n return (\r\n <InputGroupAddon key={key} align={key === \"start\" ? \"inline-start\" : \"inline-end\"}>\r\n {content}\r\n </InputGroupAddon>\r\n );\r\n}\r\n\r\nexport const FormFieldInput = forwardRef<HTMLInputElement, FormFieldInputProps>(\r\n (\r\n {\r\n label,\r\n required,\r\n helperText,\r\n state,\r\n errorMessage,\r\n warningMessage,\r\n successMessage,\r\n className,\r\n id,\r\n startAddon,\r\n endAddon,\r\n ...inputProps\r\n },\r\n ref,\r\n ) => {\r\n const hasAddon = startAddon !== undefined || endAddon !== undefined;\r\n // Separa o `size` do CVA pra usar no wrapper — InputGroupInput recebe os\r\n // demais HTML attrs (sem o size, que no <input> nativo seria number).\r\n const { size, ...inputHtmlProps } = inputProps;\r\n\r\n return (\r\n <FormField\r\n label={label}\r\n required={required}\r\n helperText={helperText}\r\n state={state}\r\n errorMessage={errorMessage}\r\n warningMessage={warningMessage}\r\n successMessage={successMessage}\r\n className={className}\r\n id={id}\r\n disabled={inputProps.disabled}\r\n >\r\n {({ id: fieldId, state: fieldState }) =>\r\n hasAddon ? (\r\n <InputGroup state={fieldState} size={size ?? undefined}>\r\n {startAddon !== undefined && renderAddon(startAddon, \"start\")}\r\n <InputGroupInput ref={ref} id={fieldId} {...inputHtmlProps} />\r\n {endAddon !== undefined && renderAddon(endAddon, \"end\")}\r\n </InputGroup>\r\n ) : (\r\n <Input\r\n ref={ref}\r\n id={fieldId}\r\n state={fieldState}\r\n size={size}\r\n {...inputHtmlProps}\r\n />\r\n )\r\n }\r\n </FormField>\r\n );\r\n },\r\n);\r\nFormFieldInput.displayName = \"FormFieldInput\";\r\n","import { forwardRef } from \"react\";\r\nimport { Textarea, type TextareaProps } from \"@/components/shadcn/textarea\";\r\nimport { FormField } from \"./form-field\";\r\nimport type { FormFieldBaseProps } from \"./form-field.types\";\r\n\r\n/**\r\n * FormFieldTextarea — wrapper \"one-shot\" pra um campo multilinha.\r\n * Compõe FormField + Textarea (mesmo componente do shadcn/), sem reimplementação.\r\n */\r\nexport type FormFieldTextareaProps = FormFieldBaseProps &\r\n Omit<TextareaProps, \"state\" | \"id\">;\r\n\r\nexport const FormFieldTextarea = forwardRef<\r\n HTMLTextAreaElement,\r\n FormFieldTextareaProps\r\n>(\r\n (\r\n {\r\n label,\r\n required,\r\n helperText,\r\n state,\r\n errorMessage,\r\n warningMessage,\r\n successMessage,\r\n className,\r\n id,\r\n ...textareaProps\r\n },\r\n ref,\r\n ) => (\r\n <FormField\r\n label={label}\r\n required={required}\r\n helperText={helperText}\r\n state={state}\r\n errorMessage={errorMessage}\r\n warningMessage={warningMessage}\r\n successMessage={successMessage}\r\n className={className}\r\n id={id}\r\n disabled={textareaProps.disabled}\r\n >\r\n {({ id: fieldId, state: fieldState }) => (\r\n <Textarea\r\n ref={ref}\r\n id={fieldId}\r\n state={fieldState}\r\n {...textareaProps}\r\n />\r\n )}\r\n </FormField>\r\n ),\r\n);\r\nFormFieldTextarea.displayName = \"FormFieldTextarea\";\r\n","import { useRef, type ReactNode } from \"react\";\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n type SelectTriggerState,\r\n} from \"@/components/shadcn/select\";\r\nimport { FormField } from \"./form-field\";\r\nimport type { FormFieldBaseProps } from \"./form-field.types\";\r\n\r\n/**\r\n * Valor interno que substitui `\"\"` antes de chegar ao Radix. Ver o docblock do\r\n * componente: `\"\"` é a sentinela de \"nada selecionado\" do próprio Radix, e uma\r\n * opção com esse valor ou some da tela ou lança, dependendo da versão.\r\n *\r\n * Cifrões não aparecem em valor de domínio, e o prefixo `__ds` diz de onde vem\r\n * — colisão com valor real de consumidor exigiria má-fé.\r\n */\r\nconst SENTINELA_VAZIO = \"__ds_select_vazio__\";\r\n\r\nexport type FormFieldSelectOption = {\r\n value: string;\r\n label: ReactNode;\r\n disabled?: boolean;\r\n};\r\n\r\n/**\r\n * FormFieldSelect — wrapper \"one-shot\" pra um select dropdown.\r\n *\r\n * Compõe FormField + Select (radix) — reutiliza os Select* primitives existentes.\r\n *\r\n * Uso simples via `options`:\r\n * <FormFieldSelect label=\"País\" placeholder=\"Selecione...\" options={[\r\n * { value: \"br\", label: \"Brasil\" },\r\n * { value: \"us\", label: \"Estados Unidos\" },\r\n * ]} />\r\n *\r\n * Pra casos avançados (groups, separators), use o Select primitive direto.\r\n */\r\nexport type FormFieldSelectProps = FormFieldBaseProps & {\r\n options: FormFieldSelectOption[];\r\n placeholder?: string;\r\n value?: string;\r\n defaultValue?: string;\r\n onValueChange?: (value: string) => void;\r\n disabled?: boolean;\r\n /** className aplicado ao <SelectTrigger>. Pra estilizar o wrapper, use `className` (vai pro FormField root). */\r\n triggerClassName?: string;\r\n /** Largura/maxHeight customizada do dropdown */\r\n contentClassName?: string;\r\n};\r\n\r\nexport function FormFieldSelect({\r\n label,\r\n required,\r\n helperText,\r\n state,\r\n errorMessage,\r\n warningMessage,\r\n successMessage,\r\n className,\r\n id,\r\n options,\r\n placeholder,\r\n value,\r\n defaultValue,\r\n onValueChange,\r\n disabled,\r\n triggerClassName,\r\n contentClassName,\r\n}: FormFieldSelectProps) {\r\n /**\r\n * Duas armadilhas do Radix Select, e as duas apagam dado em silêncio.\r\n *\r\n * ── 1. `\"\"` é a SENTINELA de \"nada selecionado\" ───────────────────────────\r\n *\r\n * `shouldShowPlaceholder(value) { return value === \"\" || value === void 0 }`.\r\n * Consumidor que oferece uma opção \"nenhum\" com `value: \"\"` — o idioma óbvio,\r\n * e o que este componente sempre convidou a escrever — colide com ela:\r\n *\r\n * - o rótulo da opção NUNCA aparece: com `value=\"\"` o gatilho mostra o\r\n * placeholder, então \"Sem fila padrão\" fica invisível e o campo parece\r\n * vazio mesmo estando preenchido;\r\n * - no Radix 2.2.6 o `<SelectItem value=\"\">` LANÇA (\"must have a value prop\r\n * that is not an empty string\"). No 2.3.1 esse erro foi REMOVIDO e o\r\n * comportamento virou silencioso — o mesmo código quebra alto numa versão\r\n * e erra baixo na outra.\r\n *\r\n * A sentinela abaixo mantém a API pública intacta (`value: \"\"` continua\r\n * sendo o jeito de dizer \"nenhum\") e o vazio nunca chega ao Radix.\r\n *\r\n * ── 2. O valor controlado é ECOADO de volta, e o eco pode vir vazio ───────\r\n *\r\n * O `SelectBubbleInput` guarda um `<select>` nativo escondido para integração\r\n * com formulário. Quando o `value` muda, ele ecoa num efeito:\r\n *\r\n * setValue.call(select, selectValue); // select.value = \"24\"\r\n * select.dispatchEvent(new Event(\"change\")); // change de verdade\r\n *\r\n * com `onChange: (e) => onValueChange(e.target.value)`.\r\n *\r\n * O DOM recusa atribuir a um `<select>` um valor sem `<option>`\r\n * correspondente — o campo fica em `\"\"`. O eco então chega ao consumidor como\r\n * `onValueChange(\"\")`, indistinguível de uma escolha. Quem controla o campo\r\n * por formulário grava esse vazio e o valor some sozinho.\r\n *\r\n * Acontece sempre que as OPÇÕES chegam depois do VALOR: lista assíncrona, ou\r\n * opções derivadas do próprio estado do formulário. Medido no Hub em\r\n * 20/08/2026 — a tela de Conexões parou de salvar, a validação reprovava por\r\n * um campo que ninguém esvaziou, e 19 horas de log não tiveram um PUT.\r\n *\r\n * A guarda é estreita: só engole o vazio quando ele NÃO pode ter vindo de\r\n * quem usa (dropdown fechado) e o valor atual é órfão. Escolha real acontece\r\n * com o dropdown aberto e passa direto.\r\n */\r\n const abertoRef = useRef(false);\r\n\r\n const valorEhOrfao =\r\n value !== undefined &&\r\n value !== \"\" &&\r\n !options.some((opt) => opt.value === value);\r\n\r\n const paraRadix = (v: string | undefined) =>\r\n v === \"\" ? SENTINELA_VAZIO : v;\r\n\r\n const aoMudarValor = (proximo: string) => {\r\n if (proximo === \"\" && valorEhOrfao && !abertoRef.current) return;\r\n onValueChange?.(proximo === SENTINELA_VAZIO ? \"\" : proximo);\r\n };\r\n\r\n return (\r\n <FormField\r\n label={label}\r\n required={required}\r\n helperText={helperText}\r\n state={state}\r\n errorMessage={errorMessage}\r\n warningMessage={warningMessage}\r\n successMessage={successMessage}\r\n className={className}\r\n id={id}\r\n disabled={disabled}\r\n >\r\n {({ id: fieldId, state: fieldState }) => (\r\n <Select\r\n value={paraRadix(value)}\r\n defaultValue={paraRadix(defaultValue)}\r\n onValueChange={aoMudarValor}\r\n onOpenChange={(aberto) => {\r\n abertoRef.current = aberto;\r\n }}\r\n disabled={disabled}\r\n >\r\n <SelectTrigger\r\n id={fieldId}\r\n state={fieldState as SelectTriggerState}\r\n className={triggerClassName}\r\n >\r\n <SelectValue placeholder={placeholder} />\r\n </SelectTrigger>\r\n <SelectContent className={contentClassName}>\r\n {options.map((opt) => (\r\n <SelectItem\r\n key={opt.value}\r\n value={paraRadix(opt.value) as string}\r\n disabled={opt.disabled}\r\n >\r\n {opt.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n )}\r\n </FormField>\r\n );\r\n}\r\n","import { forwardRef, useId, type ReactNode } from \"react\";\r\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\r\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\r\nimport { Checkbox } from \"@/components/shadcn/checkbox\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport {\r\n formFieldRoot,\r\n formFieldLabel,\r\n formFieldRequired,\r\n formFieldMessage,\r\n} from \"./form-field.styles\";\r\nimport type { FormFieldBaseProps, FieldState } from \"./form-field.types\";\r\n\r\n/**\r\n * FormFieldCheckbox — wrapper \"one-shot\" pra checkbox com label inline.\r\n *\r\n * Layout (diferente de FormFieldInput/Select):\r\n * ┌──────────────────────────────────────┐\r\n * │ [☑] Label texto │\r\n * │ Helper / error message │\r\n * └──────────────────────────────────────┘\r\n *\r\n * Reaproveita o Checkbox do shadcn. O label fica à direita (não em cima).\r\n */\r\nexport type FormFieldCheckboxProps = Omit<FormFieldBaseProps, \"label\"> & {\r\n /** Texto do label (inline à direita do checkbox) */\r\n label?: ReactNode;\r\n /** Props nativas do Radix Checkbox.Root */\r\n} & Omit<\r\n ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,\r\n \"id\" | \"className\"\r\n >;\r\n\r\nexport const FormFieldCheckbox = forwardRef<\r\n ElementRef<typeof CheckboxPrimitive.Root>,\r\n FormFieldCheckboxProps\r\n>(\r\n (\r\n {\r\n label,\r\n required,\r\n helperText,\r\n state = \"default\",\r\n errorMessage,\r\n warningMessage,\r\n successMessage,\r\n className,\r\n id: idProp,\r\n disabled,\r\n ...checkboxProps\r\n },\r\n ref,\r\n ) => {\r\n const autoId = useId();\r\n const id = idProp ?? autoId;\r\n\r\n let message: ReactNode = helperText;\r\n let messageState: FieldState = \"default\";\r\n if (state === \"error\" && errorMessage) {\r\n message = errorMessage;\r\n messageState = \"error\";\r\n } else if (state === \"warning\" && warningMessage) {\r\n message = warningMessage;\r\n messageState = \"warning\";\r\n } else if (state === \"success\" && successMessage) {\r\n message = successMessage;\r\n messageState = \"success\";\r\n }\r\n\r\n return (\r\n <div className={cn(formFieldRoot(), \"gap-[5px]\", className)}>\r\n <div className=\"flex items-center gap-gp-md\">\r\n <Checkbox\r\n ref={ref}\r\n id={id}\r\n disabled={disabled}\r\n {...checkboxProps}\r\n />\r\n {label && (\r\n <label\r\n htmlFor={id}\r\n className={cn(formFieldLabel({ disabled }), \"cursor-pointer\")}\r\n >\r\n {label}\r\n {required && (\r\n <span className={formFieldRequired()} aria-hidden=\"true\">\r\n *\r\n </span>\r\n )}\r\n </label>\r\n )}\r\n </div>\r\n {message && (\r\n <p\r\n className={cn(formFieldMessage({ state: messageState }), \"pl-[26px]\")}\r\n role={messageState === \"error\" ? \"alert\" : undefined}\r\n >\r\n {message}\r\n </p>\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\nFormFieldCheckbox.displayName = \"FormFieldCheckbox\";\r\n","import { forwardRef, useId, type ReactNode } from \"react\";\r\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\r\nimport * as SwitchPrimitive from \"@radix-ui/react-switch\";\r\nimport { Switch } from \"@/components/shadcn/switch\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport {\r\n formFieldRoot,\r\n formFieldLabel,\r\n formFieldRequired,\r\n formFieldMessage,\r\n} from \"./form-field.styles\";\r\nimport type { FormFieldBaseProps, FieldState } from \"./form-field.types\";\r\n\r\n/**\r\n * FormFieldSwitch — wrapper \"one-shot\" pra toggle switch com label inline.\r\n *\r\n * Layout: label à ESQUERDA, switch à DIREITA (padrão de toggle):\r\n * ┌──────────────────────────────────────┐\r\n * │ Label texto [○──] │\r\n * │ Helper / error message │\r\n * └──────────────────────────────────────┘\r\n *\r\n * Reaproveita o Switch do shadcn.\r\n */\r\nexport type FormFieldSwitchProps = Omit<FormFieldBaseProps, \"label\"> & {\r\n label?: ReactNode;\r\n /** Posição do switch — default \"end\" (direita). \"start\" coloca à esquerda do label. */\r\n switchPosition?: \"start\" | \"end\";\r\n} & Omit<\r\n ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>,\r\n \"id\" | \"className\"\r\n >;\r\n\r\nexport const FormFieldSwitch = forwardRef<\r\n ElementRef<typeof SwitchPrimitive.Root>,\r\n FormFieldSwitchProps\r\n>(\r\n (\r\n {\r\n label,\r\n required,\r\n helperText,\r\n state = \"default\",\r\n errorMessage,\r\n warningMessage,\r\n successMessage,\r\n className,\r\n id: idProp,\r\n disabled,\r\n switchPosition = \"end\",\r\n ...switchProps\r\n },\r\n ref,\r\n ) => {\r\n const autoId = useId();\r\n const id = idProp ?? autoId;\r\n\r\n let message: ReactNode = helperText;\r\n let messageState: FieldState = \"default\";\r\n if (state === \"error\" && errorMessage) {\r\n message = errorMessage;\r\n messageState = \"error\";\r\n } else if (state === \"warning\" && warningMessage) {\r\n message = warningMessage;\r\n messageState = \"warning\";\r\n } else if (state === \"success\" && successMessage) {\r\n message = successMessage;\r\n messageState = \"success\";\r\n }\r\n\r\n const switchEl = (\r\n <Switch ref={ref} id={id} disabled={disabled} {...switchProps} />\r\n );\r\n const labelEl = label && (\r\n <label\r\n htmlFor={id}\r\n className={cn(formFieldLabel({ disabled }), \"cursor-pointer flex-1\")}\r\n >\r\n {label}\r\n {required && (\r\n <span className={formFieldRequired()} aria-hidden=\"true\">\r\n *\r\n </span>\r\n )}\r\n </label>\r\n );\r\n\r\n return (\r\n <div className={cn(formFieldRoot(), \"gap-[5px]\", className)}>\r\n <div className=\"flex items-center gap-gp-md\">\r\n {switchPosition === \"start\" ? (\r\n <>\r\n {switchEl}\r\n {labelEl}\r\n </>\r\n ) : (\r\n <>\r\n {labelEl}\r\n {switchEl}\r\n </>\r\n )}\r\n </div>\r\n {message && (\r\n <p\r\n className={formFieldMessage({ state: messageState })}\r\n role={messageState === \"error\" ? \"alert\" : undefined}\r\n >\r\n {message}\r\n </p>\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\nFormFieldSwitch.displayName = \"FormFieldSwitch\";\r\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * Combobox — select de escolha única com busca (autocomplete) + lista rolável.\r\n *\r\n * O `trigger` espelha 1:1 o `SelectTrigger` do shadcn (mesma altura, borda,\r\n * radius, hover e foco) pra que um Combobox e um Select fiquem visualmente\r\n * idênticos lado a lado (ex.: os 3 campos do filter-popover: Campo/Operador/Valor).\r\n * A lista, o input de busca e os items são do `Command` (cmdk) — já tokenizados.\r\n *\r\n * Foco: padrão \"input\" do DS (mesmo do SelectTrigger) — `shadow-sh-ring` no\r\n * focus-visible e no `data-[state=open]`, NÃO `ring-4` (que é o padrão de botão).\r\n * Assim o anel de foco bate com os Selects irmãos.\r\n */\r\nexport const comboboxStyles = tv({\r\n slots: {\r\n trigger: [\r\n \"flex min-h-form-lg w-full items-center justify-between gap-gp-md\",\r\n \"rounded-radius-lg px-pad-xl\",\r\n \"bg-bg-input dark:bg-bg-muted\",\r\n \"hover:bg-bg-input-hover dark:hover:bg-bg-muted-hover\",\r\n \"border border-border-input\",\r\n \"text-body-sm font-normal text-fg-default text-left\",\r\n \"transition-[color,box-shadow,background-color,border-color]\",\r\n \"focus-visible:outline-none\",\r\n \"data-[placeholder]:text-fg-muted data-[placeholder]:opacity-70\",\r\n \"focus-visible:border-border-brand data-[state=open]:border-border-brand\",\r\n \"focus-visible:shadow-sh-ring data-[state=open]:shadow-sh-ring\",\r\n \"disabled:cursor-not-allowed disabled:opacity-50\",\r\n \"disabled:hover:bg-bg-input dark:disabled:hover:bg-bg-muted\",\r\n ],\r\n value: \"min-w-0 flex-1 truncate text-left\",\r\n icon: \"size-4 shrink-0 text-fg-muted\",\r\n // Dropdown alinhado à largura do trigger (mesmo pattern do Select via\r\n // `--radix-*-trigger-width`). `p-0`/overflow: o Command interno já provê o\r\n // padding e o scroll da lista.\r\n content: \"w-[var(--radix-popover-trigger-width)] overflow-hidden p-0\",\r\n // Item da lista: ocupa a largura e trunca rótulos longos.\r\n itemLabel: \"min-w-0 flex-1 truncate\",\r\n },\r\n});\r\n","import { forwardRef, useState } from \"react\";\r\nimport { Check, ChevronDown } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/shadcn/popover\";\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n} from \"@/components/shadcn/command\";\r\nimport { comboboxStyles } from \"./combobox.styles\";\r\nimport type { ComboboxProps } from \"./combobox.types\";\r\n\r\n/**\r\n * Combobox — select de escolha única com BUSCA (autocomplete) e lista ROLÁVEL.\r\n *\r\n * Compõe `Popover` + `Command` (cmdk): o trigger imita o `SelectTrigger` (parear\r\n * com Selects irmãos) e o dropdown traz `CommandInput` no topo + `CommandList`\r\n * com `max-h`/scroll. Use no lugar de um `Select` quando a lista é longa e o\r\n * usuário precisa digitar pra achar a opção (ex.: escolher uma coluna entre 30).\r\n *\r\n * Selação robusta: o `onSelect` do cmdk passa um valor normalizado, então o\r\n * componente NÃO depende dele — fecha via closure sobre `option.value`. A busca\r\n * casa por `label` + `keywords` (que inclui o `value` da opção).\r\n */\r\nexport const Combobox = forwardRef<HTMLButtonElement, ComboboxProps>(\r\n function Combobox(\r\n {\r\n options,\r\n value,\r\n onValueChange,\r\n placeholder = \"Selecione…\",\r\n searchPlaceholder = \"Buscar…\",\r\n emptyMessage = \"Nenhum resultado.\",\r\n open: openProp,\r\n defaultOpen,\r\n onOpenChange,\r\n align = \"start\",\r\n className,\r\n contentClassName,\r\n disabled,\r\n \"aria-label\": ariaLabel,\r\n ...rest\r\n },\r\n ref,\r\n ) {\r\n const [uncontrolledOpen, setUncontrolledOpen] = useState(\r\n defaultOpen ?? false,\r\n );\r\n const isControlled = openProp !== undefined;\r\n const open = isControlled ? openProp : uncontrolledOpen;\r\n const setOpen = (next: boolean) => {\r\n if (!isControlled) setUncontrolledOpen(next);\r\n onOpenChange?.(next);\r\n };\r\n\r\n const styles = comboboxStyles();\r\n const selected = options.find((o) => o.value === value);\r\n\r\n return (\r\n <Popover open={open} onOpenChange={setOpen}>\r\n <PopoverTrigger asChild>\r\n <button\r\n ref={ref}\r\n type=\"button\"\r\n role=\"combobox\"\r\n aria-expanded={open}\r\n aria-label={ariaLabel}\r\n disabled={disabled}\r\n data-placeholder={selected ? undefined : \"\"}\r\n className={styles.trigger({ className })}\r\n {...rest}\r\n >\r\n <span className={styles.value()}>\r\n {selected ? selected.label : placeholder}\r\n </span>\r\n <ChevronDown className={styles.icon()} aria-hidden=\"true\" />\r\n </button>\r\n </PopoverTrigger>\r\n <PopoverContent\r\n align={align}\r\n className={styles.content({ className: contentClassName })}\r\n >\r\n <Command>\r\n <CommandInput placeholder={searchPlaceholder} />\r\n <CommandList>\r\n <CommandEmpty>{emptyMessage}</CommandEmpty>\r\n <CommandGroup>\r\n {options.map((option) => {\r\n const isSelected = option.value === value;\r\n return (\r\n <CommandItem\r\n key={option.value}\r\n value={option.label}\r\n keywords={[option.value, ...(option.keywords ?? [])]}\r\n onSelect={() => {\r\n onValueChange?.(option.value);\r\n setOpen(false);\r\n }}\r\n className={cn(\r\n isSelected &&\r\n \"text-fg-default font-medium [&_svg]:text-fg-brand\",\r\n )}\r\n >\r\n <span className={styles.itemLabel()}>{option.label}</span>\r\n {isSelected && <Check aria-hidden=\"true\" />}\r\n </CommandItem>\r\n );\r\n })}\r\n </CommandGroup>\r\n </CommandList>\r\n </Command>\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n },\r\n);\r\nCombobox.displayName = \"Combobox\";\r\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * Table styles — slots tv pra Table, TableHead, TableHeadCell, TableBody, TableRow, TableCell.\r\n *\r\n * Densidade afeta: altura mínima de row + padding vertical de cell.\r\n * Modo card: aplicado via container query (@container) — root declara container-type.\r\n */\r\nexport const tableStyles = tv({\r\n slots: {\r\n /* Root grid container. Aplica container-type pra container queries.\r\n flex flex-col: scroll child usa flex-1 min-h-0 pra esticar quando há altura forçada\r\n (consumer aplica `max-h-[Npx]` no Table) ou pegar altura natural quando não há. */\r\n root: [\r\n \"relative flex flex-col w-full\",\r\n \"bg-bg-table border border-border-table rounded-radius-xl shadow-sh-sm\",\r\n \"overflow-hidden\",\r\n \"[container-type:inline-size]\",\r\n ],\r\n /* Container que faz o scroll (envolve head + body).\r\n flex-1 + min-h-0: estica até preencher o root quando há altura forçada;\r\n caso contrário, altura natural do conteúdo (flex-1 sem espaço extra = no-op).\r\n overflow-auto: scroll-X sempre disponível (colunas largas); scroll-Y só ativa\r\n quando o conteúdo excede a altura (que só acontece com max-h externo).\r\n scrollbar-thin: classe global do projeto (globals.css) — alpha responsivo light/dark. */\r\n scroll: [\r\n \"flex-1 min-h-0 overflow-auto relative\",\r\n \"scrollbar-thin\",\r\n ],\r\n /* Header row (flex de TableHeadCell). Sticky default. */\r\n head: [\r\n \"flex w-max min-w-full\",\r\n \"bg-bg-table-head border-b border-border-table\",\r\n \"z-20\",\r\n ],\r\n /* Cell do header — type, padding, alinhamento. */\r\n headCell: [\r\n \"relative flex items-center gap-gp-md shrink-0\",\r\n \"h-[42px] px-pad-2xl\",\r\n \"text-body-sm font-semibold leading-none\",\r\n \"text-fg-muted\",\r\n \"select-none\",\r\n \"hover:text-fg-default\",\r\n ],\r\n /* Body container — contém as rows. */\r\n body: [\r\n \"flex flex-col w-max min-w-full\",\r\n ],\r\n /* Row (flex de TableCell). */\r\n row: [\r\n \"group/row relative flex w-full\",\r\n \"border-b border-border-table last:border-b-0\",\r\n \"bg-bg-table\",\r\n \"transition-colors duration-150\",\r\n ],\r\n /* Cell — content cell padrão. */\r\n cell: [\r\n \"flex items-center shrink-0\",\r\n \"px-pad-2xl\",\r\n \"text-body-sm font-normal text-fg-default\",\r\n \"whitespace-nowrap overflow-hidden\",\r\n ],\r\n /* Drag handle do resize — barrinha invisível no edge direito.\r\n Apenas a linha dentro do header (after:). Sem projeção pra baixo (before:)\r\n porque pseudo-elements absolute COM h-screen ainda contam pro scrollHeight\r\n do ancestral com overflow-auto, esticando o body verticalmente. */\r\n resizeHandle: [\r\n \"absolute right-0 top-0 bottom-0 w-[6px] cursor-col-resize z-10\",\r\n // Linha 1px vertical dentro do header — aparece no hover do TH\r\n \"after:content-[''] after:absolute after:left-1/2 after:-translate-x-1/2\",\r\n \"after:top-[8px] after:bottom-[8px] after:w-px after:bg-transparent\",\r\n \"after:transition-all after:duration-150\",\r\n \"group-hover/headcell:after:bg-border-default\",\r\n // Hover direto no handle → linha brand 2px full-height\r\n \"hover:after:bg-bg-brand hover:after:w-[2px] hover:after:top-0 hover:after:bottom-0\",\r\n // DRAG ATIVO → mantém linha brand visível independente do :hover\r\n \"data-[dragging=true]:after:bg-bg-brand data-[dragging=true]:after:w-[2px] data-[dragging=true]:after:top-0 data-[dragging=true]:after:bottom-0\",\r\n ],\r\n /* Ícone de sort no head cell. */\r\n sortIcon: [\r\n \"shrink-0 size-icon-xs\",\r\n \"transition-opacity duration-150\",\r\n ],\r\n /* Ícone de tipo de coluna no head (Hash, User, AtSign…). */\r\n typeIcon: [\r\n \"shrink-0 size-[13px] text-fg-muted opacity-70\",\r\n \"group-hover/headcell:opacity-100\",\r\n ],\r\n /* Badge brand com índice de sort (1, 2, 3). */\r\n sortBadge: [\r\n \"inline-flex items-center justify-center shrink-0\",\r\n \"min-w-[18px] h-[18px] px-[5px]\",\r\n \"rounded-radius-xs bg-bg-brand text-fg-on-brand\",\r\n \"text-caption-xs font-bold leading-none tabular-nums\",\r\n ],\r\n /* Stack absolute na borda direita do head cell — agrupa sort e headMenu.\r\n Largura dinâmica: encolhe quando itens estão \"hidden\", cresce quando aparecem no hover. */\r\n headRightStack: [\r\n \"absolute right-pad-md top-1/2 -translate-y-1/2 z-[1]\", // 8px de respiro da borda direita\r\n \"inline-flex items-center gap-gp-xs\",\r\n \"bg-bg-table-head pl-pad-xs\",\r\n \"pointer-events-none\",\r\n ],\r\n /* Sort ativo (asc/desc) — sempre visível quando isSorted=true. */\r\n headSortActive: [\r\n \"inline-flex items-center gap-gp-xs shrink-0\",\r\n \"text-fg-default\",\r\n ],\r\n /* Sort hint (sortable mas inativo) — display:none default, inline-flex no hover.\r\n Como é display:none, NÃO ocupa espaço no stack até aparecer. */\r\n headSortHint: [\r\n \"hidden group-hover/headcell:inline-flex items-center shrink-0\",\r\n \"text-fg-muted opacity-60\",\r\n ],\r\n /* Head menu wrapper — display:none default, inline-flex no hover.\r\n Tem pointer-events:auto pra restaurar interatividade (parent stack tem pointer-events:none). */\r\n headMenuItem: [\r\n // Esconde por padrao; revela quando:\r\n // 1. hover no header (group-hover) — UX padrao\r\n // 2. focus interno (focus-within) — keyboard navigation\r\n // 3. dropdown interno aberto (:has data-state=open) — mantem visivel\r\n // enquanto user move cursor pra dentro do menu portal\r\n // 4. data-menu-active=true no botao — mantem visivel durante a janela\r\n // de close animation (~200ms) pra portal nao perder a ancora\r\n \"hidden items-center shrink-0\",\r\n \"group-hover/headcell:inline-flex\",\r\n \"focus-within:inline-flex\",\r\n \"has-[[data-state=open]]:inline-flex\",\r\n \"has-[[data-menu-active=true]]:inline-flex\",\r\n \"pointer-events-auto\",\r\n ],\r\n /* Card mode — wrapper de cada row no modo card. */\r\n cardWrap: [\r\n \"flex flex-col w-full p-pad-card-sm gap-gp-md\",\r\n \"border-b border-border-table last:border-b-0\",\r\n \"bg-bg-table\",\r\n ],\r\n /* Card mode — header do card (primary + checkbox + actions). */\r\n cardHeader: [\r\n \"flex items-center justify-between gap-gp-md\",\r\n ],\r\n /* Card mode — body items (label/value). */\r\n cardItem: [\r\n \"flex flex-col gap-gp-2xs\",\r\n ],\r\n /* Card mode — label da coluna acima do valor. */\r\n cardLabel: [\r\n \"text-body-xs uppercase tracking-wider text-fg-muted\",\r\n ],\r\n /* Card mode — valor abaixo do label. */\r\n cardValue: [\r\n \"text-body-md text-fg-default\",\r\n ],\r\n },\r\n variants: {\r\n // ⚠️ Alturas de row por densidade. DEVEM casar com `DENSITY_ROW_HEIGHT` em\r\n // `DataTable/data-table.constants.ts` (usado pela estimativa do virtualizer).\r\n // Mudou aqui → mudar lá, senão o scroll virtual desalinha.\r\n density: {\r\n compact: { row: \"h-[40px]\", cell: \"py-0\", headCell: \"\" },\r\n standard: { row: \"h-[56px]\", cell: \"py-0\", headCell: \"\" },\r\n comfortable: { row: \"h-[64px]\", cell: \"py-0\", headCell: \"\" },\r\n },\r\n sticky: {\r\n true: { head: \"sticky top-0\" },\r\n false: {},\r\n },\r\n selected: {\r\n true: {\r\n row: [\r\n \"bg-bg-table-row-selected hover:bg-bg-table-row-selected-hover\",\r\n \"before:content-[''] before:absolute before:left-0 before:top-0 before:bottom-0 before:w-[3px] before:bg-bg-brand before:z-[5] before:pointer-events-none\",\r\n ].join(\" \"),\r\n cardWrap: \"bg-bg-table-row-selected hover:bg-bg-table-row-selected-hover\",\r\n },\r\n false: {\r\n row: \"hover:bg-bg-table-row-hover\",\r\n cardWrap: \"hover:bg-bg-table-row-hover\",\r\n },\r\n },\r\n clickable: {\r\n true: { row: \"cursor-pointer\", cardWrap: \"cursor-pointer\" },\r\n false: {},\r\n },\r\n pinned: {\r\n // `bg-inherit` cobre o conteúdo scrollado nos estados normais (row bg opaco).\r\n // Quando a row está destacada (`data-highlighted` via group/row), o bg da row\r\n // é color-mix com transparent → trocamos pro token SÓLIDO pra não vazar.\r\n // Hover usa variante de grupo ARBITRÁRIA única (`[[data-highlighted]:hover]`)\r\n // — encadear dois `group-*/row` geraria descendente aninhado (não casa).\r\n left: {\r\n headCell: \"sticky z-10 bg-bg-table-head\",\r\n cell: \"sticky z-[5] bg-inherit group-data-[highlighted]/row:bg-bg-table-row-selected-solid group-[[data-highlighted]:hover]/row:bg-bg-table-row-selected-hover-solid\",\r\n },\r\n right: {\r\n headCell: \"sticky z-10 bg-bg-table-head\",\r\n cell: \"sticky z-[5] bg-inherit group-data-[highlighted]/row:bg-bg-table-row-selected-solid group-[[data-highlighted]:hover]/row:bg-bg-table-row-selected-hover-solid\",\r\n },\r\n },\r\n align: {\r\n left: { cell: \"justify-start text-left\", headCell: \"justify-start text-left\" },\r\n center: { cell: \"justify-center text-center\", headCell: \"justify-center text-center\" },\r\n right: { cell: \"justify-end text-right\", headCell: \"justify-end text-right\" },\r\n },\r\n sortable: {\r\n true: { headCell: \"cursor-pointer hover:text-fg-default\" },\r\n false: {},\r\n },\r\n ellipsis: {\r\n true: { cell: \"overflow-hidden [&>*]:truncate\" },\r\n false: {},\r\n },\r\n cellBorders: {\r\n true: {\r\n // `:has(+ [data-purpose='actions'])`: a cell ANTES da coluna actions\r\n // perde border-right — evita o divider visual encostado na actions.\r\n headCell:\r\n \"border-r border-border-table last:border-r-0 has-[+_[data-purpose='actions']]:border-r-0\",\r\n cell:\r\n \"border-r border-border-table last:border-r-0 has-[+_[data-purpose='actions']]:border-r-0\",\r\n },\r\n false: {},\r\n },\r\n /** Variant pra cells de coluna especial (selection / actions).\r\n *\r\n * - `selection`: remove padding pra checkbox 28px caber em 56px e centralizar.\r\n * - `actions`: header em branco (sem texto/menu), sem border-right, padding\r\n * horizontal mínimo. Usado quando `type: \"actions\"` no DataTableColumnDef.\r\n * Border-right removida via `!border-r-0` (override do cellBorders=true). */\r\n purpose: {\r\n default: {},\r\n selection: {\r\n // Sem padding + centralizado: checkbox 28px fica no meio dos 56px.\r\n // justify-center sobrescreve o align default (left) — coluna de seleção\r\n // sempre centraliza, sem o consumer precisar passar align=\"center\".\r\n headCell: \"px-0 py-0 justify-center\",\r\n cell: \"px-0 py-0 justify-center\",\r\n },\r\n actions: {\r\n headCell: \"!border-r-0 px-pad-md\",\r\n cell: \"!border-r-0 px-pad-md\",\r\n },\r\n },\r\n },\r\n defaultVariants: {\r\n density: \"standard\",\r\n sticky: true,\r\n selected: false,\r\n clickable: false,\r\n align: \"left\",\r\n sortable: false,\r\n ellipsis: false,\r\n cellBorders: true,\r\n purpose: \"default\",\r\n },\r\n});\r\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport type UseColumnResizeParams = {\n currentWidth: number;\n minWidth?: number;\n maxWidth?: number;\n /** Disparado a cada `mousemove` durante o drag.\n * Tipicamente usado pra side-effect \"live preview\" pelo consumer.\n * Em consumers React, prefira `onResizeEnd` pra evitar re-render storm —\n * use `onResizeLiveDOM` pra DOM mutation síncrona sem state. */\n onResize?: (widthPx: number) => void;\n /** Disparado no `mouseup` com largura final em px.\n * Pra consumers React: ideal pra commit no state (1 update por drag). */\n onResizeEnd?: (widthPx: number) => void;\n /** Callback síncrono pra DOM mutation durante drag (sem state React).\n * Recomendado pra atualizar inline styles em massa (ex: <Cell width>) sem\n * causar re-render storm. Chamado a cada mousemove em paralelo com `onResize`.\n * Pattern: consumer query DOM via ref + aplica `style.width` direto. */\n onResizeLiveDOM?: (widthPx: number) => void;\n};\n\nexport type UseColumnResizeResult = {\n onMouseDown: (e: React.MouseEvent) => void;\n isDragging: boolean;\n};\n\nconst DEFAULT_MIN = 60;\nconst DEFAULT_MAX = 800;\n\nexport function useColumnResize({\n currentWidth,\n minWidth = DEFAULT_MIN,\n maxWidth = DEFAULT_MAX,\n onResize,\n onResizeEnd,\n onResizeLiveDOM,\n}: UseColumnResizeParams): UseColumnResizeResult {\n const [isDragging, setIsDragging] = useState(false);\n\n const onResizeRef = useRef(onResize);\n const onResizeEndRef = useRef(onResizeEnd);\n const onResizeLiveDOMRef = useRef(onResizeLiveDOM);\n const minRef = useRef(minWidth);\n const maxRef = useRef(maxWidth);\n\n onResizeRef.current = onResize;\n onResizeEndRef.current = onResizeEnd;\n onResizeLiveDOMRef.current = onResizeLiveDOM;\n minRef.current = minWidth;\n maxRef.current = maxWidth;\n\n const stateRef = useRef<{\n startX: number;\n startWidth: number;\n lastWidth: number;\n dragging: boolean;\n }>({ startX: 0, startWidth: 0, lastWidth: currentWidth, dragging: false });\n\n stateRef.current.lastWidth = currentWidth;\n\n const handlersRef = useRef<{\n move: (e: MouseEvent) => void;\n up: (e: MouseEvent) => void;\n } | null>(null);\n\n if (!handlersRef.current) {\n handlersRef.current = {\n move: (e: MouseEvent) => {\n if (!stateRef.current.dragging) return;\n const delta = e.clientX - stateRef.current.startX;\n const next = Math.min(\n maxRef.current,\n Math.max(minRef.current, stateRef.current.startWidth + delta),\n );\n stateRef.current.lastWidth = next;\n // Live DOM primeiro (síncrono, sem React) — feedback visual fluido.\n // Depois o callback onResize (estado/state). Os 2 podem coexistir.\n onResizeLiveDOMRef.current?.(next);\n onResizeRef.current?.(next);\n },\n up: () => {\n if (!stateRef.current.dragging) return;\n stateRef.current.dragging = false;\n setIsDragging(false);\n document.removeEventListener(\"mousemove\", handlersRef.current!.move);\n document.removeEventListener(\"mouseup\", handlersRef.current!.up);\n document.body.style.cursor = \"\";\n document.body.style.userSelect = \"\";\n onResizeEndRef.current?.(stateRef.current.lastWidth);\n },\n };\n }\n\n const onMouseDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n stateRef.current = {\n startX: e.clientX,\n startWidth: currentWidth,\n lastWidth: currentWidth,\n dragging: true,\n };\n setIsDragging(true);\n document.addEventListener(\"mousemove\", handlersRef.current!.move);\n document.addEventListener(\"mouseup\", handlersRef.current!.up);\n document.body.style.cursor = \"col-resize\";\n document.body.style.userSelect = \"none\";\n },\n [currentWidth],\n );\n\n useEffect(() => {\n return () => {\n if (stateRef.current.dragging && handlersRef.current) {\n document.removeEventListener(\"mousemove\", handlersRef.current.move);\n document.removeEventListener(\"mouseup\", handlersRef.current.up);\n document.body.style.cursor = \"\";\n document.body.style.userSelect = \"\";\n }\n };\n }, []);\n\n return {\n onMouseDown,\n isDragging,\n };\n}\n","import type React from \"react\";\r\nimport { createContext, forwardRef, useCallback, useContext, useEffect, useRef, useState } from \"react\";\r\nimport { ArrowUp, ArrowDown, ArrowUpDown } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { tableStyles } from \"./table.styles\";\r\nimport { useColumnResize } from \"./use-column-resize\";\r\nimport type {\r\n TableProps,\r\n TableHeadProps,\r\n TableBodyProps,\r\n TableRowProps,\r\n TableCellProps,\r\n TableHeadCellProps,\r\n TableDensity,\r\n SortDirection,\r\n} from \"./table.types\";\r\n\r\n/* ── Context interno (privado) — propaga density + cellBorders pros subcomponentes ─ */\r\n\r\ntype TableContextValue = {\r\n density: TableDensity;\r\n cellBorders: boolean;\r\n /**\r\n * Field da coluna com resize handle ATIVO — drag em curso OU hover sobre o handle.\r\n * Aplica linha brand em todas as cells da coluna. Null quando nenhum.\r\n */\r\n resizingField: string | null;\r\n setResizingField: (field: string | null) => void;\r\n /** True quando body scrollou pra baixo (scrollTop > 0) — header ganha shadow. */\r\n isScrolled: boolean;\r\n};\r\n\r\nconst TableContext = createContext<TableContextValue>({\r\n density: \"standard\",\r\n cellBorders: true,\r\n resizingField: null,\r\n setResizingField: () => {},\r\n isScrolled: false,\r\n});\r\n\r\nfunction useTableContext(): TableContextValue {\r\n return useContext(TableContext);\r\n}\r\n\r\nconst styles = tableStyles();\r\n\r\n/* ── <Table> root ─────────────────────────────────────────────────── */\r\n\r\nexport function Table({\r\n density = \"standard\",\r\n cardBreakpoint = 768,\r\n cellBorders = true,\r\n ariaLabel,\r\n className,\r\n scrollRef: externalScrollRef,\r\n children,\r\n}: TableProps) {\r\n // Container queries via inline style — Tailwind v4 não tem arbitrary container query no momento da escrita\r\n const cardCss =\r\n cardBreakpoint === false\r\n ? undefined\r\n : ({ \"--table-card-bp\": `${cardBreakpoint}px` } as React.CSSProperties);\r\n\r\n // State pra tracking de coluna em drag ativo (resize) — aplica data-resizing-col no root,\r\n // CSS estiliza todas as cells com data-field correspondente (full-height line).\r\n const [resizingField, setResizingField] = useState<string | null>(null);\r\n\r\n // Detecta scroll vertical pra mostrar shadow no sticky header\r\n const [isScrolled, setIsScrolled] = useState(false);\r\n const internalScrollRef = useRef<HTMLDivElement>(null);\r\n // Usa ref externa se passada (DataTable virtualization), senao a interna.\r\n const scrollRef = externalScrollRef ?? internalScrollRef;\r\n useEffect(() => {\r\n const el = scrollRef.current;\r\n if (!el) return;\r\n const onScroll = () => setIsScrolled(el.scrollTop > 0);\r\n el.addEventListener(\"scroll\", onScroll, { passive: true });\r\n onScroll();\r\n return () => el.removeEventListener(\"scroll\", onScroll);\r\n }, [scrollRef]);\r\n\r\n return (\r\n <TableContext.Provider\r\n value={{ density, cellBorders, resizingField, setResizingField, isScrolled }}\r\n >\r\n <div\r\n role=\"grid\"\r\n aria-label={ariaLabel}\r\n data-density={density}\r\n data-resizing-col={resizingField ?? undefined}\r\n className={cn(styles.root(), className)}\r\n style={cardCss}\r\n >\r\n <div ref={scrollRef} className={styles.scroll()}>{children}</div>\r\n </div>\r\n </TableContext.Provider>\r\n );\r\n}\r\n\r\n/* ── <TableHead> ──────────────────────────────────────────────────── */\r\n\r\nexport function TableHead({\r\n sticky = true,\r\n className,\r\n rootProps,\r\n children,\r\n}: TableHeadProps) {\r\n const { isScrolled } = useTableContext();\r\n return (\r\n <div\r\n {...rootProps}\r\n role=\"rowgroup\"\r\n data-scrolled={isScrolled ? \"true\" : undefined}\r\n className={cn(tableStyles({ sticky }).head(), className)}\r\n >\r\n <div role=\"row\" className=\"flex w-full\">\r\n {children}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n/* ── <TableBody> ──────────────────────────────────────────────────── */\r\n\r\nexport function TableBody({\r\n className,\r\n style,\r\n rootProps,\r\n virtualized,\r\n children,\r\n}: TableBodyProps) {\r\n // Em modo virtualizado: body vira block + position relative + height total\r\n // pra que rows absolute-positioned (do @tanstack/react-virtual) renderizem\r\n // corretamente. Override do flex-col default via className `!block`.\r\n const virtualStyle: React.CSSProperties | undefined = virtualized\r\n ? {\r\n height: virtualized.totalHeight,\r\n position: \"relative\",\r\n minWidth: \"100%\",\r\n ...style,\r\n }\r\n : style;\r\n return (\r\n <div\r\n {...rootProps}\r\n role=\"rowgroup\"\r\n className={cn(\r\n styles.body(),\r\n virtualized && \"!block\",\r\n className,\r\n )}\r\n style={virtualStyle}\r\n >\r\n {children}\r\n </div>\r\n );\r\n}\r\n\r\n/* ── <TableRow> ───────────────────────────────────────────────────── */\r\n\r\nexport const TableRow = forwardRef<HTMLDivElement, TableRowProps>(function TableRow({\r\n selected = false,\r\n open = false,\r\n focused = false,\r\n clickable,\r\n onClick,\r\n className,\r\n rootProps,\r\n children,\r\n}, ref) {\r\n const { density } = useTableContext();\r\n const isClickable = clickable ?? !!onClick;\r\n const highlighted = selected || open;\r\n // Pinned/sticky cells precisam de bg OPACO quando a row está destacada\r\n // (selected/open/focused) — o bg da row é color-mix com transparent e deixaria\r\n // o conteúdo scrollado vazar sob a coluna fixa. `data-highlighted` + `group/row`\r\n // permitem o table.styles aplicar o token sólido só nessas cells.\r\n const solidPinned = highlighted || focused;\r\n const dataState = selected && open\r\n ? \"selected open\"\r\n : selected\r\n ? \"selected\"\r\n : open\r\n ? \"open\"\r\n : undefined;\r\n\r\n return (\r\n <div\r\n {...rootProps}\r\n ref={ref}\r\n role=\"row\"\r\n aria-selected={selected || undefined}\r\n data-state={dataState}\r\n data-focused={focused || undefined}\r\n data-highlighted={solidPinned || undefined}\r\n tabIndex={focused ? 0 : -1}\r\n className={cn(\r\n \"group/row\",\r\n tableStyles({ selected: highlighted, clickable: isClickable, density }).row(),\r\n // Focus visual — bg tinted (match checkbox selected) + borda brand interna.\r\n // A borda vem de um overlay ::after com z-[7] (ACIMA do pinned cell z-[5]):\r\n // `outline` no row era pintado SOB as sticky cells (bg opaco) e quebrava\r\n // no topo/embaixo na coluna fixa. O overlay desenha por cima, contínuo.\r\n focused &&\r\n \"bg-bg-table-row-selected hover:bg-bg-table-row-selected-hover z-[6] relative after:content-[''] after:absolute after:inset-0 after:z-[7] after:pointer-events-none after:border-2 after:border-bg-brand\",\r\n className,\r\n )}\r\n onClick={onClick}\r\n >\r\n {children}\r\n </div>\r\n );\r\n});\r\n\r\n/* ── <TableCell> ──────────────────────────────────────────────────── */\r\n\r\nexport const TableCell = forwardRef<HTMLDivElement, TableCellProps>(function TableCell({\r\n field,\r\n tooltip,\r\n width,\r\n pinned,\r\n pinOffset,\r\n align = \"left\",\r\n ellipsis = false,\r\n label,\r\n className,\r\n rootProps,\r\n purpose = \"default\",\r\n children,\r\n}, ref) {\r\n const { density, cellBorders, resizingField } = useTableContext();\r\n const isResizingThisCol = field !== undefined && resizingField === field;\r\n const style: React.CSSProperties = {};\r\n if (width !== undefined) {\r\n style.width = width;\r\n style.minWidth = width;\r\n style.maxWidth = width;\r\n }\r\n if (pinned === \"left\" && pinOffset !== undefined) style.left = pinOffset;\r\n if (pinned === \"right\" && pinOffset !== undefined) style.right = pinOffset;\r\n\r\n return (\r\n <div\r\n {...rootProps}\r\n ref={ref}\r\n role=\"gridcell\"\r\n data-pinned={pinned}\r\n data-label={label}\r\n data-field={field}\r\n data-purpose={purpose}\r\n data-resize-active={isResizingThisCol ? \"true\" : undefined}\r\n title={tooltip}\r\n className={cn(\r\n tableStyles({ pinned, align, ellipsis, density, cellBorders, purpose }).cell(),\r\n // Linha brand 2px alinhada com o centro do resize handle do header (~2px do edge)\r\n isResizingThisCol &&\r\n \"relative after:absolute after:right-[2px] after:top-0 after:bottom-0 after:w-[2px] after:bg-bg-brand after:pointer-events-none\",\r\n className,\r\n )}\r\n style={style}\r\n >\r\n {children}\r\n </div>\r\n );\r\n});\r\n\r\n/* ── <TableHeadCell> ──────────────────────────────────────────────── */\r\n\r\nexport const TableHeadCell = forwardRef<HTMLDivElement, TableHeadCellProps>(function TableHeadCell({\r\n field,\r\n width,\r\n pinned,\r\n pinOffset,\r\n align = \"left\",\r\n sortable = false,\r\n sortDirection = null,\r\n sortIndex = 1,\r\n onSortClick,\r\n icon: Icon,\r\n headMenu,\r\n resizable,\r\n onResize,\r\n onResizeEnd,\r\n className,\r\n style: extraStyle,\r\n rootProps,\r\n purpose = \"default\",\r\n children,\r\n}, forwardedRef) {\r\n const { density, cellBorders, setResizingField } = useTableContext();\r\n const headCellRef = useRef<HTMLDivElement | null>(null);\r\n // Merge forwardedRef com headCellRef interno (usado pelo resize live-DOM).\r\n const setRefs = useCallback((el: HTMLDivElement | null) => {\r\n headCellRef.current = el;\r\n if (typeof forwardedRef === \"function\") forwardedRef(el);\r\n else if (forwardedRef) forwardedRef.current = el;\r\n }, [forwardedRef]);\r\n\r\n const resize = useColumnResize({\r\n currentWidth: width ?? 160,\r\n // Live DOM update — escreve `style.width` direto nas cells com `data-field`\r\n // correspondente, escopado ao `[role=\"grid\"]` ancestral. Síncrono, sem React,\r\n // zero re-render durante o drag. Documented hook API via `onResizeLiveDOM`\r\n // (vs `onResize` que vai pro state externo, normalmente debounced ao mouseup).\r\n onResizeLiveDOM: field\r\n ? (w) => {\r\n const grid = headCellRef.current?.closest('[role=\"grid\"]');\r\n grid?.querySelectorAll<HTMLElement>(`[data-field=\"${field}\"]`).forEach((el) => {\r\n el.style.width = `${w}px`;\r\n el.style.minWidth = `${w}px`;\r\n el.style.maxWidth = `${w}px`;\r\n });\r\n }\r\n : undefined,\r\n onResize,\r\n onResizeEnd,\r\n });\r\n\r\n // Propaga isDragging do header pro Table root via context (CSS highlight column-wide)\r\n useEffect(() => {\r\n if (resize.isDragging && field) {\r\n setResizingField(field);\r\n return () => setResizingField(null);\r\n }\r\n }, [resize.isDragging, field, setResizingField]);\r\n\r\n const style: React.CSSProperties = {};\r\n if (width !== undefined) {\r\n style.width = width;\r\n style.minWidth = width;\r\n style.maxWidth = width;\r\n }\r\n if (pinned === \"left\" && pinOffset !== undefined) style.left = pinOffset;\r\n if (pinned === \"right\" && pinOffset !== undefined) style.right = pinOffset;\r\n\r\n const ariaSort: React.AriaAttributes[\"aria-sort\"] = sortable\r\n ? sortDirection === \"asc\"\r\n ? \"ascending\"\r\n : sortDirection === \"desc\"\r\n ? \"descending\"\r\n : \"none\"\r\n : undefined;\r\n\r\n const isSorted = sortDirection === \"asc\" || sortDirection === \"desc\";\r\n\r\n return (\r\n <div\r\n {...rootProps}\r\n ref={setRefs}\r\n role=\"columnheader\"\r\n aria-sort={ariaSort}\r\n data-pinned={pinned}\r\n data-sort={sortDirection ?? undefined}\r\n data-field={field}\r\n data-purpose={purpose}\r\n className={cn(\r\n \"group/headcell\",\r\n tableStyles({ pinned, align, sortable, density, cellBorders, purpose }).headCell(),\r\n className,\r\n )}\r\n style={{ ...style, ...extraStyle }}\r\n onClick={sortable ? onSortClick : undefined}\r\n >\r\n {Icon && <Icon className={styles.typeIcon()} size={13} strokeWidth={1.7} aria-hidden />}\r\n <span\r\n className={cn(\r\n \"flex-1 min-w-0\",\r\n // Coluna de seleção (checkbox) centraliza por padrão — sem precisar\r\n // de align=\"center\" no consumer (alinha com o purpose=\"selection\").\r\n align === \"center\" || purpose === \"selection\"\r\n ? \"flex items-center justify-center\"\r\n : align === \"right\"\r\n ? cn(\r\n \"truncate text-right\",\r\n // Reserva espaço pro headRightStack APENAS quando sort está\r\n // ATIVO (sort badge + indicator visíveis permanentemente).\r\n // Para hover-only icons (sortable hint sem sort + headMenu),\r\n // NÃO reserva espaço — headRightStack tem `bg-bg-table-head`\r\n // que mascara o texto durante hover. Texto right-aligned\r\n // encosta corretamente na borda quando sem hover (antes\r\n // ficava com ~60px de \"vazio\" reservado pros ícones invisíveis).\r\n isSorted && \"pr-[60px]\",\r\n )\r\n : \"truncate text-left\",\r\n )}\r\n >\r\n {children}\r\n </span>\r\n {/* Right stack absolute: sort + headMenu agrupados, larguras dinâmicas via hidden/flex.\r\n Renderiza só se houver algo pra mostrar (sortable ou headMenu). */}\r\n {(sortable || headMenu) && (\r\n <span className={styles.headRightStack()}>\r\n {isSorted && (\r\n <span className={styles.headSortActive()}>\r\n {sortIndex !== undefined && (\r\n <span className={styles.sortBadge()}>{sortIndex}</span>\r\n )}\r\n <SortIndicator direction={sortDirection} />\r\n </span>\r\n )}\r\n {sortable && !isSorted && (\r\n <span className={styles.headSortHint()}>\r\n <SortIndicator direction={null} />\r\n </span>\r\n )}\r\n {headMenu && (\r\n <span className={styles.headMenuItem()}>{headMenu}</span>\r\n )}\r\n </span>\r\n )}\r\n {resizable && (\r\n <div\r\n className={styles.resizeHandle()}\r\n data-dragging={resize.isDragging}\r\n // dnd-kit PointerSensor escuta onPointerDown (dispara ANTES de mousedown).\r\n // Sem este stopPropagation, dragging do resize handle ativa o sortable\r\n // do header em paralelo — coluna começa a \"voar\" enquanto o usuário\r\n // tenta apenas redimensionar.\r\n onPointerDown={(e) => e.stopPropagation()}\r\n onMouseDown={resize.onMouseDown}\r\n // click dispara depois de mouseup quando o cursor não andou muito —\r\n // sem stopPropagation aqui, click no handle borbulha pro header e\r\n // ativa onSortClick. mousedown/pointerdown stopPropagation NÃO\r\n // impedem o click subsequente (são eventos separados).\r\n onClick={(e) => e.stopPropagation()}\r\n onMouseEnter={() => field && setResizingField(field)}\r\n onMouseLeave={() => {\r\n // So limpa se nao estiver em drag — drag continua marcado via useEffect\r\n if (!resize.isDragging) setResizingField(null);\r\n }}\r\n aria-hidden\r\n />\r\n )}\r\n </div>\r\n );\r\n});\r\n\r\n/* ── Sort indicator interno ───────────────────────────────────────── */\r\n\r\nfunction SortIndicator({ direction }: { direction: SortDirection }) {\r\n if (direction === \"asc\") return <ArrowUp className={styles.sortIcon()} aria-hidden />;\r\n if (direction === \"desc\") return <ArrowDown className={styles.sortIcon()} aria-hidden />;\r\n // Hint quando sortable && null — controlado por display no slot headSortHint (hidden → inline-flex no hover)\r\n return <ArrowUpDown className={styles.sortIcon()} aria-hidden />;\r\n}\r\n","import { cn } from \"@/lib/utils\";\r\nimport type { MouseEvent, ReactNode } from \"react\";\r\nimport { tableStyles } from \"./table.styles\";\r\n\r\nconst styles = tableStyles();\r\n\r\nexport type TableCardRowProps = {\r\n /** Conteúdo do header do card (esquerda). Normalmente checkbox + primary column. */\r\n header?: ReactNode;\r\n /** Conteúdo do canto superior direito do header. Normalmente actions/menu. */\r\n headerActions?: ReactNode;\r\n /** Itens label/value renderizados no body do card. */\r\n items: ReadonlyArray<{\r\n /** Label da coluna (mostrado acima do valor). */\r\n label: ReactNode;\r\n /** Valor renderizado. */\r\n value: ReactNode;\r\n /** Key opcional pro React. Default = index. */\r\n key?: string | number;\r\n }>;\r\n selected?: boolean;\r\n /**\r\n * Row está em foco pra detalhe (ex: click abriu drawer com info). Visual idêntico ao `selected`\r\n * (bg brand-tinted + strip lateral brand) — mas semanticamente independente: pode coexistir com `selected`.\r\n * Use pra padrão de \"click row → abre detail panel\", mantendo seleção (checkbox) separada.\r\n */\r\n open?: boolean;\r\n clickable?: boolean;\r\n onClick?: (e: MouseEvent<HTMLDivElement>) => void;\r\n className?: string;\r\n};\r\n\r\n/**\r\n * <TableCardRow> — renderização \"card vertical\" de uma linha pra mobile/container estreito.\r\n *\r\n * Layout:\r\n * ┌─────────────────────────────────────┐\r\n * │ {header} {headerActions} │\r\n * ├─────────────────────────────────────┤\r\n * │ {label}: {value} │\r\n * │ {label}: {value} │\r\n * └─────────────────────────────────────┘\r\n */\r\nexport function TableCardRow({\r\n header,\r\n headerActions,\r\n items,\r\n selected = false,\r\n open = false,\r\n clickable,\r\n onClick,\r\n className,\r\n}: TableCardRowProps) {\r\n const isClickable = clickable ?? !!onClick;\r\n const highlighted = selected || open;\r\n\r\n // Guard cross-device: ignora o click da row quando ele vem de um controle\r\n // interativo do card (kebab de ações, checkbox, link). Em touch o\r\n // stopPropagation do botão nem sempre impede o onClick do card — checar o\r\n // alvo é robusto e evita abrir o detalhe junto com o dropdown de ações.\r\n const handleClick = (e: MouseEvent<HTMLDivElement>) => {\r\n if (!onClick) return;\r\n if (\r\n (e.target as HTMLElement).closest(\r\n 'button, a, input, label, [role=\"menu\"], [role=\"menuitem\"], [data-slot=\"card-actions\"]',\r\n )\r\n ) {\r\n return;\r\n }\r\n onClick(e);\r\n };\r\n const dataState = selected && open\r\n ? \"selected open\"\r\n : selected\r\n ? \"selected\"\r\n : open\r\n ? \"open\"\r\n : undefined;\r\n\r\n return (\r\n <div\r\n role=\"article\"\r\n aria-selected={selected || undefined}\r\n data-state={dataState}\r\n className={cn(\r\n tableStyles({ selected: highlighted, clickable: isClickable }).cardWrap(),\r\n className,\r\n )}\r\n onClick={handleClick}\r\n >\r\n <div className={styles.cardHeader()}>\r\n <div className=\"flex items-center gap-gp-md min-w-0\">{header}</div>\r\n {headerActions && (\r\n <div\r\n className=\"flex items-center gap-gp-xs shrink-0\"\r\n data-slot=\"card-actions\"\r\n >\r\n {headerActions}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {items.length > 0 && (\r\n <div className=\"flex flex-col gap-gp-md\">\r\n {items.map((item, i) => (\r\n <div key={item.key ?? i} className={styles.cardItem()}>\r\n <span className={styles.cardLabel()}>{item.label}</span>\r\n <span className={styles.cardValue()}>{item.value}</span>\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useMemo } from \"react\";\nimport type { ColumnPinned } from \"./table.types\";\n\n/** Minimal column shape this hook needs. Real ColumnDef do DataTable é superset. */\nexport type WidthColumnInput = {\n field: string;\n width?: number;\n /** Default width usado quando `width` undefined. */\n defaultWidth?: number;\n pinned?: ColumnPinned;\n};\n\nexport type ColumnWidthsResult = {\n /** Largura efetiva por field (px). */\n widths: Record<string, number>;\n /** Offset sticky por field (px). Só faz sentido pra colunas pinned. */\n offsets: Record<string, number>;\n /** Total de largura ocupada pelas colunas pinned left. Usado pra calcular shadow lateral. */\n totalPinLeft: number;\n /** Total de largura ocupada pelas colunas pinned right. */\n totalPinRight: number;\n};\n\nconst DEFAULT_COLUMN_WIDTH = 160;\n\n/**\n * Calcula widths efetivos e offsets sticky cumulativos.\n *\n * Algoritmo:\n * 1. widths[field] = column.width ?? column.defaultWidth ?? DEFAULT_COLUMN_WIDTH\n * 2. Para colunas pinned=\"left\": offsets[field] = soma das widths das colunas pinned=left que vêm ANTES\n * 3. Para colunas pinned=\"right\": offsets[field] = soma das widths das colunas pinned=right que vêm DEPOIS\n * 4. Colunas não-pinned: offset = undefined\n *\n * @example\n * useColumnWidths([{field:'a',width:50,pinned:'left'}, {field:'b',width:80,pinned:'left'}, {field:'c'}])\n * → widths: {a:50, b:80, c:160}\n * → offsets: {a:0, b:50}\n * → totalPinLeft: 130, totalPinRight: 0\n */\nexport function useColumnWidths(\n columns: ReadonlyArray<WidthColumnInput>,\n): ColumnWidthsResult {\n return useMemo(() => {\n const widths: Record<string, number> = {};\n const offsets: Record<string, number> = {};\n let totalPinLeft = 0;\n let totalPinRight = 0;\n\n // Passo 1: widths efetivos\n for (const col of columns) {\n widths[col.field] =\n col.width ?? col.defaultWidth ?? DEFAULT_COLUMN_WIDTH;\n }\n\n // Passo 2: offsets left (acumulado da esquerda pra direita)\n let leftSum = 0;\n for (const col of columns) {\n if (col.pinned === \"left\") {\n offsets[col.field] = leftSum;\n leftSum += widths[col.field];\n }\n }\n totalPinLeft = leftSum;\n\n // Passo 3: offsets right (acumulado da direita pra esquerda)\n let rightSum = 0;\n for (let i = columns.length - 1; i >= 0; i--) {\n const col = columns[i];\n if (col.pinned === \"right\") {\n offsets[col.field] = rightSum;\n rightSum += widths[col.field];\n }\n }\n totalPinRight = rightSum;\n\n return { widths, offsets, totalPinLeft, totalPinRight };\n }, [columns]);\n}\n","/**\n * Constants compartilhadas do Table primitivo.\n *\n * Use estes valores em vez de duplicar literais — fonte única de verdade pra\n * larguras especiais, breakpoints, e identificadores de roles dentro do grid.\n */\n\n/** Largura padrão da coluna de seleção (checkbox header + body cells).\n * 56px = 28px checkbox + 14px padding lateral × 2. Calibrado pra hit area\n * WCAG mobile (44×44) com folga visual. */\nexport const SELECTION_COLUMN_WIDTH = 56;\n\n/** Altura do header de uma linha de tabela. Usada por skeleton, totalizer,\n * group header e quick filter row pra alinhar visualmente com a header bar. */\nexport const TABLE_HEADER_HEIGHT = 42;\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * Styles compartilhados das partes do TableToolbar.\r\n * Cada `tv()` corresponde a um sub-componente em `parts/`.\r\n *\r\n * Specs alinhadas com `.tbl-toolbar` do design-and-table-v2.\r\n */\r\n\r\n/* ── Root ──────────────────────────────────────────────────────────── */\r\n/**\r\n * Gaps responsivos:\r\n * - Mobile (< md): gap menor pra search + 2 botões caberem na mesma linha\r\n * - Desktop (≥ md): gap mais respirado (16px root, 10px left, 8px actions)\r\n */\r\nexport const toolbarRoot = tv({\r\n base: [\r\n \"flex items-center justify-between flex-wrap\",\r\n \"gap-gp-md md:gap-gp-2xl\", // 8px → 16px\r\n ],\r\n});\r\n\r\nexport const toolbarLeft = tv({\r\n base: [\r\n \"flex flex-1 items-center flex-wrap min-w-0\",\r\n \"gap-gp-sm md:gap-[10px]\", // 6px → 10px\r\n \"[&>*]:shrink-0\", // items hug, sem squeeze interno\r\n // Mobile (<md): toggle Kanban/Lista + abas + adicionar colapsam pro menu\r\n // de Configurações; a barra fica só com busca + ações à direita.\r\n \"max-md:hidden\",\r\n ],\r\n});\r\n\r\nexport const toolbarActions = tv({\r\n base: [\r\n \"flex items-center flex-wrap shrink-0\",\r\n \"gap-gp-sm md:gap-gp-md\", // 6px → 8px\r\n \"[&>*]:shrink-0\", // items hug, sem squeeze interno\r\n // Mobile: ocupa a linha toda pra a busca ficar fluida (flex-1 no search).\r\n \"max-md:w-full max-md:flex-1\",\r\n ],\r\n});\r\n\r\n/* ── Divider vertical ─────────────────────────────────────────────── */\r\nexport const toolbarDivider = tv({\r\n base: \"w-[1px] h-[24px] bg-border-default shrink-0 mx-[6px] self-center\",\r\n});\r\n\r\n/* ── Search input expansível ──────────────────────────────────────── */\r\n/**\r\n * Mobile (< md): fluido (`flex-1`) — ocupa o espaço restante, sem aumentar/diminuir width no foco.\r\n * Desktop (≥ md): width fixo 200px rest → 300px no focus-within OU quando tem valor.\r\n *\r\n * O `focus-within:` desktop expande automaticamente quando o input está focado.\r\n * A variant `expanded: true` mantém expandido mesmo sem foco (quando há valor).\r\n */\r\nexport const toolbarSearch = tv({\r\n base: [\r\n \"relative flex items-center gap-gp-md cursor-text\",\r\n \"h-form-lg px-[14px] rounded-radius-lg\",\r\n \"bg-bg-surface dark:bg-bg-muted\",\r\n \"border border-border-subtle dark:border-border-input\",\r\n \"shadow-sh-sm dark:shadow-sh-none\",\r\n \"text-fg-default\",\r\n // Mobile fluido / desktop width fixo + animação no focus\r\n \"flex-1 min-w-0 md:flex-initial\",\r\n \"md:w-[200px] md:focus-within:w-[300px]\",\r\n \"transition-[width,border-color,background-color,box-shadow] duration-[220ms] ease-[cubic-bezier(0.4,0,0.2,1)]\",\r\n \"focus-within:border-border-brand focus-within:shadow-sh-ring\",\r\n \"[&_svg]:size-[14px] [&_svg]:text-fg-muted [&_svg]:shrink-0\",\r\n ],\r\n variants: {\r\n /** Quando true, mantém expandido (300px) mesmo sem foco — útil quando tem valor (desktop only) */\r\n expanded: {\r\n true: \"md:w-[300px]\",\r\n false: \"\",\r\n },\r\n },\r\n defaultVariants: { expanded: false },\r\n});\r\n\r\nexport const toolbarSearchInput = tv({\r\n base: [\r\n \"flex-1 min-w-0 bg-transparent border-0 outline-none\",\r\n \"text-body-sm font-normal text-fg-default\",\r\n \"placeholder:text-fg-muted\",\r\n ],\r\n});\r\n\r\n/**\r\n * Dot indicator (filtros aplicados) — pequeno círculo brand no canto superior direito.\r\n *\r\n * NOTA: `ToolbarToolButton` agora compõe o `Button` do DS — seu estilo vem do\r\n * Button (color/variant/size). Esse helper só pinta o ponto de \"tem aplicado\".\r\n */\r\nexport const toolbarToolDot = tv({\r\n base: [\r\n \"absolute -top-[4px] -right-[4px] z-[2] pointer-events-none\",\r\n \"size-[13px] rounded-radius-full\",\r\n \"bg-bg-brand border-2 border-bg-canvas\",\r\n ],\r\n});\r\n\r\n/* ── Segmented (density-toggle, view-mode-toggle) ───────────────── */\r\nexport const toolbarSegmented = tv({\r\n base: [\r\n \"items-center gap-[2px] p-[3px]\",\r\n \"bg-bg-muted rounded-radius-lg\",\r\n \"h-form-lg\",\r\n ],\r\n variants: {\r\n fluid: {\r\n true: \"flex w-full\",\r\n false: \"inline-flex shrink-0\",\r\n },\r\n },\r\n defaultVariants: { fluid: false },\r\n});\r\n\r\nexport const toolbarSegmentedButton = tv({\r\n base: [\r\n \"grid place-items-center\",\r\n \"h-[34px] min-w-[36px] px-pad-md\",\r\n \"rounded-radius-md border-0 bg-transparent cursor-pointer outline-none\",\r\n \"text-body-sm font-normal text-fg-muted\",\r\n \"transition-[background-color,color,box-shadow] duration-150\",\r\n \"hover:text-fg-default\",\r\n \"focus-visible:shadow-sh-ring\",\r\n \"[&_svg]:size-[14px]\",\r\n \"disabled:opacity-50 disabled:pointer-events-none\",\r\n ],\r\n variants: {\r\n isActive: {\r\n true: \"bg-bg-accent text-fg-default font-semibold shadow-sh-sm\",\r\n false: \"\",\r\n },\r\n fluid: {\r\n true: \"flex-1\",\r\n false: \"shrink-0\",\r\n },\r\n },\r\n defaultVariants: { isActive: false, fluid: false },\r\n});\r\n\r\n/* ── View tabs group (Todos/Meus/Ativos…) ───────────────────────── */\r\nexport const toolbarTabs = tv({\r\n base: [\r\n \"items-center gap-[2px] p-[3px]\",\r\n \"bg-bg-muted rounded-radius-lg\",\r\n \"h-form-lg max-w-full overflow-x-auto\",\r\n \"[scrollbar-width:none] [&::-webkit-scrollbar]:hidden\",\r\n ],\r\n variants: {\r\n fluid: {\r\n true: \"flex w-full\",\r\n false: \"inline-flex\",\r\n },\r\n },\r\n defaultVariants: { fluid: false },\r\n});\r\n\r\nexport const toolbarTabWrap = tv({\r\n base: [\r\n \"relative inline-flex items-center\",\r\n \"rounded-radius-md\",\r\n \"transition-[background-color,box-shadow,padding-right] duration-[220ms] ease-[cubic-bezier(0.4,0,0.2,1)]\",\r\n ],\r\n variants: {\r\n isActive: {\r\n true: \"bg-bg-accent shadow-sh-sm\",\r\n false: \"\",\r\n },\r\n fluid: {\r\n true: \"flex-1 justify-center\",\r\n false: \"shrink-0\",\r\n },\r\n },\r\n defaultVariants: { isActive: false, fluid: false },\r\n});\r\n\r\nexport const toolbarTabButton = tv({\r\n base: [\r\n \"inline-flex items-center gap-gp-sm h-[34px] px-[14px]\",\r\n \"rounded-radius-md border-0 bg-transparent cursor-pointer outline-none\",\r\n \"text-body-sm font-medium text-fg-muted whitespace-nowrap\",\r\n \"transition-[color,padding-right] duration-[220ms] ease-[cubic-bezier(0.4,0,0.2,1)]\",\r\n \"hover:text-fg-default\",\r\n \"focus-visible:shadow-sh-ring\",\r\n ],\r\n variants: {\r\n isActive: {\r\n true: \"text-fg-default font-semibold\",\r\n false: \"\",\r\n },\r\n fluid: {\r\n true: \"flex-1 justify-center\",\r\n false: \"\",\r\n },\r\n },\r\n defaultVariants: { isActive: false, fluid: false },\r\n});\r\n\r\n/**\r\n * Botão \"X\" pra fechar tab custom — escondido por trás do tab (margin -18px),\r\n * desliza pra fora ao hover do wrap.\r\n */\r\nexport const toolbarTabClose = tv({\r\n base: [\r\n \"grid place-items-center size-[18px] -ml-[18px]\",\r\n \"rounded-radius-full border-0 bg-transparent text-fg-muted cursor-pointer\",\r\n \"opacity-0 scale-[0.6] origin-center pointer-events-none\",\r\n \"transition-[margin-left,opacity,transform,background-color,color] duration-[220ms] ease-[cubic-bezier(0.4,0,0.2,1)]\",\r\n \"group-hover/wrap:ml-0 group-hover/wrap:opacity-100 group-hover/wrap:scale-100 group-hover/wrap:pointer-events-auto\",\r\n \"hover:bg-bg-accent hover:text-fg-default\",\r\n \"[&_svg]:size-[11px]\",\r\n ],\r\n});\r\n\r\n/* ── Applied filters (chips abaixo da toolbar) ──────────────────── */\r\n/**\r\n * Espaçamento: toolbar → 16px → divider (border-top) → 16px → chips.\r\n * `mt-pad-3xl` afasta o border-top da toolbar; `pt-pad-3xl` afasta o\r\n * conteúdo interno (chips) do border.\r\n */\r\nexport const toolbarApplied = tv({\r\n // Mobile: scroll horizontal (flex-nowrap + overflow-x-auto) em vez de quebrar\r\n // os chips em várias linhas e empurrar a tabela pra baixo. Scrollbar oculta.\r\n // sm+: volta ao flex-wrap normal.\r\n base: [\r\n \"flex items-center gap-gp-md\",\r\n \"flex-nowrap overflow-x-auto sm:flex-wrap sm:overflow-x-visible\",\r\n \"[scrollbar-width:none] [&::-webkit-scrollbar]:hidden\",\r\n ],\r\n variants: {\r\n /**\r\n * Separator (margem topo 16px + border + padding 16px) entre toolbar\r\n * header e chips. Default `true`. Espaçamento total: 16px → divider → 16px → chips.\r\n */\r\n separator: {\r\n true: \"mt-pad-2xl pt-pad-2xl border-t border-border-default\",\r\n false: \"\",\r\n },\r\n },\r\n defaultVariants: {\r\n separator: true,\r\n },\r\n});\r\n\r\nexport const toolbarAppliedChip = tv({\r\n base: [\r\n \"inline-flex items-center gap-gp-md\",\r\n \"h-form-md pl-pad-sm pr-pad-lg\",\r\n \"bg-bg-surface dark:bg-bg-muted\",\r\n \"border border-dashed border-border-input rounded-radius-lg\",\r\n \"text-body-xs font-normal text-fg-default\",\r\n \"transition-[background-color,border-color] duration-150\",\r\n ],\r\n variants: {\r\n interactive: {\r\n true: [\r\n \"cursor-pointer\",\r\n \"hover:bg-bg-muted-hover hover:border-border-default\",\r\n \"dark:hover:bg-bg-accent\",\r\n \"focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand\",\r\n ],\r\n },\r\n },\r\n});\r\n\r\nexport const toolbarAppliedChipRemove = tv({\r\n base: [\r\n \"grid place-items-center size-[18px] shrink-0\",\r\n \"rounded-radius-full border-0 bg-transparent text-fg-subtle cursor-pointer outline-none\",\r\n \"transition-colors duration-150\",\r\n \"hover:text-fg-default\",\r\n \"focus-visible:shadow-sh-ring\",\r\n \"[&_svg]:size-[14px]\",\r\n ],\r\n});\r\n\r\nexport const toolbarAppliedChipName = tv({\r\n base: \"font-semibold text-fg-default\",\r\n});\r\n\r\nexport const toolbarAppliedChipOp = tv({\r\n base: \"text-fg-muted text-caption-sm\",\r\n});\r\n\r\nexport const toolbarAppliedChipValue = tv({\r\n base: [\r\n \"inline-flex items-center h-[22px] px-pad-md\",\r\n \"rounded-radius-sm\",\r\n \"bg-bg-muted dark:bg-bg-accent\",\r\n \"text-body-xs font-medium text-fg-default\",\r\n ],\r\n});\r\n\r\nexport const toolbarAppliedClearLink = tv({\r\n base: [\r\n \"ml-pad-sm text-body-xs font-medium text-fg-brand cursor-pointer outline-none\",\r\n \"bg-transparent border-0 p-0\",\r\n \"transition-opacity duration-150\",\r\n \"hover:underline underline-offset-2\",\r\n \"focus-visible:underline\",\r\n \"disabled:opacity-50 disabled:pointer-events-none\",\r\n ],\r\n});\r\n\r\n/* ── Bulk actions bar ─────────────────────────────────────────────── */\r\n/**\r\n * Spec alinhada com `.tbl-bulk-bar` do design-and-table-v2:\r\n * - padding 10px 14px, gap 12px, radius xl (12px)\r\n * - bg-brand-subtle + border-brand + fg-brand\r\n * - flex-wrap pra mobile cair em coluna naturalmente\r\n */\r\nexport const bulkBarRoot = tv({\r\n base: [\r\n \"flex items-center flex-wrap gap-gp-xl\",\r\n \"py-[10px] px-[14px] rounded-radius-xl\",\r\n \"bg-bg-brand-subtle border border-border-brand text-fg-brand\",\r\n ],\r\n});\r\n\r\nexport const bulkBarCount = tv({\r\n base: [\r\n \"inline-flex items-center gap-gp-md shrink-0\",\r\n \"text-body-sm font-semibold\",\r\n \"text-fg-brand dark:text-fg-default\",\r\n \"[&_svg]:size-[14px]\",\r\n ],\r\n});\r\n\r\nexport const bulkBarActions = tv({\r\n base: [\r\n \"flex items-center flex-wrap gap-gp-sm flex-1 min-w-0\",\r\n \"[&>*]:shrink-0\",\r\n ],\r\n});\r\n\r\nexport const bulkBarClear = tv({\r\n base: [\r\n \"shrink-0 ml-auto\",\r\n \"bg-transparent border-0 p-0 cursor-pointer outline-none\",\r\n \"text-body-xs font-semibold text-fg-brand\",\r\n \"transition-opacity duration-150\",\r\n \"hover:underline underline-offset-2\",\r\n \"focus-visible:underline\",\r\n \"disabled:opacity-50 disabled:pointer-events-none\",\r\n ],\r\n});\r\n","import { cn } from \"@/lib/utils\";\nimport { toolbarDivider } from \"../table-toolbar.styles\";\n\nexport type ToolbarDividerProps = React.HTMLAttributes<HTMLSpanElement>;\n\n/**\n * Divisor vertical 1px × 24px usado entre grupos da toolbar.\n */\nexport function ToolbarDivider({ className, ...props }: ToolbarDividerProps) {\n return (\n <span\n aria-hidden=\"true\"\n className={cn(toolbarDivider(), className)}\n {...props}\n />\n );\n}\n","import type { ReactNode } from \"react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport {\r\n toolbarActions,\r\n toolbarLeft,\r\n toolbarRoot,\r\n} from \"./table-toolbar.styles\";\r\nimport { ToolbarDivider } from \"./parts/toolbar-divider\";\r\n\r\n/**\r\n * TableToolbar — toolbar de tabela com layout OPINATIVO (padrão do DataTable).\r\n *\r\n * Recebe slots SEMÂNTICOS e renderiza numa ordem fixa. O consumer não monta a\r\n * ordem — impossível montar errado.\r\n *\r\n * Ordem renderizada:\r\n * Esquerda: viewToggle · ⟨divider⟩ · savedViews\r\n * Direita: refresh · actions · search · filter · fullscreen · settings · more\r\n *\r\n * Consolida os controles secundários: Ordenação, Colunas, Filtros avançados\r\n * e Densidade vivem dentro do `settings` (`<ToolbarSettingsMenu>`, drill-down);\r\n * o filtro simples fica no `filter` (funil → drawer); export + ações ficam no\r\n * `more` (⋯). Reaproveita 100% os parts/popovers — só muda a orquestração.\r\n *\r\n * Modo bulk: quando `bulkBar` é passado (não null/false), substitui a toolbar\r\n * inteira. Combine com `<BulkActionsBar>` (auto-some quando count=0).\r\n *\r\n * Pra filtros aplicados (chips), use `<ToolbarApplied>` LOGO ABAIXO da toolbar.\r\n */\r\nexport type TableToolbarProps = {\r\n /* ── Esquerda — navegação/visões ─────────────────────────────── */\r\n /** Toggle de modo de visualização (Kanban / Lista). */\r\n viewToggle?: ReactNode;\r\n /** Saved Views — abas + botão adicionar (geralmente `<TableToolbarViews>`). */\r\n savedViews?: ReactNode;\r\n\r\n /* ── Direita — ações ─────────────────────────────────────────── */\r\n /** Botão de atualizar (refresh). */\r\n refresh?: ReactNode;\r\n /** Campo de busca (`<ToolbarSearch>`). */\r\n search?: ReactNode;\r\n /** Filtro simples — icon button funil → drawer (`<ToolbarSimpleFilterDrawer>`). */\r\n filter?: ReactNode;\r\n /** Ações custom (button/dropdown/input) — use `<ToolbarActions>` (colapsa no ⋯ no mobile). */\r\n actions?: ReactNode;\r\n /** Toggle de tela cheia — icon button ⤢ (opcional). */\r\n fullscreen?: ReactNode;\r\n /** Configurações da tabela — icon button sliders → `<ToolbarSettingsMenu>`\r\n * (drill-down com Ordenação · Colunas · Filtros avançados · Densidade). */\r\n settings?: ReactNode;\r\n /** Menu de opções \"⋯\" (`<MoreMenu>`) — export + ações. */\r\n more?: ReactNode;\r\n\r\n /* ── Extras ──────────────────────────────────────────────────── */\r\n /** Substitui a toolbar inteira pela barra de ações em massa. */\r\n bulkBar?: ReactNode;\r\n className?: string;\r\n};\r\n\r\nexport function TableToolbar({\r\n viewToggle,\r\n savedViews,\r\n refresh,\r\n search,\r\n filter,\r\n actions,\r\n fullscreen,\r\n settings,\r\n more,\r\n bulkBar,\r\n className,\r\n}: TableToolbarProps) {\r\n if (bulkBar) {\r\n return <div className={cn(\"w-full\", className)}>{bulkBar}</div>;\r\n }\r\n\r\n return (\r\n <div className={cn(toolbarRoot(), className)}>\r\n {/* Esquerda — navegação/visões */}\r\n <div className={toolbarLeft()}>\r\n {viewToggle}\r\n {viewToggle && savedViews && <ToolbarDivider />}\r\n {savedViews}\r\n </div>\r\n\r\n {/* Direita — ações (sem dividers: busca + icon buttons limpos).\r\n Refresh some em <md (o menu de Configurações cobre o resto). */}\r\n <div className={toolbarActions()}>\r\n {refresh && <span className=\"hidden md:contents\">{refresh}</span>}\r\n {actions}\r\n {search}\r\n {filter}\r\n {fullscreen}\r\n {settings}\r\n {more}\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { forwardRef } from \"react\";\nimport { Search } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { toolbarSearch, toolbarSearchInput } from \"../table-toolbar.styles\";\n\nexport type ToolbarSearchProps = Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n \"size\"\n> & {\n /** className do wrapper (não do input) */\n wrapperClassName?: string;\n /** Largura expandida quando focus ou tem value. Default true. */\n autoExpand?: boolean;\n};\n\n/**\n * ToolbarSearch — input de busca compacto que expande no foco / quando tem valor.\n *\n * Wrapper é um `<label>` semântico — clicar em qualquer parte (ícone, espaço\n * vazio, etc) foca o input nativamente. Sem JS necessário.\n *\n * Dumb: estado vem de fora via `value` + `onChange`.\n */\nexport const ToolbarSearch = forwardRef<HTMLInputElement, ToolbarSearchProps>(\n (\n {\n value,\n placeholder = \"Buscar...\",\n className,\n wrapperClassName,\n autoExpand = true,\n \"aria-label\": ariaLabel = \"Buscar\",\n ...inputProps\n },\n ref,\n ) => {\n const hasValue = Boolean(value);\n const expanded = autoExpand ? hasValue : false;\n\n return (\n <label className={cn(toolbarSearch({ expanded }), wrapperClassName)}>\n <Search strokeWidth={1.8} aria-hidden=\"true\" />\n <input\n ref={ref}\n type=\"text\"\n value={value}\n placeholder={placeholder}\n aria-label={ariaLabel}\n className={cn(toolbarSearchInput(), className)}\n {...inputProps}\n />\n </label>\n );\n },\n);\nToolbarSearch.displayName = \"ToolbarSearch\";\n","import { cn } from \"@/lib/utils\";\nimport {\n toolbarSegmented,\n toolbarSegmentedButton,\n} from \"../table-toolbar.styles\";\nimport type { ToolbarSegmentedItem } from \"../table-toolbar.types\";\n\nexport type ToolbarSegmentedProps<TValue extends string = string> = {\n /** Valor atualmente selecionado */\n value: TValue;\n onValueChange: (value: TValue) => void;\n items: ToolbarSegmentedItem<TValue>[];\n /** Aria-label do radiogroup */\n ariaLabel?: string;\n /** Quando `true`, ocupa toda a largura disponível e cada item vira flex-1. */\n fluid?: boolean;\n className?: string;\n};\n\n/**\n * ToolbarSegmented — grupo de botões segmentado (track bg-muted, item ativo bg-accent).\n * Padrão usado por: density-toggle (3 níveis), view-mode-toggle (table/kanban).\n *\n * `fluid` faz o grupo ocupar 100% do pai e cada item dividir o espaço igualmente\n * (útil em sheet/drawer mobile).\n */\nexport function ToolbarSegmented<TValue extends string = string>({\n value,\n onValueChange,\n items,\n ariaLabel,\n fluid,\n className,\n}: ToolbarSegmentedProps<TValue>) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n className={cn(toolbarSegmented({ fluid }), className)}\n >\n {items.map((item) => {\n const isActive = item.value === value;\n return (\n <button\n key={item.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={isActive}\n aria-pressed={isActive}\n aria-label={item.label}\n title={item.label}\n disabled={item.disabled}\n onClick={() => onValueChange(item.value)}\n className={toolbarSegmentedButton({ isActive, fluid })}\n >\n {item.children}\n </button>\n );\n })}\n </div>\n );\n}\n","import { X } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport {\n toolbarTabButton,\n toolbarTabClose,\n toolbarTabs,\n toolbarTabWrap,\n} from \"../table-toolbar.styles\";\nimport type { ToolbarTab } from \"../table-toolbar.types\";\n\nexport type ToolbarTabsProps = {\n tabs: ToolbarTab[];\n activeId: string;\n onSelect: (id: string) => void;\n /** Callback do X em tabs custom. Se omitido, X não dispara nada (só visual). */\n onClose?: (id: string) => void;\n ariaLabel?: string;\n /** Quando `true`, ocupa toda a largura disponível e cada tab vira flex-1. */\n fluid?: boolean;\n className?: string;\n};\n\n/**\n * ToolbarTabs — grupo de view tabs salvas (Todos / Meus / Ativos / Royals…).\n * Tabs com `custom: true` exibem botão X (escondido no rest, visível no hover do wrap).\n *\n * `fluid` faz cada tab dividir o espaço igualmente (útil em sheet/drawer mobile).\n */\nexport function ToolbarTabs({\n tabs,\n activeId,\n onSelect,\n onClose,\n ariaLabel = \"Views salvas\",\n fluid,\n className,\n}: ToolbarTabsProps) {\n return (\n <div\n role=\"tablist\"\n aria-label={ariaLabel}\n className={cn(toolbarTabs({ fluid }), className)}\n >\n {tabs.map((tab) => {\n const isActive = tab.id === activeId;\n return (\n <div\n key={tab.id}\n className={cn(\"group/wrap\", toolbarTabWrap({ isActive, fluid }))}\n >\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n onClick={() => onSelect(tab.id)}\n className={toolbarTabButton({ isActive, fluid })}\n >\n <span>{tab.name}</span>\n </button>\n {tab.custom && (\n <button\n type=\"button\"\n aria-label=\"Fechar view\"\n className={toolbarTabClose()}\n onClick={(e) => {\n e.stopPropagation();\n onClose?.(tab.id);\n }}\n >\n <X strokeWidth={2.4} />\n </button>\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","import { forwardRef, type ReactNode } from \"react\";\nimport { Button } from \"../../Button/button\";\nimport { cn } from \"@/lib/utils\";\nimport { toolbarToolDot } from \"../table-toolbar.styles\";\n\nexport type ToolbarToolButtonProps = Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n \"children\" | \"color\"\n> & {\n /** Ícone à esquerda */\n icon?: ReactNode;\n /** Label do botão. Se omitido, vira icon-only (40×40). */\n label?: ReactNode;\n /** Borda+texto em brand (estado \"tem filtros aplicados\") */\n isActive?: boolean;\n /** Mostra dot indicator no canto superior direito (filtros aplicados) */\n hasIndicator?: boolean;\n};\n\n/**\n * ToolbarToolButton — botão usado nas actions da toolbar (Filtrar/Exportar/Ordenar/Cols/More).\n *\n * **Implementação:** usa `<Button>` do DS por baixo. Visual vem direto do Button\n * (`secondary outline` no rest, `primary soft` em isActive). Só adicionamos\n * `border-border-brand` no isActive (variant soft não tem border) e wrapper\n * `relative` pra ancorar o dot indicator.\n *\n * Variantes:\n * - Com label → size=\"md\"\n * - Sem label → size=\"icon-md\" (40×40)\n * - isActive → primary soft com border-brand\n * - hasIndicator → dot brand absoluto no canto\n */\nexport const ToolbarToolButton = forwardRef<\n HTMLButtonElement,\n ToolbarToolButtonProps\n>(\n (\n {\n icon,\n label,\n isActive,\n hasIndicator,\n className,\n ...rest\n },\n ref,\n ) => {\n const iconOnly = !label;\n return (\n <Button\n ref={ref}\n color={isActive ? \"primary\" : \"secondary\"}\n variant={isActive ? \"soft\" : \"outline\"}\n size={iconOnly ? \"icon-md\" : \"md\"}\n iconLeft={iconOnly ? undefined : icon}\n className={cn(\n \"relative\",\n // Active: Button primary soft não tem border — adicionamos brand\n isActive && \"border-border-brand hover:border-border-brand\",\n className,\n )}\n {...rest}\n >\n {iconOnly ? icon : label}\n {hasIndicator && (\n <span className={toolbarToolDot()} aria-hidden=\"true\" />\n )}\n </Button>\n );\n },\n);\nToolbarToolButton.displayName = \"ToolbarToolButton\";\n\n/* ── Save button \"+\" — Button ghost icon-only ─────────────────── */\n\nexport type ToolbarSaveButtonProps = Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n \"color\"\n> & {\n isOpen?: boolean;\n};\n\n/**\n * ToolbarSaveButton — botão \"+\" pra abrir o popover de visões salvas.\n * Usa `<Button>` do DS (variant=ghost, size=icon-md). Quando `isOpen`,\n * aplica o visual de hover persistente.\n */\nexport const ToolbarSaveButton = forwardRef<\n HTMLButtonElement,\n ToolbarSaveButtonProps\n>(({ className, isOpen, children, ...rest }, ref) => (\n <Button\n ref={ref}\n color=\"secondary\"\n variant=\"ghost\"\n size=\"icon-md\"\n className={cn(\n isOpen && \"bg-bg-muted text-fg-default\",\n className,\n )}\n {...rest}\n >\n {children}\n </Button>\n));\nToolbarSaveButton.displayName = \"ToolbarSaveButton\";\n","import type { ReactNode } from \"react\";\r\nimport { CircleX } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport {\r\n toolbarApplied,\r\n toolbarAppliedChip,\r\n toolbarAppliedChipName,\r\n toolbarAppliedChipOp,\r\n toolbarAppliedChipRemove,\r\n toolbarAppliedChipValue,\r\n toolbarAppliedClearLink,\r\n} from \"../table-toolbar.styles\";\r\nimport type { AppliedFilter, AppliedFilterOp } from \"../table-toolbar.types\";\r\n\r\n/** Helper exportado pra renderizar um valor como tag estilizada — uso em renderChip custom. */\r\nexport const toolbarAppliedTagClass = toolbarAppliedChipValue;\r\n\r\nexport type ToolbarAppliedProps = {\r\n filters: AppliedFilter[];\r\n onRemove: (id: string) => void;\r\n onClearAll?: () => void;\r\n /** Label do link \"Limpar todos\". Default \"Limpar todos\". Passe `null` pra esconder. */\r\n clearLabel?: React.ReactNode | null;\r\n /** Mapa operador → símbolo exibido (ex: { eq: \"=\", contains: \"contém\" }) */\r\n opLabels?: Partial<Record<string, string>>;\r\n /**\r\n * Render custom do chip — recebe o chip default (`<span>` com a estrutura\r\n * padrao) e permite envolver (ex: com PopoverTrigger). Use pra adicionar\r\n * comportamento (click reabre edicao) mantendo o layout visual.\r\n *\r\n * 2º param `isPendingOpen` informa se este chip está marcado como\r\n * \"abrir popover automaticamente\" via `pendingOpenId` — consumer usa pra\r\n * controlar `open={isPendingOpen}` do Popover wrapper.\r\n */\r\n renderChip?: (\r\n filter: AppliedFilter,\r\n defaultChip: ReactNode,\r\n isPendingOpen: boolean,\r\n ) => ReactNode;\r\n /**\r\n * Mostra separator (margem-topo + border) entre o toolbar header e os chips.\r\n * Default `true` (uso standalone). Setar `false` quando ja ha gap externo\r\n * (ex: dentro do DataTable que controla espacamento via wrapper).\r\n */\r\n separator?: boolean;\r\n /**\r\n * ID de chip que deve abrir popover automaticamente (controlled).\r\n * Quando definido, `renderChip` recebe `isPendingOpen=true` pro chip\r\n * com `filter.id === pendingOpenId`. Pattern usado pra \"filter shortcut\"\r\n * do header — clicar ícone na coluna abre o popover do chip aqui.\r\n */\r\n pendingOpenId?: string | null;\r\n /** Disparado quando o pending muda (null = popover fechado ou cleared). */\r\n onPendingOpenIdChange?: (next: string | null) => void;\r\n className?: string;\r\n};\r\n\r\nconst DEFAULT_OP_LABELS: Record<string, string> = {\r\n equals: \"é\",\r\n neq: \"não é\",\r\n contains: \"contém\",\r\n notContains: \"não contém\",\r\n startsWith: \"começa com\",\r\n endsWith: \"termina com\",\r\n gt: \">\",\r\n lt: \"<\",\r\n gte: \"≥\",\r\n lte: \"≤\",\r\n isAnyOf: \"é\",\r\n isNoneOf: \"não é\",\r\n between: \"entre\",\r\n isEmpty: \"vazio\",\r\n isNotEmpty: \"não vazio\",\r\n};\r\n\r\n/**\r\n * ToolbarApplied — chips dos filtros aplicados (renderiza embaixo da toolbar).\r\n *\r\n * Quando `filters` está vazio, retorna `null` (sem render).\r\n * Cada chip tem: [X remove] [Nome] [Operador] [Valor formatado]\r\n * Link \"Limpar todos\" à direita se houver mais de 0 filtros.\r\n *\r\n * Componente dumb: o consumer mantém o array de filtros e implementa o\r\n * delete/clear. Para gerenciar estado com menos boilerplate, veja `useToolbarFilters`.\r\n */\r\nexport function ToolbarApplied({\r\n filters,\r\n onRemove,\r\n onClearAll,\r\n clearLabel = \"Limpar todos\",\r\n opLabels,\r\n renderChip,\r\n separator = true,\r\n pendingOpenId,\r\n className,\r\n}: ToolbarAppliedProps) {\r\n if (filters.length === 0) return null;\r\n\r\n const resolveOp = (op: AppliedFilterOp): string =>\r\n opLabels?.[op] ?? DEFAULT_OP_LABELS[op] ?? String(op);\r\n\r\n return (\r\n <div className={cn(toolbarApplied({ separator }), className)}>\r\n {filters.map((f) => {\r\n const isPendingOpen = pendingOpenId === f.id;\r\n const defaultChip = (\r\n <span className={toolbarAppliedChip({ interactive: !!renderChip })}>\r\n <button\r\n type=\"button\"\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onRemove(f.id);\r\n }}\r\n aria-label=\"Remover filtro\"\r\n className={toolbarAppliedChipRemove()}\r\n >\r\n <CircleX strokeWidth={2} aria-hidden=\"true\" />\r\n </button>\r\n <span className={toolbarAppliedChipName()}>{f.columnLabel}</span>\r\n {/* Quando isEmpty (chip placeholder pré-ativo aguardando valor), renderiza\r\n apenas o nome da coluna — sem operador, sem value. Veja `showEmptyFilterChips`\r\n na DataTableProps + flag isEmpty no adapter. */}\r\n {!f.isEmpty && (\r\n <>\r\n <span className={toolbarAppliedChipOp()}>{f.opLabel ?? resolveOp(f.op)}</span>\r\n {Array.isArray(f.value) ? (\r\n <span className=\"inline-flex items-center gap-gp-2xs\">\r\n {(f.value as ReactNode[]).map((v) => (\r\n <span key={String(v)} className={toolbarAppliedChipValue()}>\r\n {v}\r\n </span>\r\n ))}\r\n </span>\r\n ) : (\r\n <span className={toolbarAppliedChipValue()}>{f.value}</span>\r\n )}\r\n </>\r\n )}\r\n </span>\r\n );\r\n return (\r\n // shrink-0: no scroll horizontal mobile (flex-nowrap) os chips não comprimem.\r\n <div key={f.id} className=\"inline-flex shrink-0\">\r\n {renderChip\r\n ? renderChip(f, defaultChip, isPendingOpen)\r\n : defaultChip}\r\n </div>\r\n );\r\n })}\r\n {clearLabel !== null && onClearAll && (\r\n <button\r\n type=\"button\"\r\n onClick={onClearAll}\r\n className={cn(toolbarAppliedClearLink(), \"shrink-0\")}\r\n >\r\n {clearLabel}\r\n </button>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import type { ReactNode } from \"react\";\r\nimport { ChevronDown, MoreHorizontal } from \"lucide-react\";\r\nimport {\r\n DropdownMenu,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n DropdownMenuLabel,\r\n DropdownMenuSeparator,\r\n DropdownMenuTrigger,\r\n} from \"@/components/shadcn/dropdown-menu\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { ToolbarToolButton } from \"./toolbar-tool-button\";\r\nimport { toolbarSearch, toolbarSearchInput } from \"../table-toolbar.styles\";\r\n\r\n/* ── Tipos ──────────────────────────────────────────────────────────── */\r\n\r\n/** Item de um menu dropdown (ou do colapso mobile). */\r\nexport type ToolbarActionMenuItem = {\r\n label: ReactNode;\r\n icon?: ReactNode;\r\n onClick?: () => void;\r\n /** Marca o item como selecionado (ex.: período corrente). */\r\n active?: boolean;\r\n destructive?: boolean;\r\n disabled?: boolean;\r\n separator?: boolean;\r\n};\r\n\r\ntype ActionBase = { id: string; label: string; icon?: ReactNode };\r\n\r\n/**\r\n * Ação custom do toolbar. Três formas — todas colapsam no ⋯ no mobile:\r\n * - `button` → botão de ação.\r\n * - `dropdown` → botão com menu (ex.: trocar período).\r\n * - `input` → campo de texto compacto (ex.: busca secundária).\r\n */\r\nexport type ToolbarAction =\r\n | (ActionBase & {\r\n kind: \"button\";\r\n onClick: () => void;\r\n isActive?: boolean;\r\n disabled?: boolean;\r\n })\r\n | (ActionBase & {\r\n kind: \"dropdown\";\r\n items: ToolbarActionMenuItem[];\r\n /** Esconde o chevron ▾ ao lado do label (default false). */\r\n hideChevron?: boolean;\r\n })\r\n | (ActionBase & {\r\n kind: \"input\";\r\n value: string;\r\n onChange: (value: string) => void;\r\n placeholder?: string;\r\n });\r\n\r\nexport type ToolbarActionsProps = {\r\n /** Ações custom do consumer (button/dropdown/input). */\r\n actions: ToolbarAction[];\r\n /**\r\n * Itens extras que entram SÓ no menu ⋯ do mobile (ex.: os `moreActions`\r\n * antigos) — assim tudo colapsa num único ⋯ em telas pequenas.\r\n */\r\n extraItems?: ToolbarActionMenuItem[];\r\n className?: string;\r\n};\r\n\r\n/* ── Render de UM item dentro de um menu (dropdown / mobile) ─────────── */\r\nfunction MenuItem({ item, idx }: { item: ToolbarActionMenuItem; idx: number }) {\r\n if (item.separator) return <DropdownMenuSeparator />;\r\n return (\r\n <DropdownMenuItem\r\n key={idx}\r\n variant={item.destructive ? \"destructive\" : \"default\"}\r\n disabled={item.disabled}\r\n onSelect={() => item.onClick?.()}\r\n className={cn(item.active && \"bg-bg-brand-subtle text-fg-brand\")}\r\n >\r\n {item.icon}\r\n {item.label}\r\n </DropdownMenuItem>\r\n );\r\n}\r\n\r\n/* ── Input compacto (desktop inline e dentro do ⋯ mobile) ───────────── */\r\nfunction ActionInput({\r\n action,\r\n className,\r\n}: {\r\n action: Extract<ToolbarAction, { kind: \"input\" }>;\r\n className?: string;\r\n}) {\r\n return (\r\n <label className={cn(toolbarSearch(), className)}>\r\n {action.icon}\r\n <input\r\n className={toolbarSearchInput()}\r\n value={action.value}\r\n placeholder={action.placeholder}\r\n onChange={(e) => action.onChange(e.target.value)}\r\n // Impede o typeahead do Radix quando o input vive dentro do menu mobile.\r\n onKeyDown={(e) => e.stopPropagation()}\r\n aria-label={action.label}\r\n />\r\n </label>\r\n );\r\n}\r\n\r\n/* ── Render inline (desktop) de UMA ação ────────────────────────────── */\r\nfunction InlineAction({ action }: { action: ToolbarAction }) {\r\n if (action.kind === \"button\") {\r\n return (\r\n <ToolbarToolButton\r\n icon={action.icon}\r\n label={action.label}\r\n isActive={action.isActive}\r\n disabled={action.disabled}\r\n onClick={action.onClick}\r\n />\r\n );\r\n }\r\n if (action.kind === \"dropdown\") {\r\n return (\r\n <DropdownMenu>\r\n <DropdownMenuTrigger asChild>\r\n <ToolbarToolButton\r\n icon={action.icon}\r\n label={\r\n action.hideChevron ? (\r\n action.label\r\n ) : (\r\n <span className=\"inline-flex items-center gap-gp-xs\">\r\n {action.label}\r\n <ChevronDown className=\"size-[14px]\" />\r\n </span>\r\n )\r\n }\r\n />\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent align=\"end\" sideOffset={4}>\r\n {action.items.map((it, i) => (\r\n <MenuItem key={i} item={it} idx={i} />\r\n ))}\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n );\r\n }\r\n return <ActionInput action={action} />;\r\n}\r\n\r\n/**\r\n * ToolbarActions — slot de ações custom do toolbar (DataTable / DataList).\r\n *\r\n * Desktop (≥ md): renderiza as ações inline (button/dropdown/input).\r\n * Mobile (< md): colapsa tudo num único ⋯ — buttons viram item, dropdowns\r\n * viram um grupo (label + itens), inputs viram um campo dentro do menu. Os\r\n * `extraItems` (ex.: o ⋯ antigo) entram no mesmo menu, evitando dois ⋯.\r\n */\r\nexport function ToolbarActions({\r\n actions,\r\n extraItems,\r\n className,\r\n}: ToolbarActionsProps) {\r\n if (actions.length === 0 && (!extraItems || extraItems.length === 0)) {\r\n return null;\r\n }\r\n\r\n return (\r\n <>\r\n {/* Desktop — inline (+ ⋯ pros extraItems, se houver) */}\r\n <div className={cn(\"hidden items-center gap-gp-sm md:flex\", className)}>\r\n {actions.map((a) => (\r\n <InlineAction key={a.id} action={a} />\r\n ))}\r\n {extraItems && extraItems.length > 0 && (\r\n <DropdownMenu>\r\n <DropdownMenuTrigger asChild>\r\n <ToolbarToolButton\r\n icon={<MoreHorizontal />}\r\n aria-label=\"Mais ações\"\r\n title=\"Mais ações\"\r\n />\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent align=\"end\" sideOffset={4}>\r\n {extraItems.map((it, i) => (\r\n <MenuItem key={i} item={it} idx={i} />\r\n ))}\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n )}\r\n </div>\r\n\r\n {/* Mobile — tudo no ⋯ */}\r\n <div className=\"flex md:hidden\">\r\n <DropdownMenu>\r\n <DropdownMenuTrigger asChild>\r\n <ToolbarToolButton\r\n icon={<MoreHorizontal />}\r\n aria-label=\"Mais ações\"\r\n title=\"Mais ações\"\r\n />\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent\r\n align=\"end\"\r\n sideOffset={4}\r\n className=\"min-w-[220px]\"\r\n >\r\n {actions.map((a, ai) => {\r\n if (a.kind === \"button\") {\r\n return (\r\n <MenuItem\r\n key={a.id}\r\n idx={ai}\r\n item={{\r\n label: a.label,\r\n icon: a.icon,\r\n onClick: a.onClick,\r\n active: a.isActive,\r\n disabled: a.disabled,\r\n }}\r\n />\r\n );\r\n }\r\n if (a.kind === \"dropdown\") {\r\n return (\r\n <div key={a.id}>\r\n <DropdownMenuLabel>{a.label}</DropdownMenuLabel>\r\n {a.items.map((it, i) => (\r\n <MenuItem key={i} item={it} idx={i} />\r\n ))}\r\n </div>\r\n );\r\n }\r\n return (\r\n <div key={a.id} className=\"px-pad-md py-pad-sm\">\r\n <DropdownMenuLabel className=\"px-0 pb-pad-sm\">\r\n {a.label}\r\n </DropdownMenuLabel>\r\n <ActionInput action={a} className=\"w-full\" />\r\n </div>\r\n );\r\n })}\r\n\r\n {extraItems && extraItems.length > 0 && (\r\n <>\r\n {actions.length > 0 && <DropdownMenuSeparator />}\r\n {extraItems.map((it, i) => (\r\n <MenuItem key={`x${i}`} item={it} idx={i} />\r\n ))}\r\n </>\r\n )}\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n </div>\r\n </>\r\n );\r\n}\r\n","import { Filter } from \"lucide-react\";\r\nimport { ToolbarToolButton } from \"./toolbar-tool-button\";\r\n\r\nexport type ToolbarFilterButtonProps = {\r\n /** Borda+texto em brand (há filtros aplicados). */\r\n isActive?: boolean;\r\n /** Dot indicator no canto (há filtros aplicados). */\r\n hasIndicator?: boolean;\r\n onClick?: () => void;\r\n /** Override do rótulo acessível. Default \"Filtros\". */\r\n ariaLabel?: string;\r\n};\r\n\r\n/**\r\n * ToolbarFilterButton — botão de Filtros PADRÃO (funil, icon-only).\r\n *\r\n * Fonte única pro botão de filtro simples do `DataTable` e do `DataList`, pra o\r\n * ícone/affordance virem do componente (sem cada consumer escolher o ícone e\r\n * divergir). Abre o drawer/popover de filtro via `onClick`.\r\n */\r\nexport function ToolbarFilterButton({\r\n isActive,\r\n hasIndicator,\r\n onClick,\r\n ariaLabel = \"Filtros\",\r\n}: ToolbarFilterButtonProps) {\r\n return (\r\n <ToolbarToolButton\r\n icon={<Filter />}\r\n aria-label={ariaLabel}\r\n title={ariaLabel}\r\n isActive={isActive}\r\n hasIndicator={hasIndicator}\r\n onClick={onClick}\r\n />\r\n );\r\n}\r\n","import type { ReactNode } from \"react\";\nimport { Check } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"../../Button/button\";\nimport {\n bulkBarRoot,\n bulkBarCount,\n bulkBarActions,\n bulkBarClear,\n} from \"../table-toolbar.styles\";\n\n/**\n * BulkActionsBar — barra de ações em massa (versão da toolbar quando há\n * itens selecionados na tabela).\n *\n * Visual alinhado com `.tbl-bulk-bar` do design-and-table-v2:\n * - fundo brand-subtle, borda brand, radius xl\n * - contagem à esquerda (ícone Check + label dinâmica)\n * - ações no meio (botões outline primary; danger usa soft critical)\n * - link \"Cancelar seleção\" no final\n *\n * Renderização condicional: quando `count === 0`, retorna `null`.\n * Use como `bulkBar` prop do `<TableToolbar>` pra trocar a view inteira,\n * ou renderize solto onde precisar.\n */\nexport type BulkActionsBarProps = {\n /** Quantidade de itens selecionados. Quando 0, o componente não renderiza. */\n count: number;\n /**\n * Label da contagem. Default: `${count} selecionado(s)`.\n * Recebe `count` pra você customizar singular/plural.\n */\n countLabel?: (count: number) => ReactNode;\n /** Callback do link \"Cancelar seleção\". */\n onClear?: () => void;\n /** Texto do link de limpar. Default: \"Cancelar seleção\". */\n clearLabel?: ReactNode;\n /** Ações da barra — use `<BulkActionButton>` ou compose como quiser. */\n children?: ReactNode;\n className?: string;\n};\n\nexport function BulkActionsBar({\n count,\n countLabel,\n onClear,\n clearLabel = \"Cancelar seleção\",\n children,\n className,\n}: BulkActionsBarProps) {\n if (count <= 0) return null;\n\n const label =\n typeof countLabel === \"function\"\n ? countLabel(count)\n : `${count} selecionado${count > 1 ? \"s\" : \"\"}`;\n\n return (\n <div\n role=\"toolbar\"\n aria-label=\"Ações em massa\"\n className={cn(bulkBarRoot(), className)}\n >\n <div className={bulkBarCount()}>\n <Check strokeWidth={2.4} />\n {label}\n </div>\n <div className={bulkBarActions()}>{children}</div>\n {onClear ? (\n <button type=\"button\" onClick={onClear} className={bulkBarClear()}>\n {clearLabel}\n </button>\n ) : null}\n </div>\n );\n}\n\n/* ── BulkActionButton ──────────────────────────────────────────────── */\n\nexport type BulkActionButtonProps = {\n icon?: ReactNode;\n children?: ReactNode;\n /** \"default\" usa primary outline; \"danger\" usa critical soft. */\n variant?: \"default\" | \"danger\";\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n disabled?: boolean;\n className?: string;\n /** aria-label quando só ícone. */\n \"aria-label\"?: string;\n};\n\n/**\n * Helper que padroniza o botão de ação dentro da bulk bar.\n * Usa `<Button>` do DS por baixo, com shape=\"pill\":\n *\n * default → primary outline pill xs\n * - light: bg-surface + border-brand + fg-brand\n * - dark : bg transparente + border + fg-brand (verde brilhante)\n *\n * danger → critical soft pill xs\n * - light/dark: bg-danger-muted + fg-danger (sem overrides)\n */\nexport function BulkActionButton({\n icon,\n children,\n variant = \"default\",\n onClick,\n disabled,\n className,\n ...rest\n}: BulkActionButtonProps) {\n // No dark, default vira transparente (sem bg-surface) e perde a shadow.\n // Danger ganha border-danger-muted pra destacar o botão destrutivo.\n const darkOverrides =\n variant === \"danger\"\n ? \"border border-border-danger-muted\"\n : \"dark:bg-transparent dark:shadow-sh-none\";\n\n return (\n <Button\n color={variant === \"danger\" ? \"critical\" : \"primary\"}\n variant={variant === \"danger\" ? \"soft\" : \"outline\"}\n size=\"xs\"\n shape=\"pill\"\n iconLeft={icon}\n onClick={onClick}\n disabled={disabled}\n className={cn(darkOverrides, className)}\n {...rest}\n >\n {children}\n </Button>\n );\n}\n","import type { ReactNode } from \"react\";\r\nimport {\r\n DropdownMenu,\r\n DropdownMenuCheckboxItem,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n DropdownMenuLabel,\r\n DropdownMenuRadioGroup,\r\n DropdownMenuRadioItem,\r\n DropdownMenuSeparator,\r\n DropdownMenuTrigger,\r\n} from \"@/components/shadcn/dropdown-menu\";\r\n\r\nexport type MoreMenuProps = {\r\n /** Botão que dispara o menu (geralmente `<ToolbarToolButton icon={<MoreHorizontal />}>`) */\r\n trigger: ReactNode;\r\n /** Itens do menu — use `MoreMenuItem`, `MoreMenuCheckboxItem`, `MoreMenuSeparator`. */\r\n children: ReactNode;\r\n /** Estado controlado (opcional — auto-gerencia se omitido). */\r\n open?: boolean;\r\n onOpenChange?: (open: boolean) => void;\r\n /** Alinhamento do menu em relação ao trigger. Default `\"end\"` (alinha à direita). */\r\n align?: \"start\" | \"center\" | \"end\";\r\n /** Espaço entre trigger e menu (px). Default 6. */\r\n sideOffset?: number;\r\n /** className extra no DropdownMenuContent (caso queira ajustar min-width). */\r\n className?: string;\r\n};\r\n\r\n/**\r\n * MoreMenu — popover de \"...\" (mais ações) da TableToolbar.\r\n *\r\n * Wrapper fino do `<DropdownMenu>` do shadcn com defaults pra contexto de\r\n * toolbar (`align=\"end\"`, `sideOffset=6`). Pra customizar items use os aliases:\r\n *\r\n * <MoreMenu trigger={<ToolbarToolButton ... />}>\r\n * <MoreMenuItem onSelect={...}>\r\n * <Grid3x3 />\r\n * Mostrar bordas entre colunas\r\n * </MoreMenuItem>\r\n * <MoreMenuItem onSelect={...}>\r\n * <Maximize2 />\r\n * Tela cheia\r\n * </MoreMenuItem>\r\n * <MoreMenuSeparator />\r\n * <MoreMenuItem variant=\"destructive\" onSelect={...}>\r\n * <Trash2 />\r\n * Resetar visualização\r\n * </MoreMenuItem>\r\n * </MoreMenu>\r\n *\r\n * Aliases re-exportam os primitives equivalentes do DropdownMenu:\r\n * - `MoreMenuItem` → `DropdownMenuItem` (com variant?: \"default\" | \"destructive\")\r\n * - `MoreMenuCheckboxItem` → `DropdownMenuCheckboxItem` (toggle com check)\r\n * - `MoreMenuRadioGroup` + `MoreMenuRadioItem` → escolha única\r\n * - `MoreMenuSeparator` → `DropdownMenuSeparator` (1px divider)\r\n * - `MoreMenuLabel` → `DropdownMenuLabel` (heading discreto)\r\n */\r\nexport function MoreMenu({\r\n trigger,\r\n children,\r\n open,\r\n onOpenChange,\r\n align = \"end\",\r\n sideOffset = 6,\r\n className,\r\n}: MoreMenuProps) {\r\n return (\r\n <DropdownMenu open={open} onOpenChange={onOpenChange}>\r\n <DropdownMenuTrigger asChild>{trigger}</DropdownMenuTrigger>\r\n <DropdownMenuContent\r\n align={align}\r\n sideOffset={sideOffset}\r\n className={className}\r\n >\r\n {children}\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n );\r\n}\r\n\r\n/* ── Aliases — items prontos pro MoreMenu ──────────────────────────── */\r\nexport {\r\n DropdownMenuItem as MoreMenuItem,\r\n DropdownMenuCheckboxItem as MoreMenuCheckboxItem,\r\n DropdownMenuRadioGroup as MoreMenuRadioGroup,\r\n DropdownMenuRadioItem as MoreMenuRadioItem,\r\n DropdownMenuSeparator as MoreMenuSeparator,\r\n DropdownMenuLabel as MoreMenuLabel,\r\n};\r\n","import { useState, type ComponentType, type ReactNode } from \"react\";\r\nimport { ChevronLeft, GripVertical, Pin, PinOff } from \"lucide-react\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/shadcn/popover\";\r\nimport { Checkbox } from \"@/components/shadcn/checkbox\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\n/* ── Types ────────────────────────────────────────────────────────── */\r\nexport type ColsPopoverColumn = {\r\n key: string;\r\n label: ReactNode;\r\n /** Ícone do tipo (lucide component) */\r\n icon?: ComponentType<{ className?: string }>;\r\n};\r\n\r\n/* ── Panel (miolo reutilizável) ──────────────────────────────────────\r\n * Extraído do PopoverContent pra reuso no `ColsPopover` (standalone) e no\r\n * `ToolbarSettingsMenu` (drill-down). Mantém o drag state interno (UI state).\r\n * `onBack` opcional → chevron de voltar no header. */\r\nexport type ColsPanelProps = {\r\n columns: ColsPopoverColumn[];\r\n visibleCols: Set<string>;\r\n onVisibleChange: (next: Set<string>) => void;\r\n pinnedCols: Set<string>;\r\n onPinnedChange: (next: Set<string>) => void;\r\n /**\r\n * Callback de reordenação. Quando passado, ativa o grip drag handle\r\n * e as linhas se tornam arrastáveis (HTML5 drag).\r\n */\r\n onColumnsReorder?: (next: ColsPopoverColumn[]) => void;\r\n title?: ReactNode;\r\n hideShowAll?: boolean;\r\n hideOnlyPinned?: boolean;\r\n showAllLabel?: ReactNode;\r\n onlyPinnedLabel?: ReactNode;\r\n /** Quando passado, renderiza o botão \"voltar\" no header (drill-down). */\r\n onBack?: () => void;\r\n};\r\n\r\nexport function ColsPanel({\r\n columns,\r\n visibleCols,\r\n onVisibleChange,\r\n pinnedCols,\r\n onPinnedChange,\r\n onColumnsReorder,\r\n title = \"Colunas visíveis\",\r\n hideShowAll,\r\n hideOnlyPinned,\r\n showAllLabel = \"Mostrar todas\",\r\n onlyPinnedLabel = \"Só fixadas\",\r\n onBack,\r\n}: ColsPanelProps) {\r\n const reorderable = Boolean(onColumnsReorder);\r\n\r\n /* ── Drag state ──────────────────────────────────────────────── */\r\n // `grippedIndex` = row que recebeu mousedown no grip → permite drag dessa row\r\n const [grippedIndex, setGrippedIndex] = useState<number | null>(null);\r\n const [dragIndex, setDragIndex] = useState<number | null>(null);\r\n const [dropIndex, setDropIndex] = useState<number | null>(null);\r\n\r\n const toggleVisible = (key: string) => {\r\n const next = new Set(visibleCols);\r\n next.has(key) ? next.delete(key) : next.add(key);\r\n onVisibleChange(next);\r\n };\r\n const togglePin = (key: string) => {\r\n const next = new Set(pinnedCols);\r\n next.has(key) ? next.delete(key) : next.add(key);\r\n onPinnedChange(next);\r\n };\r\n\r\n const showAll = () => onVisibleChange(new Set(columns.map((c) => c.key)));\r\n const onlyPinned = () => onVisibleChange(new Set([...pinnedCols]));\r\n\r\n const handleDragStart = (e: React.DragEvent, index: number) => {\r\n if (grippedIndex !== index) {\r\n e.preventDefault();\r\n return;\r\n }\r\n setDragIndex(index);\r\n e.dataTransfer.effectAllowed = \"move\";\r\n e.dataTransfer.setData(\"text/plain\", String(index));\r\n };\r\n\r\n const handleDragOver = (e: React.DragEvent, index: number) => {\r\n if (dragIndex === null) return;\r\n e.preventDefault();\r\n e.dataTransfer.dropEffect = \"move\";\r\n if (dropIndex !== index) setDropIndex(index);\r\n };\r\n\r\n const handleDrop = (e: React.DragEvent, index: number) => {\r\n if (dragIndex === null) return;\r\n e.preventDefault();\r\n if (dragIndex !== index) {\r\n const next = [...columns];\r\n const [moved] = next.splice(dragIndex, 1);\r\n next.splice(index, 0, moved);\r\n onColumnsReorder?.(next);\r\n }\r\n setDragIndex(null);\r\n setDropIndex(null);\r\n setGrippedIndex(null);\r\n };\r\n\r\n const handleDragEnd = () => {\r\n setDragIndex(null);\r\n setDropIndex(null);\r\n setGrippedIndex(null);\r\n };\r\n\r\n return (\r\n <>\r\n {/* Header — opcional botão voltar (drill-down) */}\r\n <div className=\"flex-none flex items-center gap-gp-md px-pad-xl py-pad-2xl border-b border-border-default\">\r\n {onBack && (\r\n <button\r\n type=\"button\"\r\n onClick={onBack}\r\n aria-label=\"Voltar\"\r\n className=\"grid place-items-center size-[20px] -ml-[2px] shrink-0 rounded-radius-sm bg-transparent text-fg-muted cursor-pointer outline-none hover:bg-bg-muted hover:text-fg-default focus-visible:bg-bg-muted [&_svg]:size-[16px]\"\r\n >\r\n <ChevronLeft strokeWidth={2.2} />\r\n </button>\r\n )}\r\n <h3 className=\"text-caption-sm font-semibold text-fg-muted uppercase tracking-wide leading-none m-0\">\r\n {title}\r\n </h3>\r\n </div>\r\n\r\n {/* List */}\r\n <div\r\n className={cn(\r\n \"flex-1 min-h-0 overflow-y-auto p-[6px] flex flex-col gap-[2px]\",\r\n \"[scrollbar-width:thin] [scrollbar-color:var(--color-border-default)_transparent]\",\r\n \"[&::-webkit-scrollbar]:w-[6px]\",\r\n \"[&::-webkit-scrollbar-thumb]:bg-border-default [&::-webkit-scrollbar-thumb]:rounded-full\",\r\n \"[&::-webkit-scrollbar-track]:bg-transparent\",\r\n )}\r\n >\r\n {columns.map((col, index) => {\r\n const Icon = col.icon;\r\n const checked = visibleCols.has(col.key);\r\n const isPinned = pinnedCols.has(col.key);\r\n const isDragging = dragIndex === index;\r\n const isDropTarget =\r\n dragIndex !== null && dropIndex === index && dragIndex !== index;\r\n const dropAbove = isDropTarget && dragIndex! > index;\r\n const dropBelow = isDropTarget && dragIndex! < index;\r\n\r\n return (\r\n <div\r\n key={col.key}\r\n draggable={reorderable && grippedIndex === index}\r\n onDragStart={(e) => handleDragStart(e, index)}\r\n onDragOver={(e) => handleDragOver(e, index)}\r\n onDrop={(e) => handleDrop(e, index)}\r\n onDragEnd={handleDragEnd}\r\n className={cn(\r\n \"group/row flex items-center gap-gp-lg px-pad-md py-[4px] rounded-radius-md\",\r\n \"transition-[opacity,box-shadow] duration-150\",\r\n \"hover:bg-bg-muted\",\r\n isDragging && \"opacity-40\",\r\n dropAbove && \"shadow-[inset_0_2px_0_0_var(--color-border-brand)]\",\r\n dropBelow && \"shadow-[inset_0_-2px_0_0_var(--color-border-brand)]\",\r\n )}\r\n >\r\n {reorderable && (\r\n <span\r\n onMouseDown={() => setGrippedIndex(index)}\r\n onMouseUp={() => {\r\n // Se soltou sem iniciar drag, limpa\r\n if (dragIndex === null) setGrippedIndex(null);\r\n }}\r\n className=\"grid place-items-center size-[16px] shrink-0 text-fg-subtle cursor-grab active:cursor-grabbing select-none [&_svg]:size-[14px]\"\r\n aria-label=\"Arrastar pra reordenar\"\r\n >\r\n <GripVertical strokeWidth={1.8} />\r\n </span>\r\n )}\r\n <Checkbox\r\n id={`col-vis-${col.key}`}\r\n checked={checked}\r\n onCheckedChange={() => toggleVisible(col.key)}\r\n aria-label={\r\n typeof col.label === \"string\"\r\n ? `Mostrar ${col.label}`\r\n : undefined\r\n }\r\n />\r\n {Icon && (\r\n <Icon className=\"size-[14px] shrink-0 text-fg-muted\" />\r\n )}\r\n <label\r\n htmlFor={`col-vis-${col.key}`}\r\n className=\"flex-1 text-body-sm font-medium text-fg-default cursor-pointer truncate\"\r\n >\r\n {col.label}\r\n </label>\r\n <button\r\n type=\"button\"\r\n onClick={() => togglePin(col.key)}\r\n aria-pressed={isPinned}\r\n aria-label={\r\n typeof col.label === \"string\"\r\n ? isPinned\r\n ? `Desfixar ${col.label}`\r\n : `Fixar ${col.label}`\r\n : undefined\r\n }\r\n title={isPinned ? \"Desfixar coluna\" : \"Fixar coluna\"}\r\n className={cn(\r\n \"grid place-items-center size-[28px] shrink-0\",\r\n \"rounded-radius-md bg-transparent text-fg-muted\",\r\n \"transition-[opacity,background-color,color] duration-150\",\r\n \"outline-none focus-visible:opacity-100 focus-visible:bg-bg-muted\",\r\n \"hover:bg-bg-muted hover:text-fg-default\",\r\n \"[&_svg]:size-[14px]\",\r\n isPinned\r\n ? \"opacity-100 text-fg-brand bg-bg-brand-subtle hover:bg-bg-brand-subtle-hover hover:text-fg-brand\"\r\n : \"opacity-0 group-hover/row:opacity-100\",\r\n )}\r\n >\r\n {isPinned ? (\r\n <Pin strokeWidth={2.2} />\r\n ) : (\r\n <PinOff strokeWidth={1.8} />\r\n )}\r\n </button>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n\r\n {/* Footer split */}\r\n {(!hideShowAll || !hideOnlyPinned) && (\r\n <div className=\"flex-none flex items-center justify-between gap-gp-md px-pad-2xl min-h-[44px] border-t border-border-default\">\r\n {!hideShowAll ? (\r\n <button\r\n type=\"button\"\r\n onClick={showAll}\r\n className=\"text-body-xs font-medium text-fg-brand bg-transparent border-0 p-0 cursor-pointer outline-none hover:underline focus-visible:underline underline-offset-2\"\r\n >\r\n {showAllLabel}\r\n </button>\r\n ) : (\r\n <span />\r\n )}\r\n {!hideOnlyPinned && (\r\n <button\r\n type=\"button\"\r\n onClick={onlyPinned}\r\n className=\"text-body-xs font-medium text-fg-brand bg-transparent border-0 p-0 cursor-pointer outline-none hover:underline focus-visible:underline underline-offset-2\"\r\n >\r\n {onlyPinnedLabel}\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n </>\r\n );\r\n}\r\n\r\n/* ── Popover wrapper ─────────────────────────────────────────────── */\r\nexport type ColsPopoverProps = ColsPanelProps & {\r\n trigger: ReactNode;\r\n align?: \"start\" | \"center\" | \"end\";\r\n open?: boolean;\r\n onOpenChange?: (open: boolean) => void;\r\n className?: string;\r\n};\r\n\r\n/**\r\n * ColsPopover — popover de gerenciamento de colunas da tabela.\r\n * Wrapper fino: renderiza o `<ColsPanel>` dentro do PopoverContent.\r\n *\r\n * NOTA: usa HTML5 drag nativo em vez de dnd-kit pra evitar conflito com o\r\n * `transform` aplicado pelo Radix Popover (Floating UI).\r\n */\r\nexport function ColsPopover({\r\n trigger,\r\n align = \"end\",\r\n open,\r\n onOpenChange,\r\n className,\r\n ...panel\r\n}: ColsPopoverProps) {\r\n return (\r\n <Popover open={open} onOpenChange={onOpenChange}>\r\n <PopoverTrigger asChild>{trigger}</PopoverTrigger>\r\n <PopoverContent\r\n align={align}\r\n className={cn(\r\n \"w-[320px] max-w-[calc(100vw-32px)] max-h-[min(480px,calc(100vh-80px))] p-0 flex flex-col min-h-0 overflow-hidden\",\r\n className,\r\n )}\r\n >\r\n <ColsPanel {...panel} />\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n","import type { ComponentType, ReactNode } from \"react\";\r\nimport { ArrowDown, ArrowUp, ChevronLeft, Plus, X } from \"lucide-react\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/shadcn/popover\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport type { SortDirection } from \"../table-toolbar.types\";\r\n\r\n/* ── Types ────────────────────────────────────────────────────────── */\r\n// Re-export pra backward-compat (consumers que importavam daqui).\r\nexport type { SortDirection };\r\n\r\nexport type SortPopoverColumn = {\r\n key: string;\r\n label: ReactNode;\r\n /** Ícone do tipo (lucide component) */\r\n icon?: ComponentType<{ className?: string }>;\r\n};\r\n\r\nexport type SortPopoverCriterion = {\r\n /** Key da coluna sendo ordenada */\r\n key: string;\r\n /** Direção da ordenação */\r\n dir: SortDirection;\r\n};\r\n\r\n/* ── Panel (miolo reutilizável) ──────────────────────────────────────\r\n * Extraído do PopoverContent pra ser reaproveitado tanto pelo `SortPopover`\r\n * (standalone) quanto pelo `ToolbarSettingsMenu` (drill-down). Renderiza só\r\n * header + body + footer (Fragment) — quem dá largura/altura é o container.\r\n * `onBack` opcional → mostra o chevron de voltar no header (settings menu). */\r\nexport type SortPanelProps = {\r\n columns: SortPopoverColumn[];\r\n sortBy: SortPopoverCriterion[];\r\n onSortByChange: (next: SortPopoverCriterion[]) => void;\r\n title?: ReactNode;\r\n emptyMessage?: ReactNode;\r\n addSectionLabel?: ReactNode;\r\n clearLabel?: ReactNode;\r\n /** Quando passado, renderiza o botão \"voltar\" no header (drill-down). */\r\n onBack?: () => void;\r\n};\r\n\r\nexport function SortPanel({\r\n columns,\r\n sortBy,\r\n onSortByChange,\r\n title = \"Ordenação\",\r\n emptyMessage = \"Sem critérios de ordenação.\",\r\n addSectionLabel = \"Adicionar ordenação por\",\r\n clearLabel = \"Limpar\",\r\n onBack,\r\n}: SortPanelProps) {\r\n const usedKeys = new Set(sortBy.map((s) => s.key));\r\n const available = columns.filter((c) => !usedKeys.has(c.key));\r\n\r\n const toggleDir = (index: number) => {\r\n const next = [...sortBy];\r\n next[index] = {\r\n ...next[index],\r\n dir: next[index].dir === \"asc\" ? \"desc\" : \"asc\",\r\n };\r\n onSortByChange(next);\r\n };\r\n\r\n const remove = (index: number) =>\r\n onSortByChange(sortBy.filter((_, i) => i !== index));\r\n\r\n const addSort = (key: string) =>\r\n onSortByChange([...sortBy, { key, dir: \"asc\" }]);\r\n\r\n const clearAll = () => onSortByChange([]);\r\n\r\n return (\r\n <>\r\n {/* Header — opcional botão voltar (drill-down) */}\r\n <div className=\"flex-none flex items-center gap-gp-md px-pad-xl py-pad-lg border-b border-border-default\">\r\n {onBack && (\r\n <button\r\n type=\"button\"\r\n onClick={onBack}\r\n aria-label=\"Voltar\"\r\n className=\"grid place-items-center size-[20px] -ml-[2px] shrink-0 rounded-radius-sm bg-transparent text-fg-muted cursor-pointer outline-none hover:bg-bg-muted hover:text-fg-default focus-visible:bg-bg-muted [&_svg]:size-[16px]\"\r\n >\r\n <ChevronLeft strokeWidth={2.2} />\r\n </button>\r\n )}\r\n <h3 className=\"text-caption-sm font-semibold text-fg-muted uppercase tracking-wide leading-none m-0\">\r\n {title}\r\n </h3>\r\n </div>\r\n <div\r\n className={cn(\r\n \"flex-1 min-h-0 overflow-y-auto\",\r\n \"[scrollbar-width:thin] [scrollbar-color:var(--color-border-default)_transparent]\",\r\n \"[&::-webkit-scrollbar]:w-[6px]\",\r\n \"[&::-webkit-scrollbar-thumb]:bg-border-default [&::-webkit-scrollbar-thumb]:rounded-full\",\r\n \"[&::-webkit-scrollbar-track]:bg-transparent\",\r\n )}\r\n >\r\n {/* ── Section: Critérios atuais ───────────────────────── */}\r\n <section className=\"px-pad-xl py-pad-lg border-b border-border-default\">\r\n {sortBy.length === 0 ? (\r\n <p className=\"text-body-xs font-normal text-fg-muted m-0 py-pad-sm\">\r\n {emptyMessage}\r\n </p>\r\n ) : (\r\n <div className=\"flex flex-col gap-[2px]\">\r\n {sortBy.map((s, i) => {\r\n const col = columns.find((c) => c.key === s.key);\r\n return (\r\n <div\r\n key={s.key}\r\n className=\"group/row flex items-center gap-gp-md px-pad-md py-[4px] rounded-radius-md hover:bg-bg-muted\"\r\n >\r\n <span className=\"text-caption-sm text-fg-subtle shrink-0\">\r\n {i === 0 ? \"Por\" : \"depois por\"}\r\n </span>\r\n <span className=\"flex-1 text-body-sm font-medium text-fg-default truncate\">\r\n {col?.label ?? s.key}\r\n </span>\r\n <button\r\n type=\"button\"\r\n onClick={() => toggleDir(i)}\r\n className={cn(\r\n \"inline-flex items-center gap-gp-xs h-[22px] px-pad-md shrink-0\",\r\n \"rounded-radius-sm bg-bg-muted text-fg-default text-caption-sm font-medium\",\r\n \"outline-none cursor-pointer\",\r\n \"hover:bg-bg-muted-hover focus-visible:bg-bg-muted-hover\",\r\n \"[&_svg]:size-[12px]\",\r\n )}\r\n aria-label={\r\n s.dir === \"asc\"\r\n ? \"Mudar para descendente\"\r\n : \"Mudar para ascendente\"\r\n }\r\n >\r\n {s.dir === \"asc\" ? <ArrowUp /> : <ArrowDown />}\r\n {s.dir === \"asc\" ? \"asc\" : \"desc\"}\r\n </button>\r\n <button\r\n type=\"button\"\r\n onClick={() => remove(i)}\r\n aria-label=\"Remover critério\"\r\n className={cn(\r\n \"grid place-items-center size-[22px] shrink-0\",\r\n \"rounded-radius-sm bg-transparent text-fg-muted\",\r\n \"outline-none cursor-pointer\",\r\n \"transition-[opacity,background-color,color] duration-150\",\r\n \"opacity-0 group-hover/row:opacity-100\",\r\n \"hover:bg-bg-muted hover:text-fg-default\",\r\n \"focus-visible:opacity-100 focus-visible:bg-bg-muted\",\r\n \"[&_svg]:size-[12px]\",\r\n )}\r\n >\r\n <X strokeWidth={2.2} />\r\n </button>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n </section>\r\n\r\n {/* ── Section: Adicionar ─────────────────────────────── */}\r\n {available.length > 0 && (\r\n <section className=\"px-pad-xl py-pad-lg\">\r\n <h4 className=\"text-caption-sm font-semibold text-fg-muted uppercase tracking-wide leading-none m-0 mb-pad-md\">\r\n {addSectionLabel}\r\n </h4>\r\n <div className=\"flex flex-col gap-[2px]\">\r\n {available.map((col) => {\r\n const Icon = col.icon;\r\n return (\r\n <button\r\n key={col.key}\r\n type=\"button\"\r\n onClick={() => addSort(col.key)}\r\n className={cn(\r\n \"group/add flex items-center gap-gp-md w-full\",\r\n \"px-pad-md py-pad-sm rounded-radius-md\",\r\n \"bg-transparent border-0 cursor-pointer outline-none text-left\",\r\n \"hover:bg-bg-muted focus-visible:bg-bg-muted\",\r\n \"transition-colors duration-150\",\r\n )}\r\n >\r\n {Icon && (\r\n <Icon className=\"size-[14px] shrink-0 text-fg-muted\" />\r\n )}\r\n <span className=\"flex-1 text-body-sm font-medium text-fg-default truncate\">\r\n {col.label}\r\n </span>\r\n <Plus\r\n className=\"size-[14px] shrink-0 text-fg-muted opacity-50 group-hover/add:opacity-100 group-hover/add:text-fg-brand transition-[opacity,color]\"\r\n strokeWidth={2}\r\n />\r\n </button>\r\n );\r\n })}\r\n </div>\r\n </section>\r\n )}\r\n </div>\r\n\r\n {/* ── Footer ────────────────────────────────────────────── */}\r\n {sortBy.length > 0 && (\r\n <div className=\"flex-none flex items-center justify-start gap-gp-md px-pad-2xl min-h-[44px] border-t border-border-default\">\r\n <button\r\n type=\"button\"\r\n onClick={clearAll}\r\n className=\"text-body-xs font-medium text-fg-brand bg-transparent border-0 p-0 cursor-pointer outline-none hover:underline focus-visible:underline underline-offset-2\"\r\n >\r\n {clearLabel}\r\n </button>\r\n </div>\r\n )}\r\n </>\r\n );\r\n}\r\n\r\n/* ── Popover wrapper ─────────────────────────────────────────────── */\r\nexport type SortPopoverProps = SortPanelProps & {\r\n /** Botão que abre o popover */\r\n trigger: ReactNode;\r\n /** Alinhamento do popover. Default \"end\" */\r\n align?: \"start\" | \"center\" | \"end\";\r\n /** Estado controlado (opcional) */\r\n open?: boolean;\r\n onOpenChange?: (open: boolean) => void;\r\n className?: string;\r\n};\r\n\r\n/**\r\n * SortPopover — popover de ordenação multi-coluna da tabela.\r\n * Wrapper fino: renderiza o `<SortPanel>` dentro do PopoverContent.\r\n *\r\n * Componente dumb: `sortBy` (array de critérios) vem do consumer.\r\n * Use `useToolbarSort()` hook se quiser gerenciamento de estado pronto.\r\n */\r\nexport function SortPopover({\r\n trigger,\r\n align = \"end\",\r\n open,\r\n onOpenChange,\r\n className,\r\n ...panel\r\n}: SortPopoverProps) {\r\n return (\r\n <Popover open={open} onOpenChange={onOpenChange}>\r\n <PopoverTrigger asChild>{trigger}</PopoverTrigger>\r\n <PopoverContent\r\n align={align}\r\n className={cn(\r\n \"w-[300px] max-w-[calc(100vw-32px)] max-h-[min(480px,calc(100vh-80px))] p-0 flex flex-col min-h-0 overflow-hidden\",\r\n className,\r\n )}\r\n >\r\n <SortPanel {...panel} />\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n","import { useMemo, useState, type ReactNode } from \"react\";\r\nimport { Plus, Search, Trash2 } from \"lucide-react\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/shadcn/popover\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\n/* ── Types ────────────────────────────────────────────────────────── */\r\nexport type ViewsPopoverView = {\r\n id: string;\r\n name: ReactNode;\r\n /**\r\n * Quem é o dono da view. Se igual a `myOwnerKey` (default `\"me\"`), a view\r\n * é considerada \"minha\" — mostra o botão de delete e cai na tab \"Pessoais\".\r\n * Caso contrário, é uma view compartilhada (mostra autor).\r\n */\r\n owner: string;\r\n /** Nome do autor exibido quando não é \"minha\" */\r\n ownerName?: string;\r\n};\r\n\r\nexport type ViewsPopoverProps = {\r\n /** Botão que abre o popover (geralmente `<ToolbarSaveButton>`) */\r\n trigger: ReactNode;\r\n\r\n /** Lista completa de views disponíveis */\r\n views: ViewsPopoverView[];\r\n\r\n /** ID da view atualmente ativa */\r\n activeViewId?: string;\r\n /** Aplicar/selecionar uma view (clique no item) */\r\n onApply?: (view: ViewsPopoverView) => void;\r\n /** Excluir uma view \"minha\" */\r\n onDelete?: (id: string) => void;\r\n /** Clicar em \"Salvar visão atual\" (footer) */\r\n onCreate?: () => void;\r\n\r\n /**\r\n * Key que identifica views \"minhas\" (default `\"me\"`).\r\n * Views com `owner === myOwnerKey` mostram delete e ficam na tab Pessoais.\r\n */\r\n myOwnerKey?: string;\r\n\r\n /** Esconde as tabs Todos/Pessoais (mostra todas as views direto) */\r\n hideTabs?: boolean;\r\n /** Esconde o input de busca */\r\n hideSearch?: boolean;\r\n /** Esconde o botão \"Salvar visão atual\" no footer */\r\n hideCreate?: boolean;\r\n\r\n /** Labels customizáveis */\r\n allTabLabel?: ReactNode;\r\n myTabLabel?: ReactNode;\r\n searchPlaceholder?: string;\r\n createLabel?: ReactNode;\r\n /** Mensagem de estado vazio (com search ativa) */\r\n emptySearchMessage?: (query: string) => ReactNode;\r\n /** Mensagem de estado vazio (sem search) */\r\n emptyMessage?: ReactNode;\r\n\r\n /** Alinhamento do popover. Default \"start\" */\r\n align?: \"start\" | \"center\" | \"end\";\r\n /** Estado controlado (opcional) */\r\n open?: boolean;\r\n onOpenChange?: (open: boolean) => void;\r\n\r\n className?: string;\r\n};\r\n\r\n/**\r\n * ViewsPopover — popover de visualizações salvas da tabela.\r\n *\r\n * - Tabs `Todos` / `Pessoais` (filtra por `owner === myOwnerKey`)\r\n * - Search local por nome ou autor\r\n * - Lista com estado ativo + botão delete em views \"minhas\"\r\n * - Footer \"Salvar visão atual\" pra criar nova\r\n *\r\n * Dumb: `views` + `activeViewId` vêm do consumer. Tabs e search são state interno.\r\n */\r\nexport function ViewsPopover({\r\n trigger,\r\n views,\r\n activeViewId,\r\n onApply,\r\n onDelete,\r\n onCreate,\r\n myOwnerKey = \"me\",\r\n hideTabs,\r\n hideSearch,\r\n hideCreate,\r\n allTabLabel = \"Todos\",\r\n myTabLabel = \"Pessoais\",\r\n searchPlaceholder = \"Buscar\",\r\n createLabel = \"Salvar visão atual\",\r\n emptySearchMessage = (q) => `Nenhuma visão pra \"${q}\".`,\r\n emptyMessage = \"Nenhuma visão disponível.\",\r\n align = \"start\",\r\n open,\r\n onOpenChange,\r\n className,\r\n}: ViewsPopoverProps) {\r\n const [tab, setTab] = useState<\"all\" | \"mine\">(\"all\");\r\n const [search, setSearch] = useState(\"\");\r\n\r\n const filtered = useMemo(() => {\r\n const baseList = hideTabs\r\n ? views\r\n : tab === \"mine\"\r\n ? views.filter((v) => v.owner === myOwnerKey)\r\n : views;\r\n const q = search.trim().toLowerCase();\r\n if (!q) return baseList;\r\n return baseList.filter((v) => {\r\n const name = typeof v.name === \"string\" ? v.name.toLowerCase() : \"\";\r\n const author = (v.ownerName ?? \"\").toLowerCase();\r\n return name.includes(q) || author.includes(q);\r\n });\r\n }, [views, tab, search, myOwnerKey, hideTabs]);\r\n\r\n return (\r\n <Popover open={open} onOpenChange={onOpenChange}>\r\n <PopoverTrigger asChild>{trigger}</PopoverTrigger>\r\n <PopoverContent\r\n align={align}\r\n role=\"dialog\"\r\n aria-label=\"Visualizações\"\r\n className={cn(\r\n \"w-[280px] max-w-[calc(100vw-32px)] max-h-[min(480px,calc(100vh-80px))] p-0 flex flex-col min-h-0 overflow-hidden\",\r\n className,\r\n )}\r\n >\r\n {/* Tabs */}\r\n {!hideTabs && (\r\n <div\r\n role=\"tablist\"\r\n className=\"flex-none flex items-center gap-[2px] p-[3px] m-pad-md mb-0 bg-bg-muted rounded-radius-md\"\r\n >\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n aria-selected={tab === \"all\"}\r\n onClick={() => setTab(\"all\")}\r\n className={cn(\r\n \"flex-1 h-form-sm px-pad-lg rounded-radius-sm\",\r\n \"text-body-xs font-medium cursor-pointer outline-none focus-visible:shadow-sh-ring\",\r\n \"transition-[background-color,color,box-shadow] duration-150\",\r\n tab === \"all\"\r\n ? \"bg-bg-accent text-fg-default font-semibold shadow-sh-sm\"\r\n : \"bg-transparent text-fg-muted hover:text-fg-default\",\r\n )}\r\n >\r\n {allTabLabel}\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n aria-selected={tab === \"mine\"}\r\n onClick={() => setTab(\"mine\")}\r\n className={cn(\r\n \"flex-1 h-form-sm px-pad-lg rounded-radius-sm\",\r\n \"text-body-xs font-medium cursor-pointer outline-none focus-visible:shadow-sh-ring\",\r\n \"transition-[background-color,color,box-shadow] duration-150\",\r\n tab === \"mine\"\r\n ? \"bg-bg-accent text-fg-default font-semibold shadow-sh-sm\"\r\n : \"bg-transparent text-fg-muted hover:text-fg-default\",\r\n )}\r\n >\r\n {myTabLabel}\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Search */}\r\n {!hideSearch && (\r\n <label className=\"flex-none flex items-center gap-gp-md mx-pad-md mt-pad-md h-form-md px-pad-xl rounded-radius-lg bg-bg-input dark:bg-bg-muted border border-border-input shadow-sh-sm dark:shadow-sh-none cursor-text focus-within:border-border-brand focus-within:shadow-sh-ring transition-[border-color,box-shadow] duration-150\">\r\n <Search\r\n strokeWidth={1.8}\r\n aria-hidden=\"true\"\r\n className=\"size-[14px] text-fg-muted shrink-0\"\r\n />\r\n <input\r\n type=\"text\"\r\n placeholder={searchPlaceholder}\r\n value={search}\r\n onChange={(e) => setSearch(e.target.value)}\r\n autoFocus\r\n className=\"flex-1 min-w-0 bg-transparent border-0 outline-none text-body-sm font-normal text-fg-default placeholder:text-fg-muted\"\r\n />\r\n </label>\r\n )}\r\n\r\n {/* List */}\r\n <div\r\n role=\"list\"\r\n className={cn(\r\n \"flex-1 min-h-0 overflow-y-auto p-pad-md flex flex-col gap-[2px]\",\r\n \"[scrollbar-width:thin] [scrollbar-color:var(--color-border-default)_transparent]\",\r\n \"[&::-webkit-scrollbar]:w-[6px]\",\r\n \"[&::-webkit-scrollbar-thumb]:bg-border-default [&::-webkit-scrollbar-thumb]:rounded-full\",\r\n \"[&::-webkit-scrollbar-track]:bg-transparent\",\r\n )}\r\n >\r\n {filtered.length === 0 ? (\r\n <p className=\"text-body-xs font-normal text-fg-muted m-0 px-pad-md py-pad-2xl text-center\">\r\n {search.trim() ? emptySearchMessage(search.trim()) : emptyMessage}\r\n </p>\r\n ) : (\r\n filtered.map((view) => {\r\n const isActive = view.id === activeViewId;\r\n const isMine = view.owner === myOwnerKey;\r\n return (\r\n <div\r\n key={view.id}\r\n role=\"listitem\"\r\n className={cn(\r\n \"group/view flex items-stretch gap-[2px] rounded-radius-md\",\r\n isActive && \"bg-bg-brand-subtle\",\r\n )}\r\n >\r\n <button\r\n type=\"button\"\r\n onClick={() => onApply?.(view)}\r\n className={cn(\r\n \"flex-1 flex items-center gap-gp-md min-w-0\",\r\n \"px-pad-md py-pad-sm rounded-radius-md\",\r\n \"bg-transparent border-0 cursor-pointer outline-none text-left\",\r\n \"transition-[background-color,color] duration-150\",\r\n isActive\r\n ? \"text-fg-brand hover:bg-bg-brand-subtle-hover\"\r\n : \"text-fg-default hover:bg-bg-muted focus-visible:bg-bg-muted\",\r\n )}\r\n >\r\n <span\r\n className={cn(\r\n \"flex-1 text-body-sm font-normal truncate\",\r\n isActive ? \"font-semibold\" : \"font-medium\",\r\n )}\r\n >\r\n {view.name}\r\n </span>\r\n {!isMine && view.ownerName && (\r\n <span className=\"text-caption-sm text-fg-muted shrink-0\">\r\n por {view.ownerName}\r\n </span>\r\n )}\r\n </button>\r\n {isMine && onDelete && (\r\n <button\r\n type=\"button\"\r\n onClick={() => onDelete(view.id)}\r\n aria-label={\r\n typeof view.name === \"string\"\r\n ? `Excluir ${view.name}`\r\n : \"Excluir\"\r\n }\r\n title=\"Excluir\"\r\n className={cn(\r\n \"grid place-items-center size-[28px] shrink-0 self-center\",\r\n \"mr-pad-sm\", // respiro da borda direita (= sandbox)\r\n \"rounded-radius-md bg-transparent text-fg-muted\",\r\n \"outline-none cursor-pointer\",\r\n \"transition-[opacity,background-color,color] duration-150\",\r\n \"opacity-0 group-hover/view:opacity-100\",\r\n \"hover:bg-bg-danger-muted hover:text-fg-danger\",\r\n \"focus-visible:opacity-100 focus-visible:bg-bg-muted\",\r\n \"[&_svg]:size-[14px]\",\r\n )}\r\n >\r\n <Trash2 strokeWidth={1.8} />\r\n </button>\r\n )}\r\n </div>\r\n );\r\n })\r\n )}\r\n </div>\r\n\r\n {/* Footer \"Salvar visão atual\" */}\r\n {!hideCreate && onCreate && (\r\n <div className=\"flex-none p-pad-md border-t border-border-default\">\r\n <button\r\n type=\"button\"\r\n onClick={onCreate}\r\n className={cn(\r\n \"flex items-center justify-center gap-gp-sm w-full\",\r\n \"h-form-md px-pad-xl rounded-radius-lg\",\r\n \"bg-bg-surface dark:bg-bg-muted\",\r\n \"border border-border-subtle dark:border-border-input\",\r\n \"shadow-sh-sm dark:shadow-sh-none\",\r\n \"text-body-sm font-semibold text-fg-default dark:text-fg-muted\",\r\n \"outline-none cursor-pointer\",\r\n \"transition-[background-color,color,box-shadow] duration-150\",\r\n \"hover:bg-bg-muted-hover hover:text-fg-default\",\r\n \"focus-visible:shadow-sh-ring\",\r\n \"[&_svg]:size-[14px]\",\r\n )}\r\n >\r\n <Plus strokeWidth={2.2} />\r\n {createLabel}\r\n </button>\r\n </div>\r\n )}\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * Slots tv() pro AddViewModal — replica literal do modal do sandbox\r\n * /design-and-table-v2 (TblViewsModal).\r\n *\r\n * Valores fora da escala DS (14px gap, 18px gap, 22px py, 13.5/17px font,\r\n * 3px gap) usados como arbitrary — calibração visual exata do sandbox.\r\n * Quando o token semantico existe na medida certa (form-lg, form-md,\r\n * radius-lg, pad-4xl=24, etc), usar o token.\r\n */\r\n\r\nexport const dialog = tv({\r\n base: [\r\n // Override do DialogContent default (grid + p-pad-4xl + rounded-radius-base + shadow-sh-xl)\r\n \"!gap-0 !p-0\",\r\n \"!max-w-[540px] w-[calc(100%-32px)]\",\r\n \"border border-border-default\", // sandbox tem border 1px solid — DialogContent default não traz\r\n \"!rounded-radius-2xl !shadow-sh-2xl\", // radius-2xl=18px (sandbox quer 16, mantemos token DS)\r\n \"outline-float\", // halo 6px alpha em volta — match sandbox\r\n \"flex flex-col overflow-hidden\",\r\n ],\r\n});\r\n\r\n/**\r\n * Close button manual — substitui o padrão do DialogContent (que usa\r\n * opacity-70 + cor herdada). Sandbox: 28×28, text-fg-muted, opacity 0.55 →\r\n * 1 no hover + bg-muted no hover.\r\n */\r\nexport const closeBtn = tv({\r\n base: [\r\n \"absolute top-[14px] right-[14px] z-[1]\",\r\n \"grid place-items-center size-[28px]\",\r\n \"rounded-radius-md bg-transparent border-0 cursor-pointer\",\r\n \"text-fg-muted opacity-55\",\r\n \"transition-[background-color,color,opacity] duration-150\",\r\n \"hover:bg-bg-muted hover:text-fg-default hover:opacity-100\",\r\n \"focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand\",\r\n \"dark:hover:bg-bg-muted-hover\",\r\n ],\r\n});\r\n\r\nexport const head = tv({\r\n base: [\r\n \"flex items-center gap-[14px]\", // sandbox 14px (não tem na escala)\r\n \"px-pad-4xl pt-pad-4xl pb-pad-3xl\", // 24/24/20 — sandbox literal\r\n \"border-b border-border-default\",\r\n ],\r\n});\r\n\r\nexport const headIcon = tv({\r\n base: [\r\n \"shrink-0 grid place-items-center size-form-lg\", // 40×40 — sandbox\r\n \"bg-bg-muted border border-border-input rounded-radius-lg\",\r\n \"text-fg-default\",\r\n \"dark:bg-bg-accent dark:border-border-subtle\",\r\n ],\r\n});\r\n\r\nexport const headTitleWrap = tv({\r\n base: [\r\n \"flex-1 min-w-0\",\r\n // Reserva espaço pro X close do DialogContent (absolute right-4 / size ~24px)\r\n // — evita sobreposição quando o título quebra ou é longo (mobile estreito).\r\n \"pr-pad-3xl\",\r\n ],\r\n});\r\n\r\nexport const title = tv({\r\n base: [\r\n \"m-0 mb-[2px]\",\r\n // leading-[1.3] balanceia o bloco verticalmente com o icon container 40px\r\n // (leading-none deixava o glyph colado no top → parecia subido).\r\n \"text-body-lg font-bold leading-[1.3]\",\r\n \"text-fg-default\",\r\n \"tracking-[-0.01em]\",\r\n ],\r\n});\r\n\r\nexport const sub = tv({\r\n base: \"m-0 text-body-xs font-normal text-fg-muted leading-[1.45]\",\r\n});\r\n\r\nexport const body = tv({\r\n base: \"flex flex-col gap-[18px] px-pad-4xl py-[22px]\",\r\n});\r\n\r\nexport const toggleRow = tv({\r\n base: [\r\n \"flex items-center gap-gp-xl\", // 12px — sandbox\r\n \"px-pad-2xl py-[14px]\", // 16 / 14 — sandbox\r\n \"bg-bg-muted border border-border-default rounded-radius-xl\", // radius-xl=14px (sandbox quer 12, mantemos token DS)\r\n \"cursor-pointer transition-[background-color,border-color] duration-200\",\r\n ],\r\n variants: {\r\n on: {\r\n true: \"bg-bg-brand-subtle border-border-brand\",\r\n },\r\n },\r\n});\r\n\r\nexport const toggleIcon = tv({\r\n base: [\r\n \"shrink-0 grid place-items-center size-form-md rounded-radius-lg\", // 36×36 / radius-lg=10px\r\n \"bg-bg-surface border border-border-subtle text-fg-default\",\r\n \"dark:bg-bg-accent dark:border-border-input dark:text-fg-muted\",\r\n \"transition-[background-color,border-color,color] duration-200\",\r\n ],\r\n variants: {\r\n on: {\r\n true: \"!bg-bg-surface !border-border-brand !text-fg-brand\",\r\n },\r\n },\r\n});\r\n\r\nexport const toggleText = tv({\r\n base: \"flex-1 min-w-0 flex flex-col gap-[3px]\",\r\n});\r\n\r\nexport const toggleLabel = tv({\r\n base: \"text-body-md font-semibold text-fg-default leading-[1.3]\",\r\n});\r\n\r\nexport const toggleDesc = tv({\r\n base: \"text-body-xs font-normal text-fg-muted leading-[1.45]\",\r\n});\r\n\r\nexport const foot = tv({\r\n base: [\r\n \"flex items-center justify-end gap-gp-lg\", // 10px — sandbox\r\n \"px-pad-4xl pt-pad-md pb-[22px]\", // 24 / 8 / 22 — sandbox literal\r\n ],\r\n});\r\n","import { useEffect, useState } from \"react\";\r\nimport { Eye, Users, X } from \"lucide-react\";\r\nimport {\r\n Dialog,\r\n DialogContent,\r\n DialogClose,\r\n DialogTitle,\r\n DialogDescription,\r\n} from \"@/components/shadcn/dialog\";\r\nimport { Switch } from \"@/components/shadcn/switch\";\r\nimport { Button } from \"../../Button/button\";\r\nimport { FormFieldInput } from \"../../FormField/form-field-input\";\r\nimport {\r\n dialog,\r\n closeBtn,\r\n head,\r\n headIcon,\r\n headTitleWrap,\r\n title,\r\n sub,\r\n body,\r\n toggleRow,\r\n toggleIcon,\r\n toggleText,\r\n toggleLabel,\r\n toggleDesc,\r\n foot,\r\n} from \"./add-view-modal.styles\";\r\n\r\nexport type AddViewModalSubmit = {\r\n name: string;\r\n isPublic: boolean;\r\n};\r\n\r\nexport type AddViewModalProps = {\r\n /** Controlled open. */\r\n open: boolean;\r\n /** Callback de fechamento (X, ESC, overlay click, ou apos submit). */\r\n onClose: () => void;\r\n /** Disparado quando user clica em Salvar Visao com nome valido. */\r\n onSubmit?: (data: AddViewModalSubmit) => void | Promise<void>;\r\n};\r\n\r\n/**\r\n * Modal \"Adicionar nova visao\" — replica do sandbox /design-and-table-v2.\r\n * Header: icon container (Eye) + titulo + sub + X custom no canto direito.\r\n * Body: campo \"Nome da visao\" + toggle card \"Tornar publica\".\r\n * Footer: Fechar (outline secondary) + Salvar Visao (primary, disabled se nome vazio).\r\n *\r\n * Reseta state ao fechar. Card toggle inteiro eh <label> — click em qualquer\r\n * area liga o Switch. Enter no input dispara submit.\r\n */\r\nexport function AddViewModal({ open, onClose, onSubmit }: AddViewModalProps) {\r\n const [name, setName] = useState(\"\");\r\n const [isPublic, setIsPublic] = useState(false);\r\n\r\n useEffect(() => {\r\n if (!open) {\r\n setName(\"\");\r\n setIsPublic(false);\r\n }\r\n }, [open]);\r\n\r\n const handleSave = async () => {\r\n const trimmed = name.trim();\r\n if (!trimmed) return;\r\n await onSubmit?.({ name: trimmed, isPublic });\r\n onClose();\r\n };\r\n\r\n return (\r\n <Dialog open={open} onOpenChange={(o) => !o && onClose()}>\r\n <DialogContent className={dialog()} hideClose>\r\n <DialogClose className={closeBtn()} aria-label=\"Fechar\">\r\n <X className=\"size-icon-sm\" />\r\n </DialogClose>\r\n\r\n <header className={head()}>\r\n <span className={headIcon()} aria-hidden=\"true\">\r\n <Eye className=\"size-icon-md\" strokeWidth={1.7} />\r\n </span>\r\n <div className={headTitleWrap()}>\r\n <DialogTitle asChild>\r\n <h3 className={title()}>Adicionar nova visão</h3>\r\n </DialogTitle>\r\n <DialogDescription asChild>\r\n <p className={sub()}>\r\n Salve sua configuração atual de filtros e colunas\r\n </p>\r\n </DialogDescription>\r\n </div>\r\n </header>\r\n\r\n <div className={body()}>\r\n <FormFieldInput\r\n label=\"Nome da visão\"\r\n placeholder=\"Ex: Royals em atendimento\"\r\n value={name}\r\n onChange={(e) => setName(e.target.value)}\r\n onKeyDown={(e) => {\r\n if (e.key === \"Enter\") {\r\n e.preventDefault();\r\n handleSave();\r\n }\r\n }}\r\n autoFocus\r\n />\r\n\r\n <label className={toggleRow({ on: isPublic })}>\r\n <span className={toggleIcon({ on: isPublic })} aria-hidden=\"true\">\r\n <Users className=\"size-icon-sm\" />\r\n </span>\r\n <span className={toggleText()}>\r\n <span className={toggleLabel()}>Tornar esta visão pública</span>\r\n <span className={toggleDesc()}>\r\n Outros usuários da sua equipe poderão visualizar e usar esta visão\r\n </span>\r\n </span>\r\n <Switch checked={isPublic} onCheckedChange={setIsPublic} />\r\n </label>\r\n </div>\r\n\r\n <footer className={foot()}>\r\n <Button\r\n color=\"secondary\"\r\n variant=\"outline\"\r\n size=\"md\"\r\n onClick={onClose}\r\n >\r\n Fechar\r\n </Button>\r\n <Button\r\n color=\"primary\"\r\n variant=\"filled\"\r\n size=\"md\"\r\n onClick={handleSave}\r\n disabled={!name.trim()}\r\n >\r\n Salvar Visão\r\n </Button>\r\n </footer>\r\n </DialogContent>\r\n </Dialog>\r\n );\r\n}\r\n","import { useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\r\nimport { Plus } from \"lucide-react\";\r\nimport { ToolbarDivider } from \"./toolbar-divider\";\r\nimport { ToolbarTabs } from \"./toolbar-tabs\";\r\nimport { ToolbarSaveButton } from \"./toolbar-tool-button\";\r\nimport { ViewsPopover, type ViewsPopoverView } from \"../popovers/views-popover\";\r\nimport {\r\n AddViewModal,\r\n type AddViewModalSubmit,\r\n} from \"../popovers/add-view-modal\";\r\nimport { AlertModal } from \"../../AlertModal\";\r\n\r\n/** ID fixo da tab \"Default\" — virtual (nao tem entrada no storage). */\r\nexport const DEFAULT_VIEW_ID = \"__default__\";\r\n\r\nexport type TableToolbarViewsItem = ViewsPopoverView;\r\n\r\nexport type TableToolbarViewsProps = {\r\n /** Lista completa de views salvas (sem Default — esse e injetado internamente). */\r\n views: TableToolbarViewsItem[];\r\n /** ID da view atualmente aplicada. `null`/`undefined` ⇒ tab Default ativa. */\r\n activeViewId?: string | null;\r\n /** Aplicar uma view (click numa tab OU click num item do popover). */\r\n onApply: (id: string) => void;\r\n /** Resetar pra \"Default\" (limpar filtros, sort, cols, density). */\r\n onApplyDefault: () => void;\r\n /**\r\n * Excluir PERMANENTEMENTE uma view do storage. So eh chamado apos\r\n * confirmacao via AlertModal danger — disparado pelo lixinho no popover.\r\n *\r\n * X em tab NAO chama isso (apenas remove da barra — view continua salva).\r\n */\r\n onDelete: (id: string) => void | Promise<void>;\r\n /** Disparado quando user salva uma nova view via modal. */\r\n onSave: (data: AddViewModalSubmit) => void | Promise<void>;\r\n /** Quantas tabs ficam visiveis (incluindo Default). Default 3 — Default + ate 2 views customizadas. */\r\n maxTabs?: number;\r\n /** Key que identifica views \"minhas\" (default `\"me\"`). Controla X em tab e delete no popover. */\r\n myOwnerKey?: string;\r\n /** Slot opcional pra divider antes das tabs (default renderiza um ToolbarDivider). */\r\n divider?: ReactNode;\r\n /** Esconde o divider default — usado quando ja ha um divider adjacente. */\r\n hideDivider?: boolean;\r\n /**\r\n * Permite o usuário criar/salvar novas visões (botão \"+\" / popover de views).\r\n * Default `true`. Passe `false` pra exibir SÓ as visões pré-definidas (sem o\r\n * \"+\") — read-only views.\r\n */\r\n allowCreate?: boolean;\r\n /**\r\n * Label da tab Default **quando ela é a única** (sem nenhuma view pré-definida\r\n * nem salva). Evita a barra \"vazia\" mostrando só \"Default\" — troque por um\r\n * título genérico do contexto (ex: \"Lista de Clientes\"). Default `\"Default\"`.\r\n * Assim que houver ≥ 1 outra view, a tab volta a se chamar \"Default\" pra\r\n * distinguir das views nomeadas.\r\n */\r\n soloLabel?: string;\r\n};\r\n\r\n/**\r\n * TableToolbarViews — **compound component** (smart) de Saved Views.\r\n *\r\n * ⚠️ **Pattern compound smart** — este é um dos POUCOS componentes do TableToolbar\r\n * que mantém estado interno (`tabViewIds`, `addModalOpen`, `confirmDeleteView`).\r\n * É uma exceção consciente ao princípio dumb do toolbar: orquestra 4 filhos\r\n * (ToolbarTabs + ViewsPopover + AddViewModal + AlertModal) como \"bloco pronto\".\r\n *\r\n * **Quando usar este compound**: caso de uso saved views completo (CRM admin).\r\n * **Quando NÃO usar**: se precisar reordenar/customizar a interação entre os\r\n * 4 filhos, COMPONHA OS PARTS DIRETAMENTE — ToolbarTabs + ViewsPopover +\r\n * AddViewModal + AlertModal são exportados standalone pelo TableToolbar. Você\r\n * controla os 4 states (open, deleting, etc) e a ordem visual.\r\n *\r\n * Renderiza no slot esquerdo do TableToolbar:\r\n * 1. ToolbarDivider\r\n * 2. ToolbarTabs com \"Default\" + ate (maxTabs - 1) views como tabs\r\n * - Default sem X (custom: false)\r\n * - Views minhas com X — X apenas remove da barra (view continua salva)\r\n * 3. ViewsPopover via ToolbarSaveButton \"+\"\r\n * - Click no item: pina como tab + aplica + fecha popover\r\n * - Lixinho no item: abre AlertModal danger pra exclusao definitiva\r\n * - Footer \"Salvar visao atual\": abre AddViewModal mode create\r\n * 4. AddViewModal (estado interno) — disparado pelo footer do popover\r\n * 5. AlertModal danger (estado interno) — confirma exclusao definitiva\r\n *\r\n * Distinção crítica:\r\n * - X em tab → unpin (cosmetico, view fica no popover/storage)\r\n * - Lixinho no popover → confirm + delete permanente (chama onDelete)\r\n *\r\n * Comportamento de pin (push-out):\r\n * - `tabViewIds` eh um state local com as view IDs que ocupam slots de tab.\r\n * - Inicializa com as (maxTabs - 1) primeiras views.\r\n * - Click numa view que NAO esta como tab: pina (push out da ultima se cheio).\r\n * - X em tab: remove o ID daqui (sem promover proxima).\r\n * - View deletada permanente: remove o ID daqui (se estiver).\r\n * - View nova criada: anexa se ha slot livre.\r\n * - Re-mount (reload) reseta — pega as N-1 primeiras de novo.\r\n */\r\nexport function TableToolbarViews({\r\n views,\r\n activeViewId,\r\n onApply,\r\n onApplyDefault,\r\n onDelete,\r\n onSave,\r\n maxTabs = 3,\r\n myOwnerKey = \"me\",\r\n divider,\r\n hideDivider,\r\n soloLabel = \"Default\",\r\n allowCreate = true,\r\n}: TableToolbarViewsProps) {\r\n const maxCustomTabs = Math.max(0, maxTabs - 1);\r\n\r\n /* ── State: tabs pinadas (IDs) ─────────────────────────────────── */\r\n\r\n const initialIds = useMemo(\r\n // Auto-pina os presets do DS (owner === \"preset\" — as abas fixas de defaultViews)\r\n // e as views do próprio usuário (owner === myOwnerKey). As públicas de OUTROS\r\n // usuários só viram tab quando explicitamente aplicadas (via activeViewId).\r\n () =>\r\n views\r\n .filter((v) => v.owner === myOwnerKey || v.owner === \"preset\")\r\n .slice(0, maxCustomTabs)\r\n .map((v) => v.id),\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n [],\r\n );\r\n const [tabViewIds, setTabViewIds] = useState<string[]>(initialIds);\r\n\r\n /**\r\n * Aviso em DEV quando há mais visões candidatas a aba do que slots.\r\n *\r\n * O corte é por `.slice(0, maxCustomTabs)` no mount e por `break` no effect de sync —\r\n * **sem nenhum sinal**: a visão simplesmente não aparece. Não há overflow, \"+N\" nem erro.\r\n * Já custou caro: o audit log registra a própria página de doc do `DataTable` declarando\r\n * 3 presets e renderizando 2, com \"Pipeline (Kanban)\" engolido em silêncio — descoberto\r\n * medindo no browser, não lendo o código.\r\n *\r\n * A conta que confunde: `maxTabs` conta a aba **\"Default\"**, que é nativa e virtual. Com o\r\n * default 3, sobram **2** slots pra visão própria — não 3.\r\n *\r\n * Só em dev, e uma vez por combinação (candidatas × slots): este componente re-renderiza a\r\n * cada mudança de filtro/sort, e aviso repetido em console vira aviso ignorado.\r\n */\r\n const avisadoRef = useRef<string | null>(null);\r\n useEffect(() => {\r\n if (!import.meta.env?.DEV) return;\r\n const candidatas = views.filter(\r\n (v) => v.owner === myOwnerKey || v.owner === \"preset\",\r\n );\r\n if (candidatas.length <= maxCustomTabs) return;\r\n const chave = `${candidatas.length}/${maxCustomTabs}`;\r\n if (avisadoRef.current === chave) return;\r\n avisadoRef.current = chave;\r\n // `name` é ReactNode: só serve na mensagem se for string, senão cai no `id`.\r\n // Sem isso, uma view com nome em JSX viraria \"[object Object]\" no aviso — o `tsc`\r\n // aceita (ReactNode entra em array), e o texto sairia lixo.\r\n const cortadas = candidatas\r\n .slice(maxCustomTabs)\r\n .map((v) => (typeof v.name === \"string\" ? v.name : v.id));\r\n console.warn(\r\n `[TableToolbar] ${candidatas.length} visões candidatas a aba e só ${maxCustomTabs} slot(s): ` +\r\n `${cortadas.join(\", \")} não vai(vão) aparecer. ` +\r\n `\\`maxTabs\\` é ${maxTabs} e conta a aba \"Default\" (nativa), então sobram ${maxCustomTabs}. ` +\r\n `Pra mostrar todas, passe maxViewTabs={${candidatas.length + 1}} no <DataTable> (o +1 é a Default).`,\r\n );\r\n }, [views, maxCustomTabs, maxTabs, myOwnerKey]);\r\n\r\n // Sync: quando uma view some, tira do state; quando nova chega, anexa se tem slot\r\n const prevIdsRef = useRef<string[]>(views.map((v) => v.id));\r\n useEffect(() => {\r\n const currentIds = views.map((v) => v.id);\r\n const removedIds = prevIdsRef.current.filter((id) => !currentIds.includes(id));\r\n const addedIds = currentIds.filter((id) => !prevIdsRef.current.includes(id));\r\n prevIdsRef.current = currentIds;\r\n\r\n if (removedIds.length === 0 && addedIds.length === 0) return;\r\n\r\n setTabViewIds((prev) => {\r\n let next = prev.filter((id) => !removedIds.includes(id));\r\n for (const id of addedIds) {\r\n if (next.length >= maxCustomTabs) break;\r\n // Auto-pina presets do DS e views do próprio usuário; públicas de outros não.\r\n const v = views.find((vv) => vv.id === id);\r\n if (v && v.owner !== myOwnerKey && v.owner !== \"preset\") continue;\r\n next = [...next, id];\r\n }\r\n return next;\r\n });\r\n }, [views, maxCustomTabs, myOwnerKey]);\r\n\r\n /* ── State: modal create + popover open + confirm delete ──────── */\r\n\r\n const [addModalOpen, setAddModalOpen] = useState(false);\r\n const [popoverOpen, setPopoverOpen] = useState(false);\r\n const [confirmDeleteView, setConfirmDeleteView] =\r\n useState<TableToolbarViewsItem | null>(null);\r\n\r\n /* ── Tabs effective: Default + views pinadas ────────────────────── */\r\n\r\n const tabs = useMemo(() => {\r\n // Garante que a view ATIVA sempre apareça como tab — mesmo que não esteja\r\n // pinada (ex: reload restaura uma view salva fora das N primeiras, ou a barra\r\n // estava cheia). Sem isso, a tab ativa some e nenhuma fica destacada (a view\r\n // aplicada fica \"invisível\"). Inclusão é só visual (não muta tabViewIds).\r\n const renderIds =\r\n activeViewId &&\r\n activeViewId !== DEFAULT_VIEW_ID &&\r\n !tabViewIds.includes(activeViewId) &&\r\n views.some((v) => v.id === activeViewId)\r\n ? [...tabViewIds, activeViewId]\r\n : tabViewIds;\r\n const customTabs = renderIds\r\n .map((id) => views.find((v) => v.id === id))\r\n .filter((v): v is TableToolbarViewsItem => !!v)\r\n .map((v) => ({\r\n id: v.id,\r\n name: typeof v.name === \"string\" ? v.name : String(v.name),\r\n // Mostra o \"X\" (desfixar/fechar) nas views do usuário E na view pública de\r\n // OUTRO que foi aplicada (o X só desfixa/deseleciona; não deleta a view de\r\n // ninguém). Preset do DS é aba FIXA read-only → nunca mostra X.\r\n custom:\r\n v.owner === myOwnerKey ||\r\n (v.id === activeViewId && v.owner !== \"preset\"),\r\n }));\r\n // Tab Default sozinha (sem views) → label genérico configurável (soloLabel),\r\n // pra barra não ficar com um único \"Default\" solto. Com ≥ 1 outra view,\r\n // volta a \"Default\" pra distinguir das nomeadas.\r\n const defaultName = customTabs.length === 0 ? soloLabel : \"Default\";\r\n return [{ id: DEFAULT_VIEW_ID, name: defaultName, custom: false }, ...customTabs];\r\n }, [tabViewIds, views, myOwnerKey, soloLabel, activeViewId]);\r\n\r\n const effectiveActiveId = activeViewId ?? DEFAULT_VIEW_ID;\r\n\r\n /* ── Handlers ──────────────────────────────────────────────────── */\r\n\r\n const handleTabSelect = (id: string) => {\r\n if (id === DEFAULT_VIEW_ID) {\r\n onApplyDefault();\r\n } else {\r\n onApply(id);\r\n }\r\n };\r\n\r\n /** X em tab — APENAS remove da barra de tabs. Nao deleta a view. */\r\n const handleTabUnpin = (id: string) => {\r\n setTabViewIds((prev) => prev.filter((x) => x !== id));\r\n if (id === activeViewId) onApplyDefault();\r\n };\r\n\r\n /**\r\n * Click no item da lista do popover: pina como tab (push-out da ultima\r\n * se ja estiver cheio) + aplica como ativa + fecha popover.\r\n */\r\n const handlePopoverItemClick = (v: ViewsPopoverView) => {\r\n setTabViewIds((prev) => {\r\n if (prev.includes(v.id)) return prev;\r\n const next = [...prev, v.id];\r\n if (next.length > maxCustomTabs) next.shift();\r\n return next;\r\n });\r\n onApply(v.id);\r\n setPopoverOpen(false);\r\n };\r\n\r\n const handleCreateClick = () => {\r\n setPopoverOpen(false);\r\n setTimeout(() => setAddModalOpen(true), 0);\r\n };\r\n\r\n /** Lixinho na lista do popover — pede confirmacao. */\r\n const handleAskDelete = (id: string) => {\r\n const view = views.find((v) => v.id === id);\r\n if (!view) return;\r\n setConfirmDeleteView(view);\r\n };\r\n\r\n const handleConfirmDelete = async () => {\r\n if (!confirmDeleteView) return;\r\n await onDelete(confirmDeleteView.id);\r\n setConfirmDeleteView(null);\r\n };\r\n\r\n return (\r\n <>\r\n {hideDivider ? null : divider ?? <ToolbarDivider />}\r\n\r\n <ToolbarTabs\r\n tabs={tabs}\r\n activeId={effectiveActiveId}\r\n onSelect={handleTabSelect}\r\n onClose={handleTabUnpin}\r\n ariaLabel=\"Visões salvas\"\r\n />\r\n\r\n {allowCreate && (\r\n <ViewsPopover\r\n open={popoverOpen}\r\n onOpenChange={setPopoverOpen}\r\n trigger={\r\n <ToolbarSaveButton aria-label=\"Visões salvas\">\r\n <Plus strokeWidth={2.4} />\r\n </ToolbarSaveButton>\r\n }\r\n views={views}\r\n activeViewId={activeViewId ?? undefined}\r\n myOwnerKey={myOwnerKey}\r\n onApply={handlePopoverItemClick}\r\n onDelete={handleAskDelete}\r\n onCreate={handleCreateClick}\r\n />\r\n )}\r\n\r\n {allowCreate && (\r\n <AddViewModal\r\n open={addModalOpen}\r\n onClose={() => setAddModalOpen(false)}\r\n onSubmit={onSave}\r\n />\r\n )}\r\n\r\n <AlertModal\r\n tone=\"danger\"\r\n open={!!confirmDeleteView}\r\n onOpenChange={(o) => !o && setConfirmDeleteView(null)}\r\n title=\"Excluir visão\"\r\n description={\r\n confirmDeleteView\r\n ? `Tem certeza que deseja excluir a visão \"${typeof confirmDeleteView.name === \"string\" ? confirmDeleteView.name : String(confirmDeleteView.name)}\"? Esta ação não pode ser desfeita.`\r\n : \"\"\r\n }\r\n confirmLabel=\"Excluir\"\r\n cancelLabel=\"Cancelar\"\r\n onConfirm={handleConfirmDelete}\r\n />\r\n </>\r\n );\r\n}\r\n","/**\r\n * Parser SQL-like — converte texto livre ↔ FilterPopoverEntry[] (round-trip-safe).\r\n *\r\n * Suporta o conjunto COMPLETO de operadores do FilterModel. Operadores\r\n * estruturais (lista/intervalo) usam sintaxe de COLCHETES pra não conflitar com\r\n * o split por AND/OR (colchetes nunca contêm ` AND `/` OR ` solto):\r\n *\r\n * field = value → equals field != value → neq\r\n * field contains value → contains field not contains v → notContains\r\n * field starts with value → startsWith field ends with value → endsWith\r\n * field > value → gt field < value → lt\r\n * field >= value → gte field <= value → lte\r\n * field is empty → isEmpty field is not empty → isNotEmpty\r\n * field in [a, b, c] → isAnyOf field not in [a, b, c] → isNoneOf\r\n * field between [x, y] → between\r\n *\r\n * Logical: AND, OR (case-insensitive, um único conector). Sem parênteses/nested.\r\n */\r\n\r\nexport type ParsedFilterOp =\r\n | \"equals\"\r\n | \"neq\"\r\n | \"contains\"\r\n | \"notContains\"\r\n | \"startsWith\"\r\n | \"endsWith\"\r\n | \"gt\"\r\n | \"lt\"\r\n | \"gte\"\r\n | \"lte\"\r\n | \"isEmpty\"\r\n | \"isNotEmpty\"\r\n | \"isAnyOf\"\r\n | \"isNoneOf\"\r\n | \"between\";\r\n\r\nexport type ParsedFilterEntry = {\r\n field: string;\r\n op: ParsedFilterOp;\r\n /** string pros ops escalares; string[] pros estruturais (in/not in/between). */\r\n value: string | string[];\r\n};\r\n\r\nexport type ParseResult =\r\n | { ok: true; entries: ParsedFilterEntry[]; logicOperator: \"AND\" | \"OR\" }\r\n | { ok: false; error: string };\r\n\r\nfunction unquote(s: string): string {\r\n const t = s.trim();\r\n if (\r\n (t.startsWith('\"') && t.endsWith('\"')) ||\r\n (t.startsWith(\"'\") && t.endsWith(\"'\"))\r\n ) {\r\n return t.slice(1, -1);\r\n }\r\n return t;\r\n}\r\n\r\n/** Parseia uma lista entre colchetes `[a, \"b c\", 'd']` → string[] (unquoted). */\r\nfunction parseList(raw: string): string[] | null {\r\n const t = raw.trim();\r\n if (!t.startsWith(\"[\") || !t.endsWith(\"]\")) return null;\r\n const inner = t.slice(1, -1).trim();\r\n if (!inner) return [];\r\n // split por vírgula respeitando aspas simples\r\n const out: string[] = [];\r\n let buf = \"\";\r\n let quote: '\"' | \"'\" | null = null;\r\n for (const ch of inner) {\r\n if (quote) {\r\n if (ch === quote) quote = null;\r\n else buf += ch;\r\n } else if (ch === '\"' || ch === \"'\") {\r\n quote = ch;\r\n } else if (ch === \",\") {\r\n out.push(buf.trim());\r\n buf = \"\";\r\n } else {\r\n buf += ch;\r\n }\r\n }\r\n if (buf.trim()) out.push(buf.trim());\r\n return out.map((v) => v.trim());\r\n}\r\n\r\n/**\r\n * Tenta casar um operador no início de `rest` (já sem o field). Retorna o op +\r\n * o restante (value bruto), ou null se nenhum operador casou. Ordem importa:\r\n * frases mais específicas/longas primeiro.\r\n */\r\nfunction matchOperator(\r\n rest: string,\r\n): { op: ParsedFilterOp; rawValue: string } | null {\r\n const r = rest.trim();\r\n const lower = r.toLowerCase();\r\n\r\n // No-value (frase completa, value vazio)\r\n if (lower === \"is not empty\") return { op: \"isNotEmpty\", rawValue: \"\" };\r\n if (lower === \"is empty\") return { op: \"isEmpty\", rawValue: \"\" };\r\n\r\n // Multi-palavra com value\r\n const phrase: Array<[RegExp, ParsedFilterOp]> = [\r\n [/^not\\s+in\\b/i, \"isNoneOf\"],\r\n [/^in\\b/i, \"isAnyOf\"],\r\n [/^between\\b/i, \"between\"],\r\n [/^not\\s+contains\\b/i, \"notContains\"],\r\n [/^starts\\s+with\\b/i, \"startsWith\"],\r\n [/^ends\\s+with\\b/i, \"endsWith\"],\r\n [/^contains\\b/i, \"contains\"],\r\n [/^like\\b/i, \"contains\"],\r\n ];\r\n for (const [re, op] of phrase) {\r\n const m = r.match(re);\r\n if (m) return { op, rawValue: r.slice(m[0].length).trim() };\r\n }\r\n\r\n // Símbolos (sem precisar de espaço)\r\n const sym: Array<[string, ParsedFilterOp]> = [\r\n [\">=\", \"gte\"],\r\n [\"<=\", \"lte\"],\r\n [\"!=\", \"neq\"],\r\n [\"<>\", \"neq\"],\r\n [\"==\", \"equals\"],\r\n [\"=\", \"equals\"],\r\n [\">\", \"gt\"],\r\n [\"<\", \"lt\"],\r\n ];\r\n for (const [symbol, op] of sym) {\r\n if (r.startsWith(symbol)) {\r\n return { op, rawValue: r.slice(symbol.length).trim() };\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nconst LIST_OPS = new Set<ParsedFilterOp>([\"isAnyOf\", \"isNoneOf\", \"between\"]);\r\nconst NO_VALUE_OPS = new Set<ParsedFilterOp>([\"isEmpty\", \"isNotEmpty\"]);\r\n\r\nexport function parseSqlFilter(input: string): ParseResult {\r\n const trimmed = input\r\n .split(\"\\n\")\r\n .map((l) => l.trim())\r\n .filter((l) => l && !l.startsWith(\"#\") && !l.startsWith(\"--\"))\r\n .join(\" \")\r\n .trim();\r\n if (!trimmed) return { ok: true, entries: [], logicOperator: \"AND\" };\r\n\r\n const logicMatch = trimmed.match(/\\s(AND|OR)\\s/i);\r\n const logicOperator: \"AND\" | \"OR\" =\r\n logicMatch?.[1]?.toUpperCase() === \"OR\" ? \"OR\" : \"AND\";\r\n\r\n const parts = trimmed\r\n .split(/\\s+(?:AND|OR)\\s+/i)\r\n .map((p) => p.trim())\r\n .filter(Boolean);\r\n\r\n const entries: ParsedFilterEntry[] = [];\r\n for (const part of parts) {\r\n // field = primeiro token (sem espaço); pode ter dots (user.name)\r\n const fm = part.match(/^(\\S+)\\s*(.*)$/s);\r\n const field = fm?.[1]?.trim();\r\n if (!field) {\r\n return { ok: false, error: `Campo ausente em \"${part}\".` };\r\n }\r\n const matched = matchOperator(fm![2]);\r\n if (!matched) {\r\n return {\r\n ok: false,\r\n error: `Sem operador válido em \"${part}\". Use =, !=, >, contains, in [..], between [..], is empty, etc.`,\r\n };\r\n }\r\n const { op, rawValue } = matched;\r\n\r\n if (NO_VALUE_OPS.has(op)) {\r\n entries.push({ field, op, value: \"\" });\r\n continue;\r\n }\r\n if (LIST_OPS.has(op)) {\r\n const list = parseList(rawValue);\r\n if (!list) {\r\n return {\r\n ok: false,\r\n error: `\"${op}\" espera lista entre colchetes em \"${part}\" (ex: in [a, b]).`,\r\n };\r\n }\r\n entries.push({ field, op, value: list });\r\n continue;\r\n }\r\n const value = unquote(rawValue);\r\n if (!value) {\r\n return { ok: false, error: `Valor ausente em \"${part}\".` };\r\n }\r\n entries.push({ field, op, value });\r\n }\r\n\r\n return { ok: true, entries, logicOperator };\r\n}\r\n\r\n/* ── Serialização (FilterPopoverEntry → texto) ───────────────────── */\r\n\r\nconst SYMBOL_OP: Partial<Record<ParsedFilterOp, string>> = {\r\n equals: \"=\",\r\n neq: \"!=\",\r\n gt: \">\",\r\n lt: \"<\",\r\n gte: \">=\",\r\n lte: \"<=\",\r\n};\r\nconst PHRASE_OP: Partial<Record<ParsedFilterOp, string>> = {\r\n contains: \"contains\",\r\n notContains: \"not contains\",\r\n startsWith: \"starts with\",\r\n endsWith: \"ends with\",\r\n};\r\n\r\n/** Aspas se o valor tem espaço/aspas/vírgula. */\r\nfunction quoteIfNeeded(v: string): string {\r\n return /[\\s\",[\\]]/.test(v) ? `\"${v.replace(/\"/g, '\\\\\"')}\"` : v;\r\n}\r\n\r\nfunction serializeList(value: string | string[]): string {\r\n const arr = Array.isArray(value) ? value : value === \"\" ? [] : [value];\r\n return `[${arr.map((v) => quoteIfNeeded(String(v))).join(\", \")}]`;\r\n}\r\n\r\n/** Converte FilterPopoverEntry[] de volta pra string SQL-like (round-trip). */\r\nexport function entriesToSql(\r\n entries: ParsedFilterEntry[],\r\n logicOperator: \"AND\" | \"OR\" = \"AND\",\r\n): string {\r\n return entries\r\n .map((e) => {\r\n if (e.op === \"isEmpty\") return `${e.field} is empty`;\r\n if (e.op === \"isNotEmpty\") return `${e.field} is not empty`;\r\n if (e.op === \"isAnyOf\") return `${e.field} in ${serializeList(e.value)}`;\r\n if (e.op === \"isNoneOf\")\r\n return `${e.field} not in ${serializeList(e.value)}`;\r\n if (e.op === \"between\")\r\n return `${e.field} between ${serializeList(e.value)}`;\r\n\r\n const v = quoteIfNeeded(String(Array.isArray(e.value) ? e.value.join(\",\") : e.value));\r\n const sym = SYMBOL_OP[e.op];\r\n if (sym) return `${e.field} ${sym} ${v}`;\r\n const phrase = PHRASE_OP[e.op];\r\n return `${e.field} ${phrase ?? \"contains\"} ${v}`;\r\n })\r\n .join(` ${logicOperator} `);\r\n}\r\n","import { useEffect, useRef, useState, type ReactNode } from \"react\";\r\nimport { ChevronLeft, Filter, Plus, Trash2 } from \"lucide-react\";\r\nimport {\r\n Popover,\r\n PopoverAnchor,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/shadcn/popover\";\r\nimport { parseSqlFilter, entriesToSql, type ParsedFilterEntry } from \"./filter-sql-parser\";\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from \"@/components/shadcn/select\";\r\nimport { Button } from \"../../Button/button\";\r\nimport { Combobox } from \"../../Combobox\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\n/* ── Types ────────────────────────────────────────────────────────── */\r\nexport type FilterPopoverColumn = {\r\n key: string;\r\n /** Label da coluna (exibido no select) */\r\n label: string;\r\n /** Tipo do valor — define o input renderizado. Default `\"text\"`. */\r\n type?: \"text\" | \"number\" | \"select\";\r\n /** Opções pro select (quando `type=\"select\"`) */\r\n options?: Array<{ value: string; label: string }>;\r\n /** Tipo original do ColumnTypeRegistry (date, currency, etc) — opcional,\r\n * passado pelo DataTable pra `renderValueInput` resolver o input correto. */\r\n filterType?: string;\r\n};\r\n\r\nexport type FilterPopoverOperator = {\r\n id: string;\r\n label: string;\r\n};\r\n\r\nexport type FilterPopoverEntry = {\r\n id: string;\r\n columnKey: string;\r\n op: string;\r\n /** Valor do filtro — `unknown` pra carregar string, array (multiSelect/tags),\r\n * tupla (between/date range), número, etc. Native fallback rendering coage\r\n * pra string via toString; `renderValueInput` recebe o valor puro. */\r\n value: unknown;\r\n};\r\n\r\nexport const DEFAULT_FILTER_OPERATORS: FilterPopoverOperator[] = [\r\n { id: \"equals\", label: \"é\" },\r\n { id: \"neq\", label: \"não é\" },\r\n { id: \"contains\", label: \"contém\" },\r\n { id: \"gt\", label: \"maior que\" },\r\n { id: \"lt\", label: \"menor que\" },\r\n { id: \"isAnyOf\", label: \"é um de\" },\r\n { id: \"isNoneOf\", label: \"não é\" },\r\n { id: \"between\", label: \"entre\" },\r\n { id: \"isEmpty\", label: \"está vazio\" },\r\n { id: \"isNotEmpty\", label: \"não está vazio\" },\r\n];\r\n\r\nfunction generateId(): string {\r\n if (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto) {\r\n return crypto.randomUUID();\r\n }\r\n return `f_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\r\n}\r\n\r\n/** Filter row tem valor real preenchido?\r\n * - String vazia, null, array vazio/só nulls = vazio (pula)\r\n * - Operadores isEmpty/isNotEmpty não precisam de valor (sempre ativos) */\r\nexport function isFilterEntryActive(entry: FilterPopoverEntry): boolean {\r\n if (entry.op === \"isEmpty\" || entry.op === \"isNotEmpty\") return true;\r\n const v = entry.value;\r\n if (v == null) return false;\r\n if (typeof v === \"string\") return v.length > 0;\r\n if (Array.isArray(v)) {\r\n return v.some((x) => x != null && (typeof x === \"string\" ? x.length > 0 : true));\r\n }\r\n return true;\r\n}\r\n\r\n/* ── Filter Row Editor ───────────────────────────────────────────── */\r\ntype FilterRowEditorProps = {\r\n filter: FilterPopoverEntry;\r\n index: number;\r\n columns: FilterPopoverColumn[];\r\n operators: FilterPopoverOperator[];\r\n conjLabels: { first: ReactNode; rest: ReactNode };\r\n onChange: (next: FilterPopoverEntry) => void;\r\n onRemove: () => void;\r\n /** Override do input de valor — passado da prop top-level pra delegar\r\n * ao consumer (que conhece o tipo via registry). Quando undefined, usa\r\n * fallback nativo (select/number/text). */\r\n renderValueInput?: FilterPanelProps[\"renderValueInput\"];\r\n /** Quando true, o Select \"Campo\" abre o dropdown imediatamente no mount\r\n * (usado pelo \"Adicionar condição\" pra o user escolher coluna sem clique\r\n * extra). */\r\n autoOpenField?: boolean;\r\n /** Resolve operators do column-type da nova coluna ao trocar o Campo. */\r\n getOperatorsForColumn?: (column: FilterPopoverColumn) => FilterPopoverOperator[] | undefined;\r\n};\r\n\r\n/**\r\n * Classes compartilhadas pra trigger/input — mesma altura, padding e box-sizing\r\n * pra evitar resize visual entre os campos.\r\n */\r\nconst FIELD_BASE = cn(\r\n \"min-h-form-md h-form-md min-w-0 w-full\",\r\n \"rounded-radius-md\",\r\n \"text-body-sm font-normal\",\r\n);\r\n\r\nconst INPUT_FIELD = cn(\r\n FIELD_BASE,\r\n \"px-pad-xl\",\r\n \"bg-bg-input dark:bg-bg-muted\",\r\n \"border border-border-input text-fg-default\",\r\n \"placeholder:text-fg-muted outline-none\",\r\n \"transition-[border-color,box-shadow] duration-150\",\r\n \"focus:border-border-brand focus:shadow-sh-ring\",\r\n);\r\n\r\nfunction FilterRowEditor({\r\n filter,\r\n index,\r\n columns,\r\n operators,\r\n conjLabels,\r\n onChange,\r\n onRemove,\r\n renderValueInput,\r\n autoOpenField,\r\n getOperatorsForColumn,\r\n}: FilterRowEditorProps) {\r\n const col = columns.find((c) => c.key === filter.columnKey);\r\n const isSelect = col?.type === \"select\";\r\n const inputType = col?.type === \"number\" ? \"number\" : \"text\";\r\n // Defensive: se filter.op não está nos operators do column atual, faz FALLBACK\r\n // pro primeiro operator disponível. Sem isso, o Select de operador renderiza\r\n // VAZIO. Também propaga a normalização via useEffect.\r\n const opValid = operators.some((o) => o.id === filter.op);\r\n const effectiveOp = opValid ? filter.op : (operators[0]?.id ?? filter.op);\r\n useEffect(() => {\r\n if (!opValid && effectiveOp !== filter.op) {\r\n onChange({ ...filter, op: effectiveOp });\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [opValid, effectiveOp, filter.id]);\r\n // Quando consumer passa renderValueInput, delega 100% (registry-aware).\r\n const customValueInput =\r\n renderValueInput && col\r\n ? renderValueInput({\r\n column: col,\r\n operator: filter.op,\r\n value: filter.value,\r\n onChange: (v) => onChange({ ...filter, value: v }),\r\n })\r\n : null;\r\n // Coerce pra string só pro native fallback (select/input).\r\n const stringValue =\r\n typeof filter.value === \"string\"\r\n ? filter.value\r\n : filter.value == null\r\n ? \"\"\r\n : String(filter.value);\r\n\r\n return (\r\n <div\r\n className={cn(\r\n // Mobile: vertical (1 select por linha). sm+: horizontal alinhado.\r\n \"flex flex-col sm:flex-row sm:items-center gap-gp-md\",\r\n )}\r\n >\r\n <span className=\"text-caption-sm text-fg-muted shrink-0 sm:w-[18px] sm:text-center\">\r\n {index === 0 ? conjLabels.first : conjLabels.rest}\r\n </span>\r\n {/* Campo (flex 1) — Combobox: lista de colunas pode ser longa (ex.: ~30 em\r\n MAPACLIENTES), então precisa de busca (autocomplete) + scroll. */}\r\n <div className=\"w-full sm:flex-[1_1_0%] sm:basis-0 min-w-0\">\r\n <Combobox\r\n value={filter.columnKey}\r\n defaultOpen={autoOpenField}\r\n options={columns.map((c) => ({ value: c.key, label: c.label }))}\r\n onValueChange={(v) => {\r\n const newCol = columns.find((c) => c.key === v);\r\n const newOperators =\r\n (newCol && getOperatorsForColumn?.(newCol)) ?? operators;\r\n const opValid = newOperators.some((o) => o.id === filter.op);\r\n const nextOp = opValid ? filter.op : (newOperators[0]?.id ?? filter.op);\r\n onChange({ ...filter, columnKey: v, op: nextOp, value: \"\" });\r\n }}\r\n className={cn(FIELD_BASE, \"px-pad-xl gap-gp-md\")}\r\n align=\"start\"\r\n aria-label=\"Campo\"\r\n searchPlaceholder=\"Buscar campo…\"\r\n emptyMessage=\"Nenhum campo\"\r\n />\r\n </div>\r\n {/* Operador (flex 0.7 em desktop — menor, dá mais espaço pro valor) */}\r\n <div className=\"w-full sm:flex-[0.7_1_0%] sm:basis-0 min-w-0 sm:min-w-[80px]\">\r\n <Select\r\n value={effectiveOp}\r\n onValueChange={(v) => onChange({ ...filter, op: v })}\r\n >\r\n <SelectTrigger\r\n className={cn(FIELD_BASE, \"px-pad-xl gap-gp-md\")}\r\n aria-label=\"Operador\"\r\n >\r\n <SelectValue />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {operators.map((o) => (\r\n <SelectItem key={o.id} value={o.id}>\r\n {o.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n </div>\r\n {/* Valor (flex 1.3 — maior em desktop). */}\r\n <div className=\"w-full sm:flex-[1.3_1_0%] sm:basis-0 min-w-0\">\r\n {customValueInput ? (\r\n customValueInput\r\n ) : isSelect ? (\r\n <Select\r\n value={stringValue}\r\n onValueChange={(v) => onChange({ ...filter, value: v })}\r\n >\r\n <SelectTrigger\r\n className={cn(FIELD_BASE, \"px-pad-xl gap-gp-md\")}\r\n aria-label=\"Valor\"\r\n >\r\n <SelectValue placeholder=\"Selecione…\" />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {col!.options?.map((o) => (\r\n <SelectItem key={o.value} value={o.value}>\r\n {o.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n ) : (\r\n <input\r\n type={inputType}\r\n value={stringValue}\r\n onChange={(e) => onChange({ ...filter, value: e.target.value })}\r\n placeholder=\"Valor\"\r\n aria-label=\"Valor\"\r\n className={INPUT_FIELD}\r\n />\r\n )}\r\n </div>\r\n {/* Remover (Button do DS, mesma altura do input). */}\r\n <Button\r\n color=\"secondary\"\r\n variant=\"ghost\"\r\n size=\"icon-sm\"\r\n aria-label=\"Remover condição\"\r\n onClick={onRemove}\r\n className=\"shrink-0 self-end sm:self-auto hover:bg-bg-danger-muted hover:text-fg-danger focus-visible:bg-bg-muted\"\r\n >\r\n <Trash2 strokeWidth={1.8} />\r\n </Button>\r\n </div>\r\n );\r\n}\r\n\r\n/* ── Panel (miolo reutilizável) ──────────────────────────────────────\r\n * Query builder Visual/Avançado extraído do PopoverContent pra reuso no\r\n * `FilterPopover` (standalone) e no `ToolbarSettingsMenu` (drill-down).\r\n * Mantém o state do builder (mode/advancedText/pendingOpenFieldId).\r\n * `onBack` opcional → chevron de voltar no header. */\r\nexport type FilterPanelProps = {\r\n columns: FilterPopoverColumn[];\r\n operators?: FilterPopoverOperator[];\r\n filters: FilterPopoverEntry[];\r\n onFiltersChange: (next: FilterPopoverEntry[]) => void;\r\n enableAdvanced?: boolean;\r\n title?: ReactNode;\r\n conjLabels?: { first: ReactNode; rest: ReactNode };\r\n renderValueInput?: (params: {\r\n column: FilterPopoverColumn;\r\n operator: string;\r\n value: unknown;\r\n onChange: (next: unknown) => void;\r\n }) => ReactNode;\r\n getOperatorsForColumn?: (column: FilterPopoverColumn) => FilterPopoverOperator[] | undefined;\r\n /** Quando passado, renderiza o botão \"voltar\" no header (drill-down). */\r\n onBack?: () => void;\r\n};\r\n\r\nexport function FilterPanel({\r\n columns,\r\n operators = DEFAULT_FILTER_OPERATORS,\r\n filters,\r\n onFiltersChange,\r\n enableAdvanced,\r\n title = \"Filtros\",\r\n conjLabels = { first: \"Se\", rest: \"E\" },\r\n renderValueInput,\r\n getOperatorsForColumn,\r\n onBack,\r\n}: FilterPanelProps) {\r\n const [mode, setMode] = useState<\"visual\" | \"advanced\">(\"visual\");\r\n const [advancedText, setAdvancedText] = useState(\"\");\r\n const [advancedError, setAdvancedError] = useState<string | null>(null);\r\n // ID do último row adicionado via \"Adicionar condição\" — usado pra abrir o\r\n // Select de Campo automaticamente. Reset após 1 render via useEffect.\r\n const [pendingOpenFieldId, setPendingOpenFieldId] = useState<string | null>(null);\r\n useEffect(() => {\r\n if (pendingOpenFieldId == null) return;\r\n const t = setTimeout(() => setPendingOpenFieldId(null), 0);\r\n return () => clearTimeout(t);\r\n }, [pendingOpenFieldId]);\r\n\r\n // Purge de linhas em branco ao DESMONTAR o painel — fonte única de limpeza.\r\n // O FilterPanel só vive enquanto o filtro avançado está aberto: fechar o\r\n // popover, fechar o settings menu ou voltar pro nível root desmonta o painel.\r\n // Aí removemos toda entry sem valor real (user clicou \"+ Adicionar\" e não\r\n // preencheu) pra não poluir o filterModel nem ativar o indicador \"verde\".\r\n // Latest-ref (L-028): lê filters/onFiltersChange no unmount-time, sem stale.\r\n const latestRef = useRef({ filters, onFiltersChange });\r\n latestRef.current = { filters, onFiltersChange };\r\n useEffect(() => {\r\n return () => {\r\n const { filters: cur, onFiltersChange: change } = latestRef.current;\r\n const active = cur.filter(isFilterEntryActive);\r\n if (active.length !== cur.length) change(active);\r\n };\r\n }, []);\r\n\r\n // Quando entra no modo advanced, hidrata textarea com filters atuais\r\n useEffect(() => {\r\n if (mode === \"advanced\") {\r\n setAdvancedText(\r\n entriesToSql(\r\n filters.map((f) => ({\r\n field: f.columnKey,\r\n op: f.op as ParsedFilterEntry[\"op\"],\r\n // value bruto (string | array) — entriesToSql serializa listas/tuplas\r\n // como `[a, b]` pros ops estruturais (round-trip-safe).\r\n value: Array.isArray(f.value)\r\n ? (f.value as string[]).map((v) => String(v))\r\n : f.value == null\r\n ? \"\"\r\n : String(f.value),\r\n })),\r\n \"AND\",\r\n ),\r\n );\r\n setAdvancedError(null);\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [mode]);\r\n\r\n const validCount = filters.filter((f) => f.value).length;\r\n\r\n const updateRow = (id: string, next: FilterPopoverEntry) =>\r\n onFiltersChange(filters.map((f) => (f.id === id ? next : f)));\r\n\r\n const removeRow = (id: string) =>\r\n onFiltersChange(filters.filter((f) => f.id !== id));\r\n\r\n const addRow = () => {\r\n const firstCol = columns[0];\r\n if (!firstCol) return;\r\n const colOperators = getOperatorsForColumn?.(firstCol) ?? operators;\r\n const newRow: FilterPopoverEntry = {\r\n id: generateId(),\r\n columnKey: firstCol.key,\r\n op: colOperators[0]?.id ?? \"equals\",\r\n value: \"\",\r\n };\r\n onFiltersChange([newRow, ...filters]);\r\n setPendingOpenFieldId(newRow.id);\r\n };\r\n\r\n const clearAll = () => onFiltersChange([]);\r\n\r\n /** Aplica o textarea SQL — parseia e converte em FilterPopoverEntry[]. */\r\n const applyAdvanced = () => {\r\n const result = parseSqlFilter(advancedText);\r\n if (!result.ok) {\r\n setAdvancedError(result.error);\r\n return;\r\n }\r\n setAdvancedError(null);\r\n const validKeys = new Set(columns.map((c) => c.key));\r\n const valid = result.entries.filter((e) => validKeys.has(e.field));\r\n const invalid = result.entries.filter((e) => !validKeys.has(e.field));\r\n if (invalid.length > 0) {\r\n setAdvancedError(\r\n `Campos desconhecidos: ${invalid.map((e) => e.field).join(\", \")}`,\r\n );\r\n return;\r\n }\r\n onFiltersChange(\r\n valid.map((e) => ({\r\n id: generateId(),\r\n columnKey: e.field,\r\n op: e.op,\r\n value: e.value,\r\n })),\r\n );\r\n setMode(\"visual\");\r\n };\r\n\r\n return (\r\n <>\r\n {/* Header com tabs */}\r\n <div className=\"flex-none flex items-center justify-between gap-gp-md px-pad-xl py-pad-lg border-b border-border-default\">\r\n <div className=\"flex items-center gap-gp-md min-w-0\">\r\n {onBack && (\r\n <button\r\n type=\"button\"\r\n onClick={onBack}\r\n aria-label=\"Voltar\"\r\n className=\"grid place-items-center size-[20px] -ml-[2px] shrink-0 rounded-radius-sm bg-transparent text-fg-muted cursor-pointer outline-none hover:bg-bg-muted hover:text-fg-default focus-visible:bg-bg-muted [&_svg]:size-[16px]\"\r\n >\r\n <ChevronLeft strokeWidth={2.2} />\r\n </button>\r\n )}\r\n <h3 className=\"text-caption-sm font-semibold text-fg-muted uppercase tracking-wide leading-none m-0\">\r\n {title}\r\n </h3>\r\n </div>\r\n {enableAdvanced && (\r\n <div\r\n role=\"tablist\"\r\n className=\"inline-flex items-center gap-[2px] p-[2px] bg-bg-muted rounded-radius-md h-[34px]\"\r\n >\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n aria-selected={mode === \"visual\"}\r\n onClick={() => setMode(\"visual\")}\r\n className={cn(\r\n \"h-[30px] px-pad-lg rounded-radius-sm text-body-xs font-medium cursor-pointer outline-none focus-visible:shadow-sh-ring\",\r\n \"transition-[background-color,color,box-shadow] duration-150\",\r\n mode === \"visual\"\r\n ? \"bg-bg-accent text-fg-default font-semibold shadow-sh-sm\"\r\n : \"bg-transparent text-fg-muted hover:text-fg-default\",\r\n )}\r\n >\r\n Visual\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n aria-selected={mode === \"advanced\"}\r\n onClick={() => setMode(\"advanced\")}\r\n className={cn(\r\n \"h-[30px] px-pad-lg rounded-radius-sm text-body-xs font-medium cursor-pointer outline-none focus-visible:shadow-sh-ring\",\r\n \"transition-[background-color,color,box-shadow] duration-150\",\r\n mode === \"advanced\"\r\n ? \"bg-bg-accent text-fg-default font-semibold shadow-sh-sm\"\r\n : \"bg-transparent text-fg-muted hover:text-fg-default\",\r\n )}\r\n >\r\n Avançado\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Body */}\r\n {mode === \"visual\" ? (\r\n filters.length === 0 ? (\r\n <div className=\"flex flex-col items-center justify-center text-center px-pad-2xl py-pad-4xl\">\r\n <Filter\r\n strokeWidth={1.6}\r\n className=\"size-[20px] text-fg-muted mb-pad-xl\"\r\n />\r\n <p className=\"text-body-sm font-semibold text-fg-default m-0\">\r\n Nenhuma condição\r\n </p>\r\n <p className=\"text-body-xs font-normal text-fg-muted m-0 mt-pad-2xs mb-pad-2xl\">\r\n Adicione filtros pra refinar a lista.\r\n </p>\r\n <button\r\n type=\"button\"\r\n onClick={addRow}\r\n className={cn(\r\n \"inline-flex items-center gap-gp-sm h-form-md px-pad-2xl rounded-radius-lg\",\r\n \"bg-bg-brand text-fg-on-brand\",\r\n \"text-body-sm font-semibold cursor-pointer outline-none\",\r\n \"transition-[background-color] duration-150\",\r\n \"hover:bg-bg-brand-hover focus-visible:shadow-sh-ring\",\r\n \"[&_svg]:size-[14px]\",\r\n )}\r\n >\r\n <Plus strokeWidth={2.4} />\r\n Adicionar condição\r\n </button>\r\n </div>\r\n ) : (\r\n <>\r\n {/* List scrollable */}\r\n <div\r\n className={cn(\r\n \"flex-1 min-h-0 overflow-y-auto\",\r\n \"[scrollbar-width:thin] [scrollbar-color:var(--color-border-default)_transparent]\",\r\n \"[&::-webkit-scrollbar]:w-[6px]\",\r\n \"[&::-webkit-scrollbar-thumb]:bg-border-default [&::-webkit-scrollbar-thumb]:rounded-full\",\r\n \"[&::-webkit-scrollbar-track]:bg-transparent\",\r\n )}\r\n >\r\n <div className=\"flex flex-col gap-gp-2xl sm:gap-gp-md p-pad-xl\">\r\n {filters.map((f, i) => {\r\n const col = columns.find((c) => c.key === f.columnKey);\r\n const rowOperators =\r\n (col && getOperatorsForColumn?.(col)) ?? operators;\r\n return (\r\n <FilterRowEditor\r\n key={f.id}\r\n filter={f}\r\n index={i}\r\n columns={columns}\r\n operators={rowOperators}\r\n conjLabels={conjLabels}\r\n onChange={(next) => updateRow(f.id, next)}\r\n onRemove={() => removeRow(f.id)}\r\n renderValueInput={renderValueInput}\r\n autoOpenField={pendingOpenFieldId === f.id}\r\n getOperatorsForColumn={getOperatorsForColumn}\r\n />\r\n );\r\n })}\r\n </div>\r\n </div>\r\n {/* Add button — fora do scroll, full-width, dashed */}\r\n <div className=\"flex-none px-pad-xl pb-pad-xl pt-0\">\r\n <button\r\n type=\"button\"\r\n onClick={addRow}\r\n className={cn(\r\n \"flex items-center justify-center gap-gp-sm w-full\",\r\n \"min-h-form-md px-pad-xl rounded-radius-md\",\r\n \"bg-transparent text-fg-muted\",\r\n \"border border-dashed border-border-default\",\r\n \"text-body-sm font-medium cursor-pointer outline-none\",\r\n \"transition-[background-color,color,border-color] duration-150\",\r\n \"hover:bg-bg-muted hover:text-fg-default hover:border-border-default\",\r\n \"focus-visible:bg-bg-muted focus-visible:text-fg-default\",\r\n \"[&_svg]:size-[14px]\",\r\n )}\r\n >\r\n <Plus strokeWidth={2.2} />\r\n Adicionar condição\r\n </button>\r\n </div>\r\n </>\r\n )\r\n ) : (\r\n <div className=\"flex-1 min-h-0 flex flex-col gap-gp-md p-pad-xl overflow-y-auto\">\r\n <span className=\"text-caption-sm text-fg-muted\">\r\n Editor livre — sintaxe estilo SQL. Operadores: <code>=</code>{\" \"}\r\n <code>!=</code> <code>></code> <code><</code>{\" \"}\r\n <code>contains</code>. Conectores: <code>AND</code>{\" \"}\r\n <code>OR</code>.\r\n </span>\r\n <textarea\r\n spellCheck={false}\r\n value={advancedText}\r\n onChange={(e) => {\r\n setAdvancedText(e.target.value);\r\n setAdvancedError(null);\r\n }}\r\n rows={8}\r\n placeholder={`-- Ex:\\nstatus = \"active\"\\nAND value > 1000`}\r\n className={cn(\r\n \"w-full px-pad-xl py-pad-md rounded-radius-md\",\r\n \"bg-bg-input dark:bg-bg-muted\",\r\n \"border\",\r\n advancedError ? \"border-border-danger-muted\" : \"border-border-input\",\r\n \"text-body-xs font-normal font-mono text-fg-default placeholder:text-fg-muted\",\r\n \"outline-none resize-y\",\r\n \"transition-[border-color,box-shadow] duration-150\",\r\n advancedError\r\n ? \"focus:border-border-danger-muted focus:shadow-sh-ring-danger\"\r\n : \"focus:border-border-brand focus:shadow-sh-ring\",\r\n )}\r\n />\r\n {advancedError && (\r\n <p className=\"text-caption-sm text-fg-danger\">\r\n {advancedError}\r\n </p>\r\n )}\r\n <button\r\n type=\"button\"\r\n onClick={applyAdvanced}\r\n className={cn(\r\n \"self-end px-pad-xl h-form-md rounded-radius-md\",\r\n \"bg-bg-brand text-fg-on-brand\",\r\n \"text-body-xs font-semibold\",\r\n \"hover:bg-bg-brand-hover focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand\",\r\n \"transition-[background-color,box-shadow] duration-150\",\r\n )}\r\n >\r\n Aplicar\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Footer */}\r\n <div className=\"flex-none flex items-center justify-between gap-gp-md px-pad-xl min-h-[44px] border-t border-border-default\">\r\n <button\r\n type=\"button\"\r\n onClick={clearAll}\r\n disabled={filters.length === 0}\r\n className={cn(\r\n \"text-body-xs font-medium text-fg-brand bg-transparent border-0 p-0 cursor-pointer outline-none\",\r\n \"hover:underline focus-visible:underline underline-offset-2\",\r\n \"disabled:opacity-50 disabled:pointer-events-none disabled:no-underline\",\r\n )}\r\n >\r\n Limpar todos\r\n </button>\r\n <span className=\"text-caption-sm text-fg-muted\">\r\n {validCount === 0\r\n ? \"Nenhum filtro ativo\"\r\n : `${validCount} ${\r\n validCount > 1 ? \"condições ativas\" : \"condição ativa\"\r\n }`}\r\n </span>\r\n </div>\r\n </>\r\n );\r\n}\r\n\r\n/* ── Popover wrapper ─────────────────────────────────────────────── */\r\nexport type FilterPopoverProps = FilterPanelProps & {\r\n /** Botão que abre o popover. Quando `anchor` é passado, este `trigger` é\r\n * ignorado — o popover é posicionado relativo ao `anchor` mas só abre\r\n * via prop `open` controlled (use case: split button externo). */\r\n trigger: ReactNode;\r\n /**\r\n * Anchor element pra posicionar o popover SEM disparar abertura via click.\r\n * Quando undefined, usa `trigger` como PopoverTrigger padrão.\r\n */\r\n anchor?: ReactNode;\r\n align?: \"start\" | \"center\" | \"end\";\r\n open?: boolean;\r\n onOpenChange?: (open: boolean) => void;\r\n className?: string;\r\n};\r\n\r\n/**\r\n * FilterPopover — popover de filtros estilo query builder.\r\n * Wrapper fino: renderiza o `<FilterPanel>` dentro do PopoverContent. A limpeza\r\n * de linhas em branco (user clicou \"+ Adicionar\" mas não preencheu valor) mora\r\n * no PRÓPRIO `FilterPanel` (unmount-purge) — fonte única que cobre este popover,\r\n * o drill-down do settings menu e o split button, independente de COMO fechou.\r\n *\r\n * Dumb: `filters` (array de entries) vem do consumer. Use o hook\r\n * `useToolbarFilters()` se quiser gerenciamento de estado pronto.\r\n */\r\nexport function FilterPopover({\r\n trigger,\r\n anchor,\r\n align = \"end\",\r\n open,\r\n onOpenChange,\r\n className,\r\n ...panel\r\n}: FilterPopoverProps) {\r\n return (\r\n <Popover open={open} onOpenChange={onOpenChange}>\r\n {anchor ? (\r\n // Anchor mode: posiciona o popover mas NÃO dispara abertura — consumer\r\n // controla via prop `open` externa (split button pattern).\r\n <PopoverAnchor asChild>{anchor}</PopoverAnchor>\r\n ) : (\r\n <PopoverTrigger asChild>{trigger}</PopoverTrigger>\r\n )}\r\n <PopoverContent\r\n align={align}\r\n className={cn(\r\n \"w-[560px] max-w-[calc(100vw-32px)] max-h-[min(480px,calc(100vh-80px))] p-0 flex flex-col min-h-0 overflow-hidden\",\r\n className,\r\n )}\r\n >\r\n <FilterPanel {...panel} />\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n","import { useState, type ComponentType, type ReactNode } from \"react\";\r\nimport { ArrowUpDown, Check, ChevronLeft, ChevronRight, Columns, Eye, SlidersHorizontal } from \"lucide-react\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/shadcn/popover\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\n/**\r\n * ToolbarSettingsMenu — menu \"Configurações da tabela\" com navegação em níveis\r\n * (drill-down) num único painel.\r\n *\r\n * Visual inspirado fielmente no `DropdownMenu` (mesma respiração): container\r\n * `p-pad-sm` com `gap-px`, items `px-pad-lg py-pad-md gap-pad-lg` (texto muted →\r\n * default no hover), labels `text-fg-subtle uppercase`, separadores `h-px`.\r\n *\r\n * Nível 0: lista de seções (Ordenação ›, Colunas ›, Filtros avançados ›) +\r\n * seção Densidade inline.\r\n * Nível 1: o miolo (`SortPanel` / `ColsPanel` / `FilterPanel`) com botão voltar.\r\n *\r\n * Extras só-mobile (não mudam nada no desktop): `mobileViewToggle` (Kanban/Lista,\r\n * seção inline) e `mobileViews` (entrada \"Visões ›\" drill-down listando só as\r\n * visões pré-definidas, com a selecionada exibida à direita).\r\n */\r\ntype SettingsView = \"root\" | \"sort\" | \"cols\" | \"filter\" | \"views\";\r\n\r\ntype NavEntry = {\r\n view: Exclude<SettingsView, \"root\">;\r\n label: ReactNode;\r\n icon: ComponentType<{ className?: string; strokeWidth?: number }>;\r\n render: (onBack: () => void) => ReactNode;\r\n /** Texto à direita (cor fraca) — ex: a visão atualmente selecionada. */\r\n rightHint?: ReactNode;\r\n /** Entrada só aparece em <md (CSS `md:hidden`). */\r\n mobileOnly?: boolean;\r\n};\r\n\r\nexport type ToolbarSettingsMenuView = {\r\n id: string;\r\n name: ReactNode;\r\n};\r\n\r\nexport type ToolbarSettingsMenuProps = {\r\n /** Botão que abre o menu (ícone sliders). */\r\n trigger: ReactNode;\r\n\r\n /** Painel de ordenação (recebe `onBack`). Omitir → não mostra a seção. */\r\n sortPanel?: (onBack: () => void) => ReactNode;\r\n /** Painel de colunas (recebe `onBack`). */\r\n colsPanel?: (onBack: () => void) => ReactNode;\r\n /** Painel de filtros avançados (recebe `onBack`). */\r\n filterPanel?: (onBack: () => void) => ReactNode;\r\n\r\n /** Controle de densidade (segmented) renderizado inline no nível 0. */\r\n density?: ReactNode;\r\n\r\n /**\r\n * Toggle de visualização (Kanban/Lista) — seção inline só-mobile (`md:hidden`).\r\n * Passe o `<ToolbarSegmented fluid>` aqui pra ele aparecer no menu em <md.\r\n */\r\n mobileViewToggle?: ReactNode;\r\n /**\r\n * Toggle de EXIBIÇÃO da tabela no mobile (Linhas/Cards) — seção inline\r\n * só-mobile (`md:hidden`). Eixo independente do `mobileViewToggle`\r\n * (table/kanban): controla se a tabela renderiza como linhas ou cards.\r\n */\r\n mobileDisplayToggle?: ReactNode;\r\n /**\r\n * Visões pré-definidas — entrada drill-down só-mobile (`md:hidden`). Lista só\r\n * as views default da montagem (sem salvas, sem adicionar). A selecionada\r\n * aparece à direita da entrada.\r\n */\r\n mobileViews?: {\r\n items: ToolbarSettingsMenuView[];\r\n activeId?: string;\r\n onSelect: (id: string) => void;\r\n };\r\n\r\n /** Título do nível 0. Default \"Configurações da tabela\". */\r\n title?: ReactNode;\r\n /** Labels das seções. */\r\n densityLabel?: ReactNode;\r\n sortLabel?: ReactNode;\r\n colsLabel?: ReactNode;\r\n filterLabel?: ReactNode;\r\n viewToggleLabel?: ReactNode;\r\n mobileDisplayLabel?: ReactNode;\r\n viewsLabel?: ReactNode;\r\n\r\n align?: \"start\" | \"center\" | \"end\";\r\n open?: boolean;\r\n onOpenChange?: (open: boolean) => void;\r\n className?: string;\r\n};\r\n\r\n/* ── Estilos espelhados do DropdownMenu ──────────────────────────── */\r\nconst MENU_ITEM = cn(\r\n \"group/row relative flex items-center gap-pad-lg w-full\",\r\n \"px-pad-lg py-pad-md rounded-radius-sm\",\r\n \"bg-transparent border-0 cursor-pointer outline-none text-left\",\r\n \"text-body-sm font-medium text-fg-muted [&_svg]:text-fg-muted\",\r\n \"transition-colors duration-150\",\r\n \"hover:bg-bg-muted hover:text-fg-default hover:[&_svg]:text-fg-default\",\r\n \"focus-visible:bg-bg-muted focus-visible:text-fg-default\",\r\n \"[&_svg]:size-4 [&_svg]:shrink-0\",\r\n);\r\nconst MENU_LABEL =\r\n \"px-pad-lg py-pad-sm text-caption-sm font-semibold uppercase tracking-wider text-fg-subtle\";\r\nconst MENU_SEP = \"mx-pad-xs my-pad-xs h-px bg-border-default\";\r\nconst MENU_FIELD = \"px-pad-lg pb-pad-sm\"; // wrapper do control (segmented) alinhado aos items\r\n\r\n/* Header com botão voltar — usado pelos níveis drill-down internos. */\r\nfunction LevelHeader({ label, onBack }: { label: ReactNode; onBack: () => void }) {\r\n return (\r\n <div className=\"flex-none flex items-center gap-gp-md px-pad-xl py-pad-lg border-b border-border-default\">\r\n <button\r\n type=\"button\"\r\n onClick={onBack}\r\n aria-label=\"Voltar\"\r\n className=\"grid place-items-center size-[20px] -ml-[2px] shrink-0 rounded-radius-sm bg-transparent text-fg-muted cursor-pointer outline-none hover:bg-bg-muted hover:text-fg-default focus-visible:bg-bg-muted [&_svg]:size-[16px]\"\r\n >\r\n <ChevronLeft strokeWidth={2.2} />\r\n </button>\r\n <h3 className=\"text-caption-sm font-semibold text-fg-subtle uppercase tracking-wider leading-none m-0\">\r\n {label}\r\n </h3>\r\n </div>\r\n );\r\n}\r\n\r\nexport function ToolbarSettingsMenu({\r\n trigger,\r\n sortPanel,\r\n colsPanel,\r\n filterPanel,\r\n density,\r\n mobileViewToggle,\r\n mobileDisplayToggle,\r\n mobileViews,\r\n title = \"Configurações da tabela\",\r\n densityLabel = \"Densidade\",\r\n sortLabel = \"Ordenação\",\r\n colsLabel = \"Colunas\",\r\n filterLabel = \"Filtros avançados\",\r\n viewToggleLabel = \"Visualização\",\r\n mobileDisplayLabel = \"Exibição\",\r\n viewsLabel = \"Visões\",\r\n align = \"end\",\r\n open,\r\n onOpenChange,\r\n className,\r\n}: ToolbarSettingsMenuProps) {\r\n const [view, setView] = useState<SettingsView>(\"root\");\r\n\r\n // Reset pro nível 0 ao ABRIR (não ao fechar). Resetar no fechar fazia o painel\r\n // \"voltar pro root\" durante a animação de close-out (flicker visível por alguns\r\n // ms). Como o conteúdo desmonta ao fechar, resetar no próximo open é limpo.\r\n const handleOpenChange = (next: boolean) => {\r\n if (next) setView(\"root\");\r\n onOpenChange?.(next);\r\n };\r\n\r\n const selectedViewName = mobileViews?.items.find((v) => v.id === mobileViews.activeId)?.name;\r\n\r\n const entries: NavEntry[] = [];\r\n if (sortPanel) entries.push({ view: \"sort\", label: sortLabel, icon: ArrowUpDown, render: sortPanel });\r\n if (colsPanel) entries.push({ view: \"cols\", label: colsLabel, icon: Columns, render: colsPanel });\r\n if (filterPanel) entries.push({ view: \"filter\", label: filterLabel, icon: SlidersHorizontal, render: filterPanel });\r\n if (mobileViews) {\r\n entries.push({\r\n view: \"views\",\r\n label: viewsLabel,\r\n icon: Eye,\r\n mobileOnly: true,\r\n rightHint: selectedViewName,\r\n render: (onBack) => (\r\n <>\r\n <LevelHeader label={viewsLabel} onBack={onBack} />\r\n <div className=\"flex-1 min-h-0 overflow-y-auto p-pad-sm flex flex-col gap-px\">\r\n {mobileViews.items.map((item) => {\r\n const isActive = mobileViews.activeId === item.id;\r\n return (\r\n <button\r\n key={item.id}\r\n type=\"button\"\r\n onClick={() => {\r\n mobileViews.onSelect(item.id);\r\n onBack();\r\n }}\r\n className={cn(\r\n MENU_ITEM,\r\n isActive &&\r\n \"bg-bg-brand-subtle text-fg-brand [&_svg]:text-fg-brand hover:bg-bg-brand-subtle hover:text-fg-brand\",\r\n )}\r\n >\r\n <span className=\"flex-1 truncate\">{item.name}</span>\r\n {isActive && <Check strokeWidth={2.2} />}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n </>\r\n ),\r\n });\r\n }\r\n\r\n const active = entries.find((e) => e.view === view);\r\n // Filtros avançados precisa de mais largura (query builder). Só desktop —\r\n // no mobile o sheet já ocupa a largura toda.\r\n const wide = view === \"filter\";\r\n\r\n return (\r\n <Popover open={open} onOpenChange={handleOpenChange}>\r\n <PopoverTrigger asChild>{trigger}</PopoverTrigger>\r\n <PopoverContent\r\n align={align}\r\n className={cn(\r\n \"w-[320px] max-w-[calc(100vw-32px)] max-h-[min(520px,calc(100vh-80px))] p-0 flex flex-col min-h-0 overflow-hidden\",\r\n wide && \"md:w-[550px]\",\r\n className,\r\n )}\r\n >\r\n {active ? (\r\n // Nível 1 — painel reaproveitado com voltar injetado.\r\n active.render(() => setView(\"root\"))\r\n ) : (\r\n // Nível 0 — lista flat estilo DropdownMenu (label + items + seções).\r\n <div className=\"flex-1 min-h-0 overflow-y-auto p-pad-sm flex flex-col gap-px\">\r\n <div className={MENU_LABEL}>{title}</div>\r\n\r\n {entries.map((e) => {\r\n const Icon = e.icon;\r\n return (\r\n <button\r\n key={e.view}\r\n type=\"button\"\r\n onClick={() => setView(e.view)}\r\n className={cn(MENU_ITEM, e.mobileOnly && \"md:hidden\")}\r\n >\r\n <Icon strokeWidth={1.8} />\r\n <span className=\"flex-1 truncate\">{e.label}</span>\r\n {e.rightHint && (\r\n <span className=\"text-caption-sm text-fg-subtle truncate max-w-[120px]\">\r\n {e.rightHint}\r\n </span>\r\n )}\r\n <ChevronRight strokeWidth={2} />\r\n </button>\r\n );\r\n })}\r\n\r\n {/* Visualização (Kanban/Lista) — só-mobile, inline igual Densidade. */}\r\n {mobileViewToggle && (\r\n <div className=\"md:hidden flex flex-col\">\r\n <div className={MENU_SEP} />\r\n <div className={cn(MENU_LABEL, \"pb-pad-lg\")}>{viewToggleLabel}</div>\r\n <div className={MENU_FIELD}>{mobileViewToggle}</div>\r\n </div>\r\n )}\r\n\r\n {/* Exibição (Linhas/Cards) — só-mobile, inline igual Densidade. */}\r\n {mobileDisplayToggle && (\r\n <div className=\"md:hidden flex flex-col\">\r\n <div className={MENU_SEP} />\r\n <div className={cn(MENU_LABEL, \"pb-pad-lg\")}>{mobileDisplayLabel}</div>\r\n <div className={MENU_FIELD}>{mobileDisplayToggle}</div>\r\n </div>\r\n )}\r\n\r\n {density && (\r\n <div className=\"flex flex-col\">\r\n <div className={MENU_SEP} />\r\n <div className={cn(MENU_LABEL, \"pb-pad-lg\")}>{densityLabel}</div>\r\n <div className={MENU_FIELD}>{density}</div>\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * FloatingPanel — drawer \"card flutuante\" que convive com a interação\r\n * atrás (sem backdrop modal). Versão do `<Panel>` para casos non-modal:\r\n * detail panels, side info, configurações secundárias.\r\n *\r\n * Diferenças vs `<Panel>`:\r\n * - Sem Sheet/Dialog (sem foco trap, sem overlay scrim)\r\n * - Suporte a resize horizontal (drag handle no edge)\r\n * - Suporte a maximize (toggle pra ocupar quase a tela toda)\r\n * - Em max-md vira sheet bottom-up (responsive)\r\n */\r\nexport const floatingPanelStyles = tv({\r\n slots: {\r\n root: [\r\n \"fixed z-50 flex flex-col overflow-hidden\",\r\n \"bg-bg-surface dark:bg-bg-canvas text-fg-default\",\r\n \"rounded-radius-xl border border-border-default outline-float shadow-sh-2xl\",\r\n // Desktop (md+) — gutter top/bottom 24px\r\n \"md:top-pad-4xl md:bottom-pad-4xl\",\r\n // …e o mesmo gutter de 24px como TETO de largura, simétrico (24+24=48).\r\n //\r\n // Sem isto o painel estoura a viewport com props DEFAULT: `side=\"right\"` ancora a\r\n // 24px da borda e `resizableMaxWidth` default é 800 → 800+24 = 824px de necessidade.\r\n // Em qualquer janela entre 768 e 824 (≥md, então sem o sheet mobile) a borda esquerda\r\n // ia pra fora da tela. Mesmo caso com `size={n}` grande num monitor pequeno.\r\n //\r\n // O `min`/`max` do hook de resize é em PIXEL e cego à viewport — quem clampa é isto.\r\n // Não regride nada: `max-width` só age quando a largura já estouraria.\r\n \"md:max-w-[calc(100vw-48px)]\",\r\n // Mobile (max-md) — sheet bottom-up colado nas bordas do device:\r\n // flush nas laterais + bottom, só top arredondado, sem outline/shadow, cap 92vh\r\n \"max-md:inset-x-0 max-md:bottom-0 max-md:top-auto max-md:!w-auto\",\r\n \"max-md:max-h-[92vh] max-md:rounded-b-none max-md:border-x-0 max-md:border-b-0\",\r\n \"max-md:outline-none max-md:shadow-none\",\r\n // Entrada animada\r\n \"ease-[cubic-bezier(0.4,0,0.2,1)] duration-[220ms]\",\r\n \"animate-in fade-in-0\",\r\n ],\r\n // Backdrop suave — renderizado só em mobile (md:hidden). No desktop o\r\n // FloatingPanel permanece non-modal (sem scrim, página atrás interativa).\r\n backdrop: [\r\n \"fixed inset-0 z-40 bg-overlay-scrim md:hidden\",\r\n \"animate-in fade-in-0 duration-[220ms]\",\r\n ],\r\n handle: [\r\n \"absolute top-0 bottom-0 w-[6px] cursor-col-resize z-10\",\r\n // Linha 1px que aparece sutil no hover do panel + linha brand 2px no hover direto\r\n \"after:content-[''] after:absolute after:top-[16px] after:bottom-[16px]\",\r\n \"after:left-1/2 after:-translate-x-1/2 after:w-px after:bg-border-default\",\r\n \"after:transition-all after:duration-150 after:opacity-60\",\r\n \"hover:after:bg-bg-brand hover:after:w-[2px] hover:after:top-0 hover:after:bottom-0 hover:after:opacity-100\",\r\n \"data-[dragging=true]:after:bg-bg-brand data-[dragging=true]:after:w-[2px]\",\r\n \"data-[dragging=true]:after:top-0 data-[dragging=true]:after:bottom-0 data-[dragging=true]:after:opacity-100\",\r\n // Hide em mobile (não-resizable) e quando maximized\r\n \"max-md:hidden\",\r\n ],\r\n header: [\r\n \"flex items-center gap-gp-md flex-none\",\r\n \"px-[18px] py-[14px] min-h-[60px]\",\r\n \"border-b border-border-default\",\r\n ],\r\n headerText: \"flex flex-col gap-gp-2xs min-w-0 flex-1\",\r\n headerTitle: [\r\n \"flex items-center gap-gp-md min-w-0\",\r\n \"text-body-lg font-bold tracking-[-0.01em] text-fg-default truncate\",\r\n ],\r\n headerTitleIcon: \"size-[18px] text-fg-brand shrink-0\",\r\n headerDescription: \"text-body-md text-fg-muted truncate\",\r\n headerActions: \"flex items-center gap-gp-xs flex-none\",\r\n body: [\r\n // min-h-0 garante que o flex-1 encolha e o scroll ative (em vez de\r\n // empurrar header/footer). Scroll automático independente de viewport.\r\n \"flex-1 min-h-0 overflow-y-auto scrollbar-thin\",\r\n ],\r\n footer: [\r\n // Botões fluidos lado a lado; quebram pra empilhados quando não cabem.\r\n \"flex flex-wrap items-center gap-gp-md flex-none\",\r\n \"[&>*]:flex-1 [&>*]:min-w-[140px]\",\r\n \"px-[18px] py-[14px]\",\r\n \"border-t border-border-default\",\r\n ],\r\n },\r\n variants: {\r\n side: {\r\n right: {\r\n root: \"md:right-pad-4xl md:slide-in-from-right-12 max-md:slide-in-from-bottom-12\",\r\n handle: \"left-0\",\r\n },\r\n left: {\r\n root: \"md:left-pad-4xl md:slide-in-from-left-12 max-md:slide-in-from-bottom-12\",\r\n handle: \"right-0\",\r\n },\r\n },\r\n maximized: {\r\n true: {\r\n // Ocupa quase a tela inteira (16px gutter em todas as direções)\r\n // !important sobrescreve as positions do side e do mobile\r\n root: \"md:!inset-pad-md md:!w-auto\",\r\n handle: \"md:hidden\",\r\n },\r\n },\r\n // Padding interno padrão do body (gutter 18px lateral, igual header/footer).\r\n // Default ON — conteúdo livre já respira. Desligue (`bodyPadded={false}`)\r\n // quando usar `<FloatingPanelSection>` (sections gerenciam o próprio padding\r\n // edge-to-edge com divisórias full-width).\r\n bodyPadded: {\r\n true: { body: \"px-[18px] py-pad-xl\" },\r\n false: {},\r\n },\r\n },\r\n defaultVariants: {\r\n bodyPadded: true,\r\n },\r\n});\r\n\r\n/* ── Map de sizes pré-definidos (px) ──────────────────────────── */\r\nexport const FLOATING_PANEL_SIZE_PX: Record<\r\n \"sm\" | \"md\" | \"lg\" | \"xl\",\r\n number\r\n> = {\r\n sm: 320,\r\n md: 400,\r\n lg: 560,\r\n xl: 720,\r\n};\r\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport type UseFloatingPanelResizeOptions = {\n /** Largura inicial (em px) antes do localStorage hidratar. */\n initial: number;\n /** Largura mínima permitida (em px). */\n min: number;\n /** Largura máxima permitida (em px). */\n max: number;\n /** Lado em que o panel está ancorado — determina o sentido do delta. */\n side: \"left\" | \"right\";\n /** Chave no localStorage pra persistir (opcional). */\n storageKey?: string;\n /** Se false, o hook não atualiza width (modo \"maximizado\" ou disabled). */\n enabled?: boolean;\n};\n\nexport type UseFloatingPanelResizeResult = {\n width: number;\n /** Handler pra começar o drag — atribuir em `onMouseDown` do handle. */\n onResizeStart: (e: React.MouseEvent) => void;\n};\n\n/**\n * Hook de drag-resize horizontal pra panels flutuantes com persist opcional\n * em localStorage. Suporta painéis ancorados à direita OU à esquerda — o\n * sentido do delta é invertido automaticamente.\n *\n * side=\"right\" → handle no LEFT edge → arrastar pra esquerda AUMENTA width\n * side=\"left\" → handle no RIGHT edge → arrastar pra direita AUMENTA width\n *\n * Cleanup: listeners globais são removidos no mouseup + restaura cursor/userSelect.\n */\nexport function useFloatingPanelResize({\n initial,\n min,\n max,\n side,\n storageKey,\n enabled = true,\n}: UseFloatingPanelResizeOptions): UseFloatingPanelResizeResult {\n const [width, setWidth] = useState<number>(initial);\n const hydrated = useRef(false);\n\n // Hidrata do localStorage no mount (se storageKey)\n useEffect(() => {\n if (!storageKey || typeof window === \"undefined\") {\n hydrated.current = true;\n return;\n }\n try {\n const raw = window.localStorage.getItem(storageKey);\n const n = raw ? Number(raw) : NaN;\n if (!Number.isNaN(n) && n >= min && n <= max) setWidth(n);\n } catch {\n /* ignore */\n }\n hydrated.current = true;\n }, [min, max, storageKey]);\n\n // Salva quando muda (após hidratação)\n useEffect(() => {\n if (!hydrated.current || !storageKey || typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(storageKey, String(width));\n } catch {\n /* ignore */\n }\n }, [width, storageKey]);\n\n const onResizeStart = useCallback(\n (e: React.MouseEvent) => {\n if (!enabled) return;\n e.preventDefault();\n const startX = e.clientX;\n const startWidth = width;\n\n const onMove = (ev: MouseEvent) => {\n // side=right (handle left edge): delta < 0 (cursor pra esquerda) AUMENTA width\n // side=left (handle right edge): delta > 0 (cursor pra direita) AUMENTA width\n const delta = side === \"right\" ? startX - ev.clientX : ev.clientX - startX;\n const next = Math.max(min, Math.min(max, startWidth + delta));\n setWidth(next);\n };\n const onUp = () => {\n document.removeEventListener(\"mousemove\", onMove);\n document.removeEventListener(\"mouseup\", onUp);\n document.body.style.cursor = \"\";\n document.body.style.userSelect = \"\";\n };\n document.addEventListener(\"mousemove\", onMove);\n document.addEventListener(\"mouseup\", onUp);\n document.body.style.cursor = \"col-resize\";\n document.body.style.userSelect = \"none\";\n },\n [width, min, max, side, enabled],\n );\n\n return { width, onResizeStart };\n}\n","import { useEffect, useId, useRef, useState } from \"react\";\r\nimport { createPortal } from \"react-dom\";\r\nimport { Maximize2, Minimize2, X } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Button } from \"@/components/ui/Button/button\";\r\nimport { floatingPanelStyles, FLOATING_PANEL_SIZE_PX } from \"./floating-panel.styles\";\r\nimport { useFloatingPanelResize } from \"./use-floating-panel-resize\";\r\nimport type { FloatingPanelProps, FloatingPanelSize } from \"./floating-panel.types\";\r\n\r\nfunction resolveInitialWidth(size: FloatingPanelProps[\"size\"]): number {\r\n if (typeof size === \"number\") return size;\r\n if (size && size in FLOATING_PANEL_SIZE_PX) {\r\n return FLOATING_PANEL_SIZE_PX[size as FloatingPanelSize];\r\n }\r\n return FLOATING_PANEL_SIZE_PX.md;\r\n}\r\n\r\n/**\r\n * FloatingPanel — drawer \"card flutuante\" non-modal.\r\n *\r\n * No desktop, diferente do `<Panel>`, NÃO renderiza backdrop nem trap de foco —\r\n * a página atrás continua interativa. Útil pra detail panels, side info,\r\n * configurações secundárias que precisam coexistir com a tela principal.\r\n *\r\n * Features:\r\n * - Resize horizontal (drag handle no edge) com persistência opcional\r\n * - Maximize toggle (botão no header) — ocupa quase a tela toda\r\n * - Responsive: vira sheet bottom-up colado nas bordas em max-md, com\r\n * backdrop suave (toque fecha) — só em mobile; desktop segue non-modal\r\n * - max-height 92vh em mobile; body com scroll automático\r\n * - ESC fecha (configurável)\r\n * - Renderizado via portal em document.body (escapa de overflow/transform de ancestrais)\r\n *\r\n * Exemplo:\r\n * ```tsx\r\n * <FloatingPanel\r\n * open={open}\r\n * onOpenChange={setOpen}\r\n * title=\"Detalhes do cliente\"\r\n * description=\"ID: CLI-2401\"\r\n * resizable\r\n * maximizable\r\n * headerActions={\r\n * <>\r\n * <Button variant=\"soft\" color=\"secondary\" size=\"icon-sm\"><Pencil /></Button>\r\n * <Button variant=\"soft\" color=\"critical\" size=\"icon-sm\"><Trash2 /></Button>\r\n * </>\r\n * }\r\n * footer={\r\n * <>\r\n * <Button variant=\"outline\" color=\"secondary\" onClick={() => setOpen(false)}>Cancelar</Button>\r\n * <Button variant=\"filled\" color=\"primary\">Salvar</Button>\r\n * </>\r\n * }\r\n * >\r\n * <DetailContent />\r\n * </FloatingPanel>\r\n * ```\r\n */\r\nexport function FloatingPanel({\r\n open,\r\n onOpenChange,\r\n side = \"right\",\r\n size = \"md\",\r\n title,\r\n description,\r\n titleIcon: TitleIcon,\r\n titleSlot,\r\n headerActions,\r\n hideClose,\r\n footer,\r\n children,\r\n resizable = false,\r\n resizableMinWidth = 320,\r\n resizableMaxWidth = 800,\r\n resizableStorageKey,\r\n maximizable = false,\r\n defaultMaximized = false,\r\n closeOnEscape = true,\r\n bodyPadded = true,\r\n className,\r\n}: FloatingPanelProps) {\r\n const initialWidth = resolveInitialWidth(size);\r\n const [maximized, setMaximized] = useState<boolean>(defaultMaximized);\r\n const [dragging, setDragging] = useState<boolean>(false);\r\n const titleId = useId();\r\n const descId = useId();\r\n const handleRef = useRef<HTMLButtonElement>(null);\r\n\r\n const resize = useFloatingPanelResize({\r\n initial: initialWidth,\r\n min: resizableMinWidth,\r\n max: resizableMaxWidth,\r\n side,\r\n storageKey: resizableStorageKey,\r\n enabled: resizable && !maximized,\r\n });\r\n\r\n // ESC fecha (configurável)\r\n useEffect(() => {\r\n if (!open || !closeOnEscape) return;\r\n const onKey = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") onOpenChange(false);\r\n };\r\n document.addEventListener(\"keydown\", onKey);\r\n return () => document.removeEventListener(\"keydown\", onKey);\r\n }, [open, closeOnEscape, onOpenChange]);\r\n\r\n // Capture dragging state pro data-dragging do handle (cor brand persiste)\r\n useEffect(() => {\r\n if (!dragging) return;\r\n const onUp = () => setDragging(false);\r\n document.addEventListener(\"mouseup\", onUp);\r\n return () => document.removeEventListener(\"mouseup\", onUp);\r\n }, [dragging]);\r\n\r\n // SSR safety + render condicional\r\n if (typeof window === \"undefined\" || !open) return null;\r\n\r\n const s = floatingPanelStyles({ side, maximized, bodyPadded });\r\n\r\n // Width final aplicado no style (ignora em mobile via CSS max-md:!w-auto)\r\n const widthValue = resizable ? resize.width : initialWidth;\r\n\r\n return createPortal(\r\n <>\r\n {/* Backdrop suave — só em mobile (md:hidden). Toque fecha o panel. */}\r\n <div className={s.backdrop()} aria-hidden=\"true\" onClick={() => onOpenChange(false)} />\r\n\r\n <aside\r\n role=\"dialog\"\r\n aria-modal=\"false\"\r\n aria-labelledby={title ? titleId : undefined}\r\n aria-describedby={description ? descId : undefined}\r\n style={maximized ? undefined : { width: widthValue }}\r\n className={cn(s.root(), className)}\r\n >\r\n {/* Resize handle — só quando resizable e !maximized */}\r\n {resizable && !maximized && (\r\n <button\r\n ref={handleRef}\r\n type=\"button\"\r\n aria-label=\"Redimensionar panel\"\r\n data-dragging={dragging || undefined}\r\n onMouseDown={(e) => {\r\n setDragging(true);\r\n resize.onResizeStart(e);\r\n }}\r\n className={s.handle()}\r\n />\r\n )}\r\n\r\n {/* Header — title / description / actions */}\r\n {(title || description || titleSlot || headerActions || !hideClose || maximizable) && (\r\n <header className={s.header()}>\r\n {titleSlot ? (\r\n <div className=\"flex-1 min-w-0\">{titleSlot}</div>\r\n ) : (\r\n <div className={s.headerText()}>\r\n {title && (\r\n <h2 id={titleId} className={s.headerTitle()}>\r\n {TitleIcon && <TitleIcon className={s.headerTitleIcon()} strokeWidth={1.8} />}\r\n <span className=\"truncate\">{title}</span>\r\n </h2>\r\n )}\r\n {description && (\r\n <p id={descId} className={s.headerDescription()}>\r\n {description}\r\n </p>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className={s.headerActions()}>\r\n {headerActions}\r\n {maximizable && (\r\n <Button\r\n type=\"button\"\r\n variant=\"soft\"\r\n color=\"secondary\"\r\n size=\"icon-sm\"\r\n aria-label={maximized ? \"Restaurar tamanho\" : \"Maximizar\"}\r\n onClick={() => setMaximized((m) => !m)}\r\n className=\"max-md:hidden\"\r\n >\r\n {maximized ? <Minimize2 /> : <Maximize2 />}\r\n </Button>\r\n )}\r\n {!hideClose && (\r\n <Button\r\n type=\"button\"\r\n variant=\"soft\"\r\n color=\"secondary\"\r\n size=\"icon-sm\"\r\n aria-label=\"Fechar\"\r\n onClick={() => onOpenChange(false)}\r\n >\r\n <X />\r\n </Button>\r\n )}\r\n </div>\r\n </header>\r\n )}\r\n\r\n {/* Body */}\r\n <div className={s.body()}>{children}</div>\r\n\r\n {/* Footer */}\r\n {footer && <footer className={s.footer()}>{footer}</footer>}\r\n </aside>\r\n </>,\r\n document.body,\r\n );\r\n}\r\n","import { useState, type ReactNode } from \"react\";\r\nimport { ChevronDown } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * Building blocks padrão pro conteúdo estruturado de um `<FloatingPanel>` —\r\n * seções colapsáveis (edge-to-edge, divisória full-width) + campos label/valor.\r\n *\r\n * Use com `<FloatingPanel bodyPadded={false}>` (as sections gerenciam o próprio\r\n * padding interno). É o pattern canônico de \"painel de detalhe\" do DS — espelha\r\n * o DetailDrawer da showcase de Clientes. Preferir estes compounds a remontar\r\n * sections na unha garante padding/tipografia/divisórias consistentes.\r\n */\r\nconst partStyles = tv({\r\n slots: {\r\n section: \"border-b border-border-default last:border-b-0\",\r\n head: [\r\n \"flex items-center justify-between w-full\",\r\n \"px-[18px] py-[14px]\",\r\n \"bg-transparent border-0 cursor-pointer text-left\",\r\n \"text-body-sm font-semibold text-fg-default\",\r\n \"transition-colors duration-150\",\r\n \"hover:bg-bg-muted focus-visible:outline-none focus-visible:bg-bg-muted\",\r\n ],\r\n headStatic: \"px-[18px] pt-pad-xl pb-pad-md text-body-sm font-semibold text-fg-default\",\r\n chev: \"size-[14px] text-fg-muted transition-transform duration-200 shrink-0\",\r\n body: \"flex flex-col gap-gp-md px-[18px] pb-pad-2xl\",\r\n field: \"flex items-baseline justify-between gap-gp-md text-body-sm\",\r\n fieldLabel: \"text-body-xs font-normal text-fg-muted shrink-0\",\r\n fieldValue: \"text-fg-default font-medium text-right break-words min-w-0\",\r\n },\r\n});\r\n\r\nexport type FloatingPanelSectionProps = {\r\n /** Título da seção (header). */\r\n title: ReactNode;\r\n /** Conteúdo (geralmente `<FloatingPanelField>`). */\r\n children: ReactNode;\r\n /** Colapsável (header clicável + chevron). Default: true. */\r\n collapsible?: boolean;\r\n /** Estado inicial quando colapsável. Default: true (aberta). */\r\n defaultOpen?: boolean;\r\n};\r\n\r\nexport function FloatingPanelSection({\r\n title,\r\n children,\r\n collapsible = true,\r\n defaultOpen = true,\r\n}: FloatingPanelSectionProps) {\r\n const s = partStyles();\r\n const [open, setOpen] = useState(defaultOpen);\r\n\r\n if (!collapsible) {\r\n return (\r\n <section className={s.section()}>\r\n <div className={s.headStatic()}>{title}</div>\r\n <div className={s.body()}>{children}</div>\r\n </section>\r\n );\r\n }\r\n\r\n return (\r\n <section className={s.section()}>\r\n <button\r\n type=\"button\"\r\n className={s.head()}\r\n onClick={() => setOpen((o) => !o)}\r\n aria-expanded={open}\r\n >\r\n <span>{title}</span>\r\n <ChevronDown className={cn(s.chev(), open && \"rotate-180\")} />\r\n </button>\r\n {open && <div className={s.body()}>{children}</div>}\r\n </section>\r\n );\r\n}\r\n\r\nexport type FloatingPanelFieldProps = {\r\n label: ReactNode;\r\n value: ReactNode;\r\n};\r\n\r\nexport function FloatingPanelField({ label, value }: FloatingPanelFieldProps) {\r\n const s = partStyles();\r\n return (\r\n <div className={s.field()}>\r\n <span className={s.fieldLabel()}>{label}</span>\r\n <span className={s.fieldValue()}>{value || \"—\"}</span>\r\n </div>\r\n );\r\n}\r\n","import type { ColumnTypeDefinition, ColumnTypeId } from \"./column-types.types\";\r\n\r\n/**\r\n * Tipos de coluna **estruturais**: existem na união `ColumnTypeId` e são tratados por\r\n * caminho próprio no `DataTable`, **não** pelo registry. Pedir um deles ao registry é\r\n * legítimo (o call-site é genérico e roda por célula), então não é typo — e avisar\r\n * anularia o guard, que é justamente pra typo.\r\n *\r\n * Consequência de estar aqui: `get()` devolve o fallback `text` **em silêncio**. O valor\r\n * de retorno é idêntico ao de antes; muda só a ausência do `console.warn`.\r\n *\r\n * Ao acrescentar tipo estrutural novo (coluna que o `DataTable` renderiza por conta\r\n * própria, sem `renderCell` de tipo), acrescente aqui também — senão ele passa a gritar\r\n * por célula, por page load.\r\n */\r\nconst STRUCTURAL_TYPES = new Set<string>([\r\n // `getActions` → `DataTableActionsCell`. Ver `data-table-row.tsx` (fallback chain\r\n // de render, passo 2) e `data-table.tsx` (`isActionsCol`, `headerActions`).\r\n \"actions\",\r\n]);\r\n\r\n/**\r\n * Registry Singleton de tipos de coluna do DataTable.\r\n *\r\n * Permite o consumer registrar tipos customizados sem mudar o nucleo.\r\n * Fallback automatico pra `text` quando tipo desconhecido eh requisitado.\r\n *\r\n * Uso:\r\n * columnTypeRegistry.register(myCustomType);\r\n * const def = columnTypeRegistry.get(\"currency\");\r\n */\r\nclass ColumnTypeRegistry {\r\n private types = new Map<string, ColumnTypeDefinition>();\r\n\r\n register(definition: ColumnTypeDefinition): void {\r\n if (this.types.has(definition.type)) {\r\n // Não throw — pra hot reload em dev e re-import incidental. Apenas warn.\r\n // Em produção, console.warn é silencioso por default mas detectável.\r\n console.warn(\r\n `[columnTypeRegistry] type \"${definition.type}\" já registrado — override silencioso. Verifique imports duplicados.`,\r\n );\r\n }\r\n this.types.set(definition.type, definition);\r\n }\r\n\r\n registerMany(definitions: ColumnTypeDefinition[]): void {\r\n for (const d of definitions) this.register(d);\r\n }\r\n\r\n get(typeId: ColumnTypeId | undefined): ColumnTypeDefinition {\r\n if (typeId && this.types.has(typeId)) {\r\n return this.types.get(typeId)!;\r\n }\r\n // Typo guard (dev): diferencia \"sem tipo\" (undefined → text é intencional)\r\n // de \"tipo desconhecido\" (provável typo). Sem isso, `type=\"curency\"` degrada\r\n // silenciosamente pra text plano.\r\n //\r\n // ⚠️ Tipo ESTRUTURAL não é typo — e avisar sobre ele anulava o guard.\r\n // Medido em 2026-08-10 no `?app=finance`: **156 warnings por page load**, todos\r\n // de `type: \"actions\"`. Com esse volume, um `type=\"curency\"` de verdade fica\r\n // invisível no console — o guard existe pra pegar typo e estava sepultando o\r\n // próprio sinal.\r\n //\r\n // `actions` é o ÚNICO dos 17 tipos da união que não está registrado, e está\r\n // certo em não estar: não é tipo de DADO (não tem `renderCell`, filtro nem\r\n // operadores) — é coluna estrutural, com caminho próprio de render\r\n // (`DataTableActionsCell`, via `isActionsCol && col.getActions` em\r\n // `data-table-row.tsx`). Registrá-lo seria mentira: apareceria na lista de\r\n // \"tipos disponíveis\" e nas UIs de filtro, onde não faz sentido.\r\n //\r\n // O aviso vinha de `data-table-row.tsx:149`, que chama `get(col.type)` pra TODA\r\n // célula antes de saber qual caminho de render usar — o `typeDef` da coluna de\r\n // actions é calculado e **descartado**. Ou seja: nada quebrava, era ruído puro.\r\n // Por isso o retorno aqui é o MESMO de antes (fallback `text`); só o warn sai.\r\n if (typeId && !STRUCTURAL_TYPES.has(typeId) && import.meta.env?.DEV) {\r\n console.warn(\r\n `[columnTypeRegistry] type \"${typeId}\" não registrado — usando fallback \"text\". Typo? Tipos disponíveis: ${Array.from(this.types.keys()).join(\", \")}.`,\r\n );\r\n }\r\n const fallback = this.types.get(\"text\");\r\n if (!fallback) {\r\n throw new Error(\r\n \"ColumnTypeRegistry: tipo 'text' nao registrado (default fallback ausente)\",\r\n );\r\n }\r\n return fallback;\r\n }\r\n\r\n has(typeId: string): boolean {\r\n return this.types.has(typeId);\r\n }\r\n\r\n list(): ColumnTypeDefinition[] {\r\n return Array.from(this.types.values());\r\n }\r\n}\r\n\r\nexport const columnTypeRegistry = new ColumnTypeRegistry();\r\n","import type { ReactNode } from \"react\";\r\nimport { Check } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\n/**\r\n * Helpers compartilhados pelos triggers/inputs do modal Filtros (advanced).\r\n *\r\n * Sincronizados com `FIELD_BASE` + `INPUT_FIELD` do FilterPopover pra que\r\n * Campo/Operador/Valor tenham altura, padding, radius, bg, border e tipografia\r\n * IDÊNTICOS — sem diferença visual entre tipos (date, text, select, etc).\r\n *\r\n * Altura: form-md (36px). Radius: md. Padding: pad-xl. Text: 13px.\r\n *\r\n * Use:\r\n * - `FILTER_FIELD_CLASS` em `<button>` ou divs construídos from-scratch\r\n * (date/tags/multiSelect triggers que precisam estrutura própria).\r\n * - `FILTER_FIELD_SIZE` em primitives DS (`<Input>`, `<SelectTrigger>`) que\r\n * já têm bg/border próprios — só sobrescreve altura+radius pra match.\r\n */\r\n\r\n/** Trigger completo from-scratch — bg, border, foco, tudo. */\r\nexport const FILTER_FIELD_CLASS = cn(\r\n // Box-model\r\n \"flex min-h-form-md h-form-md w-full items-center justify-between gap-gp-md\",\r\n \"rounded-radius-md px-pad-xl\",\r\n // Tipografia\r\n \"text-body-sm font-normal\",\r\n // Visual\r\n \"bg-bg-input dark:bg-bg-muted\",\r\n \"border border-border-input text-fg-default\",\r\n // Estado\r\n \"outline-none transition-[border-color,box-shadow,background-color]\",\r\n \"focus-visible:border-border-brand focus-visible:shadow-sh-ring\",\r\n \"data-[state=open]:border-border-brand data-[state=open]:shadow-sh-ring\",\r\n);\r\n\r\n/** Só sizing override — usado em primitives shadcn que já têm visual próprio\r\n * mas vêm com altura default form-lg (40px). Garante match com FIELD_BASE. */\r\nexport const FILTER_FIELD_SIZE = cn(\r\n \"min-h-form-md h-form-md rounded-radius-md\",\r\n);\r\n\r\nexport type FastSingleOption = { value: string; label: ReactNode };\r\n\r\n/**\r\n * Lista single-select pro fast filter de chips (boolean/select).\r\n *\r\n * ⚠️ NÃO usar `<Select open>` aninhado dentro do PopoverContent do chip: o\r\n * listbox do Radix Select ancora no seu próprio trigger (sr-only, ~0px) → o\r\n * popover aparece deslocado pra baixo e o layer sempre-aberto trava o dismiss\r\n * por clique-fora (bug do item 8). Renderizar a lista DIRETO no PopoverContent\r\n * — como o MultiSelectDropdown — posiciona certo e fecha no clique-fora.\r\n */\r\nexport function FastSingleSelectList({\r\n options,\r\n selected,\r\n onSelect,\r\n}: {\r\n options: FastSingleOption[];\r\n selected: string;\r\n onSelect: (value: string) => void;\r\n}) {\r\n return (\r\n <div role=\"listbox\" className=\"flex flex-col gap-gp-2xs p-pad-2xs min-w-[180px]\">\r\n {options.length === 0 && (\r\n <p className=\"text-body-xs font-normal text-fg-muted px-pad-md py-pad-sm\">\r\n Sem opções disponíveis\r\n </p>\r\n )}\r\n {options.map((opt) => {\r\n const isSel = String(opt.value) === selected;\r\n return (\r\n <button\r\n key={opt.value}\r\n type=\"button\"\r\n role=\"option\"\r\n aria-selected={isSel}\r\n onClick={() => onSelect(opt.value)}\r\n className={cn(\r\n \"flex items-center gap-gp-md w-full px-pad-md py-pad-sm rounded-radius-md\",\r\n \"text-body-md text-fg-default text-left cursor-pointer\",\r\n \"hover:bg-bg-muted focus-visible:bg-bg-muted focus-visible:outline-none\",\r\n \"transition-colors duration-100\",\r\n )}\r\n >\r\n <Check\r\n className={cn(\r\n \"size-icon-sm shrink-0 text-fg-brand\",\r\n isSel ? \"opacity-100\" : \"opacity-0\",\r\n )}\r\n aria-hidden=\"true\"\r\n />\r\n <span className=\"flex-1 min-w-0 truncate\">{opt.label}</span>\r\n </button>\r\n );\r\n })}\r\n </div>\r\n );\r\n}\r\n","import { Type } from \"lucide-react\";\r\nimport { Input } from \"@/components/shadcn/input\";\r\nimport { FILTER_FIELD_SIZE } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\n\r\nfunction normalize(s: unknown): string {\r\n if (s == null) return \"\";\r\n return String(s)\r\n .toLowerCase()\r\n .normalize(\"NFD\")\r\n .replace(/[̀-ͯ]/g, \"\");\r\n}\r\n\r\nexport const TextColumnType: ColumnTypeDefinition = {\r\n type: \"text\",\r\n // Operadores típicos de query builder para text — contém / não contém /\r\n // começa com / termina com / é / não é / vazio / não vazio. Labels alinhados\r\n // com DEFAULT_OP_LABELS pra consistência chip ↔ popover.\r\n operators: [\r\n { id: \"contains\", label: \"contém\" },\r\n { id: \"notContains\", label: \"não contém\" },\r\n { id: \"equals\", label: \"é\" },\r\n { id: \"neq\", label: \"não é\" },\r\n { id: \"startsWith\", label: \"começa com\" },\r\n { id: \"endsWith\", label: \"termina com\" },\r\n { id: \"isEmpty\", label: \"está vazio\" },\r\n { id: \"isNotEmpty\", label: \"não está vazio\" },\r\n ],\r\n renderFilterInput: ({ value, onChange, placeholder, operator }) => {\r\n // isEmpty/isNotEmpty não precisa de input — operator se basta\r\n if (operator === \"isEmpty\" || operator === \"isNotEmpty\") {\r\n return <span className=\"text-fg-muted text-body-sm pl-pad-md\">(sem valor)</span>;\r\n }\r\n return (\r\n <Input\r\n type=\"text\"\r\n size=\"sm\"\r\n className={FILTER_FIELD_SIZE}\r\n value={(value as string) ?? \"\"}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder={placeholder ?? \"Valor...\"}\r\n />\r\n );\r\n },\r\n renderFastFilterInput: ({ value, onChange, options }) => (\r\n <Input\r\n type=\"text\"\r\n value={(value as string) ?? \"\"}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder={options?.[0]?.label ?? \"Buscar...\"}\r\n autoFocus\r\n />\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = normalize(cellValue);\r\n if (operator === \"isEmpty\") return cell.length === 0;\r\n if (operator === \"isNotEmpty\") return cell.length > 0;\r\n const filter = normalize(filterValue);\r\n if (operator === \"contains\") return cell.includes(filter);\r\n if (operator === \"notContains\") return !cell.includes(filter);\r\n if (operator === \"equals\") return cell === filter;\r\n if (operator === \"neq\") return cell !== filter;\r\n if (operator === \"startsWith\") return cell.startsWith(filter);\r\n if (operator === \"endsWith\") return cell.endsWith(filter);\r\n return null;\r\n },\r\n\r\n /* G.2 slots — text não precisa renderCell custom (raw value já basta). */\r\n formatValue: (v) => (v == null ? \"\" : String(v)),\r\n defaultAlign: \"left\",\r\n defaultSortable: true,\r\n defaultIcon: Type,\r\n};\r\n","/**\r\n * Helpers compartilhados entre column-type definitions.\r\n *\r\n * Consolida lógica que estava duplicada literalmente entre definitions:\r\n * - `toNumber` — era 3× (number/currency/percentage), com divergência sutil\r\n * (number usava `Number.isFinite`, currency/percentage\r\n * `!Number.isNaN` → aceitava `Infinity`). Unificado em\r\n * `Number.isFinite` (rejeita NaN E Infinity — correto pra\r\n * valores de célula/filtro).\r\n * - date helpers — `toDateMs/dayStart/toDate/toIsoDate` eram idênticos em\r\n * date + datetime.\r\n * - chip color — `ChipColor/CHIP_COLORS/resolveChipColor` eram idênticos em\r\n * badge + tags.\r\n * - lookups — `findOption`, `toStringArray`.\r\n */\r\nimport type { ColumnOption } from \"./column-types.types\";\r\n\r\n/* ── Number ──────────────────────────────────────────────────────── */\r\n\r\n/** Coage pra número finito ou `null` (rejeita NaN, Infinity e não-numéricos). */\r\nexport function toNumber(v: unknown): number | null {\r\n if (v == null || v === \"\") return null;\r\n const n = Number(v);\r\n return Number.isFinite(n) ? n : null;\r\n}\r\n\r\n/* ── Date ────────────────────────────────────────────────────────── */\r\n\r\n/** Coage qualquer valor (number ms / Date / string) em epoch ms, ou `null`. */\r\nexport function toDateMs(v: unknown): number | null {\r\n if (v == null || v === \"\") return null;\r\n if (typeof v === \"number\") return v;\r\n if (v instanceof Date) return v.getTime();\r\n const d = new Date(String(v));\r\n return Number.isNaN(d.getTime()) ? null : d.getTime();\r\n}\r\n\r\n/** Zera a hora (00:00:00.000) — pra comparar só a data, ignorando horário. */\r\nexport function dayStart(ms: number): number {\r\n const d = new Date(ms);\r\n d.setHours(0, 0, 0, 0);\r\n return d.getTime();\r\n}\r\n\r\n/** Converte qualquer valor em `Date` (pro Calendar) ou `undefined`. */\r\nexport function toDate(v: unknown): Date | undefined {\r\n const ms = toDateMs(v);\r\n return ms == null ? undefined : new Date(ms);\r\n}\r\n\r\n/** Serializa `Date` pra ISO date estável (\"YYYY-MM-DD\", sem hora) ou `null`. */\r\nexport function toIsoDate(d: Date | undefined | null): string | null {\r\n if (!d) return null;\r\n const y = d.getFullYear();\r\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\r\n const day = String(d.getDate()).padStart(2, \"0\");\r\n return `${y}-${m}-${day}`;\r\n}\r\n\r\n/* ── Chip color ──────────────────────────────────────────────────── */\r\n\r\n/** Cores de Chip suportadas pelos tipos badge/tags. */\r\nexport type ChipColor =\r\n | \"primary\"\r\n | \"neutral\"\r\n | \"danger\"\r\n | \"warning\"\r\n | \"success\"\r\n | \"info\";\r\n\r\nexport const CHIP_COLORS: ReadonlyArray<ChipColor> = [\r\n \"primary\",\r\n \"neutral\",\r\n \"danger\",\r\n \"warning\",\r\n \"success\",\r\n \"info\",\r\n];\r\n\r\n/**\r\n * Resolve `option.color` → variant de Chip. Aceita preset names diretos OU\r\n * aliases comuns (green/red/yellow/blue/gray); cai em `neutral` por padrão.\r\n */\r\nexport function resolveChipColor(raw: string | undefined): ChipColor {\r\n if (!raw) return \"neutral\";\r\n if (CHIP_COLORS.includes(raw as ChipColor)) return raw as ChipColor;\r\n const aliases: Record<string, ChipColor> = {\r\n green: \"success\",\r\n red: \"danger\",\r\n yellow: \"warning\",\r\n blue: \"info\",\r\n gray: \"neutral\",\r\n grey: \"neutral\",\r\n };\r\n return aliases[raw.toLowerCase()] ?? \"neutral\";\r\n}\r\n\r\n/* ── Lookups ─────────────────────────────────────────────────────── */\r\n\r\n/** Acha a `ColumnOption` cujo `value` casa (comparação por string). */\r\nexport function findOption(\r\n value: unknown,\r\n options?: ColumnOption[],\r\n): ColumnOption | null {\r\n if (value == null) return null;\r\n return options?.find((o) => String(o.value) === String(value)) ?? null;\r\n}\r\n\r\n/** Normaliza escalar OU array em array de strings. */\r\nexport function toStringArray(v: unknown): string[] {\r\n if (v == null) return [];\r\n if (Array.isArray(v)) return v.map(String);\r\n return [String(v)];\r\n}\r\n","import { Hash } from \"lucide-react\";\r\nimport { Input } from \"@/components/shadcn/input\";\r\nimport { FILTER_FIELD_SIZE } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\nimport { toNumber } from \"../_shared\";\r\n\r\nexport const NumberColumnType: ColumnTypeDefinition = {\r\n type: \"number\",\r\n operators: [\r\n { id: \"equals\", label: \"=\" },\r\n { id: \"gt\", label: \">\" },\r\n { id: \"lt\", label: \"<\" },\r\n { id: \"gte\", label: \"≥\" },\r\n { id: \"lte\", label: \"≤\" },\r\n { id: \"neq\", label: \"≠\" },\r\n ],\r\n renderFilterInput: ({ value, onChange, placeholder }) => (\r\n <Input\r\n type=\"number\"\r\n size=\"sm\"\r\n className={FILTER_FIELD_SIZE}\r\n value={(value as number) ?? \"\"}\r\n onChange={(e) => onChange(e.target.value === \"\" ? \"\" : Number(e.target.value))}\r\n placeholder={placeholder ?? \"0\"}\r\n />\r\n ),\r\n renderFastFilterInput: ({ value, onChange }) => (\r\n <Input\r\n type=\"number\"\r\n value={(value as number) ?? \"\"}\r\n onChange={(e) => onChange(e.target.value === \"\" ? \"\" : Number(e.target.value))}\r\n placeholder=\"0\"\r\n autoFocus\r\n />\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = toNumber(cellValue);\r\n const filter = toNumber(filterValue);\r\n if (cell === null || filter === null) return false;\r\n if (operator === \"equals\") return cell === filter;\r\n if (operator === \"neq\") return cell !== filter;\r\n if (operator === \"gt\") return cell > filter;\r\n if (operator === \"lt\") return cell < filter;\r\n if (operator === \"gte\") return cell >= filter;\r\n if (operator === \"lte\") return cell <= filter;\r\n return null;\r\n },\r\n\r\n /* G.2 — number alinhado à direita, formato locale-aware */\r\n renderCell: ({ value }) => {\r\n const n = toNumber(value);\r\n if (n === null) return null;\r\n return <span className=\"tabular-nums\">{n.toLocaleString(\"pt-BR\")}</span>;\r\n },\r\n formatValue: (v) => {\r\n const n = toNumber(v);\r\n return n === null ? \"\" : n.toLocaleString(\"pt-BR\");\r\n },\r\n defaultAlign: \"right\",\r\n defaultWidth: 110,\r\n defaultSortable: true,\r\n defaultIcon: Hash,\r\n};\r\n","import { Calendar as CalendarIcon } from \"lucide-react\";\r\nimport { Calendar } from \"@/components/shadcn/calendar\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/shadcn/popover\";\r\nimport { FILTER_FIELD_CLASS } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\nimport { toDateMs, dayStart, toDate, toIsoDate } from \"../_shared\";\r\n\r\n/* ── Helpers ─────────────────────────────────────────────────────── */\r\n\r\n/**\r\n * Formato da CÉLULA e do export — **com ano**.\r\n *\r\n * Até 2026-08-19 era `{ day: \"2-digit\", month: \"short\" }` → \"14 de mar\", **sem ano**, e\r\n * sem nenhuma forma de mudar. Numa tabela de registros que atravessa anos isso não é\r\n * densidade, é perda de informação: uma usina conectada em 2015 e outra em 2024 apareciam\r\n * idênticas. Foi achado por um agente consumidor, que escreveu `render` próprio pra\r\n * recuperar o ano — e o defeito não estava documentado em lugar nenhum.\r\n *\r\n * Numérico em vez de mês abreviado porque **caiba o ano sem crescer**: \"14/03/2023\" tem\r\n * 10 caracteres contra os 9 de \"14 de mar\", enquanto \"14 de mar. de 2023\" teria 18.\r\n */\r\nconst ptBrData = new Intl.DateTimeFormat(\"pt-BR\", {\r\n day: \"2-digit\",\r\n month: \"2-digit\",\r\n year: \"numeric\",\r\n});\r\n\r\n/**\r\n * Formato COMPACTO, só pro trigger do filtro — sem ano, de propósito.\r\n *\r\n * Ali o valor é um período que o usuário acabou de escolher no calendário, e o trigger\r\n * mostra os dois lados (\"14 mar → 28 mar\") num campo estreito com `truncate`. Pôr o ano\r\n * dobraria o texto e truncaria justamente o segundo lado do período.\r\n */\r\nconst ptBrCompacto = new Intl.DateTimeFormat(\"pt-BR\", {\r\n day: \"2-digit\",\r\n month: \"short\",\r\n});\r\n\r\n/** Célula / export / clipboard — com ano. */\r\nfunction formatData(v: unknown): string {\r\n const d = toDate(v);\r\n if (!d) return \"\";\r\n return ptBrData.format(d);\r\n}\r\n\r\n/** Trigger de filtro — compacto. */\r\nfunction formatShort(v: unknown): string {\r\n const d = toDate(v);\r\n if (!d) return \"\";\r\n return ptBrCompacto.format(d).replace(\".\", \"\");\r\n}\r\n\r\n/* ── Column type ─────────────────────────────────────────────────── */\r\n\r\nexport const DateColumnType: ColumnTypeDefinition = {\r\n type: \"date\",\r\n // `between` (período) é o operador DEFAULT pra datas (operators[0]) — preset\r\n // mais útil e alinhado com o shortcut do header.\r\n operators: [\r\n { id: \"between\", label: \"entre\" },\r\n { id: \"equals\", label: \"é\" },\r\n { id: \"gt\", label: \"depois de\" },\r\n { id: \"lt\", label: \"antes de\" },\r\n { id: \"gte\", label: \"em ou depois de\" },\r\n { id: \"lte\", label: \"em ou antes de\" },\r\n ],\r\n /** Modal Filtros (advanced): trigger compacto que abre Calendar em popover.\r\n * Trigger mostra valor formatado (\"15 fev\" ou \"15 fev → 28 fev\") ou placeholder. */\r\n renderFilterInput: ({ value, onChange, operator }) => {\r\n const isRange = operator === \"between\";\r\n const displayValue = (() => {\r\n if (isRange && Array.isArray(value)) {\r\n const from = formatShort(value[0]);\r\n const to = formatShort(value[1]);\r\n if (from && to) return `${from} → ${to}`;\r\n if (from) return `desde ${from}`;\r\n if (to) return `até ${to}`;\r\n return \"\";\r\n }\r\n return formatShort(value);\r\n })();\r\n return (\r\n <Popover>\r\n <PopoverTrigger asChild>\r\n <button type=\"button\" className={FILTER_FIELD_CLASS}>\r\n <span className={displayValue ? \"truncate\" : \"text-fg-muted opacity-70 truncate\"}>\r\n {displayValue || (isRange ? \"Selecione período\" : \"Selecione data\")}\r\n </span>\r\n <CalendarIcon className=\"size-icon-xs text-fg-muted shrink-0\" />\r\n </button>\r\n </PopoverTrigger>\r\n <PopoverContent align=\"start\" className=\"p-pad-md w-auto\">\r\n {isRange ? (\r\n <Calendar\r\n mode=\"range\"\r\n selected={\r\n Array.isArray(value)\r\n ? { from: toDate(value[0]), to: toDate(value[1]) }\r\n : { from: undefined, to: undefined }\r\n }\r\n onSelect={(r) => {\r\n onChange([\r\n toIsoDate(r?.from ?? null),\r\n toIsoDate(r?.to ?? null),\r\n ]);\r\n }}\r\n />\r\n ) : (\r\n <Calendar\r\n mode=\"single\"\r\n selected={toDate(value)}\r\n onSelect={(d) => onChange(toIsoDate(d ?? null))}\r\n />\r\n )}\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n },\r\n /** Chip popover (fast filter): mesmo Calendar. Se valor for tuple → range mode. */\r\n renderFastFilterInput: ({ value, onChange }) => {\r\n const isRange = Array.isArray(value);\r\n if (isRange) {\r\n const range = {\r\n from: toDate(value[0]),\r\n to: toDate(value[1]),\r\n };\r\n return (\r\n <div className=\"p-pad-md\">\r\n <Calendar\r\n mode=\"range\"\r\n selected={range}\r\n onSelect={(r) => {\r\n onChange([\r\n toIsoDate(r?.from ?? null),\r\n toIsoDate(r?.to ?? null),\r\n ]);\r\n }}\r\n />\r\n </div>\r\n );\r\n }\r\n return (\r\n <div className=\"p-pad-md\">\r\n <Calendar\r\n mode=\"single\"\r\n selected={toDate(value)}\r\n onSelect={(d) => onChange(toIsoDate(d ?? null))}\r\n />\r\n </div>\r\n );\r\n },\r\n /** Formato curto pro chip — \"15 jan\" ou \"15 jan → 28 jan\". */\r\n renderChipValue: (value) => {\r\n if (Array.isArray(value)) {\r\n const from = formatShort(value[0]);\r\n const to = formatShort(value[1]);\r\n if (from && to) return `${from} → ${to}`;\r\n if (from) return `desde ${from}`;\r\n if (to) return `até ${to}`;\r\n return \"\";\r\n }\r\n return formatShort(value);\r\n },\r\n /** Filtro runtime — between aceita tuple [start, end] (inclusive em ambos). */\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = toDateMs(cellValue);\r\n if (cell === null) return false;\r\n const cellDay = dayStart(cell);\r\n\r\n if (operator === \"between\") {\r\n if (!Array.isArray(filterValue)) return null;\r\n const startMs = toDateMs(filterValue[0]);\r\n const endMs = toDateMs(filterValue[1]);\r\n // Range parcial (só um lado preenchido) = comportamento gt ou lt\r\n if (startMs !== null && endMs !== null) {\r\n return cellDay >= dayStart(startMs) && cellDay <= dayStart(endMs);\r\n }\r\n if (startMs !== null) return cellDay >= dayStart(startMs);\r\n if (endMs !== null) return cellDay <= dayStart(endMs);\r\n return false;\r\n }\r\n\r\n const filter = toDateMs(filterValue);\r\n if (filter === null) return false;\r\n const filterDay = dayStart(filter);\r\n if (operator === \"equals\") return cellDay === filterDay;\r\n if (operator === \"gt\") return cellDay > filterDay;\r\n if (operator === \"lt\") return cellDay < filterDay;\r\n if (operator === \"gte\") return cellDay >= filterDay;\r\n if (operator === \"lte\") return cellDay <= filterDay;\r\n return null;\r\n },\r\n\r\n /* G.2 slots */\r\n // `column.valueFormatter` vence o formato do tipo — é o escape hatch pra quem quer\r\n // outro formato (mês escrito, ISO, relativo) sem escrever `render` inteiro.\r\n //\r\n // Isso é o que o próprio `CellRenderProps` já prometia: o campo `column` existe ali\r\n // com o comentário \"campos auxiliares como valueFormatter\", e o JSDoc de `formatValue`\r\n // diz \"aplicado quando consumer não passa `column.valueFormatter`\". Nenhum column-type\r\n // lia esse campo, então na prática `valueFormatter` num `type: \"date\"` mudava export,\r\n // totalizador e clipboard e **não mudava a célula** — a doc afirmava o contrário.\r\n renderCell: ({ value, column }) => (\r\n <span className=\"text-fg-muted tabular-nums\">\r\n {column?.valueFormatter ? column.valueFormatter(value) : formatData(value)}\r\n </span>\r\n ),\r\n formatValue: (v) => formatData(v),\r\n defaultAlign: \"left\",\r\n defaultWidth: 130,\r\n defaultSortable: true,\r\n defaultIcon: CalendarIcon,\r\n};\r\n","import {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from \"@/components/shadcn/select\";\r\nimport { FILTER_FIELD_SIZE, FastSingleSelectList } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\n\r\n/** Normaliza value pra string — aceita escalar OU array (extrai 1º elemento).\r\n * Defensive: presets/saved views podem hidratar filterModel com array mesmo\r\n * pra column.filterType=select; sem isso o Select fica vazio. */\r\nconst toScalar = (v: unknown): string => {\r\n if (v == null) return \"\";\r\n if (Array.isArray(v)) return v.length > 0 ? String(v[0] ?? \"\") : \"\";\r\n return String(v);\r\n};\r\n\r\nexport const SelectColumnType: ColumnTypeDefinition = {\r\n type: \"select\",\r\n operators: [\r\n { id: \"equals\", label: \"é\" },\r\n { id: \"neq\", label: \"não é\" },\r\n { id: \"isEmpty\", label: \"está vazio\" },\r\n { id: \"isNotEmpty\", label: \"não está vazio\" },\r\n ],\r\n renderFilterInput: ({ value, onChange, options, operator }) => {\r\n if (operator === \"isEmpty\" || operator === \"isNotEmpty\") {\r\n return <span className=\"text-fg-muted text-body-sm pl-pad-md\">(sem valor)</span>;\r\n }\r\n return (\r\n <Select value={toScalar(value)} onValueChange={(v) => onChange(v)}>\r\n <SelectTrigger className={FILTER_FIELD_SIZE}>\r\n <SelectValue placeholder=\"Selecionar...\" />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {options?.map((opt) => (\r\n <SelectItem key={String(opt.value)} value={String(opt.value)}>\r\n {opt.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n );\r\n },\r\n renderFastFilterInput: ({ value, onChange, options, onClose }) => (\r\n <FastSingleSelectList\r\n options={(options ?? []).map((opt) => ({\r\n value: String(opt.value),\r\n label: opt.label,\r\n }))}\r\n selected={toScalar(value)}\r\n onSelect={(v) => {\r\n onChange(v);\r\n onClose?.();\r\n }}\r\n />\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = cellValue == null ? \"\" : String(cellValue);\r\n if (operator === \"isEmpty\") return cell.length === 0;\r\n if (operator === \"isNotEmpty\") return cell.length > 0;\r\n const filter = toScalar(filterValue);\r\n if (operator === \"equals\") return cell === filter;\r\n if (operator === \"neq\") return cell !== filter;\r\n return null;\r\n },\r\n};\r\n","import type { ReactNode } from \"react\";\r\nimport { ChevronDown } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Checkbox } from \"@/components/shadcn/checkbox\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/shadcn/popover\";\r\nimport { FILTER_FIELD_CLASS } from \"../_filter-field\";\r\nimport type {\r\n ColumnTypeDefinition,\r\n FastFilterInputProps,\r\n FilterInputProps,\r\n} from \"../column-types.types\";\r\n\r\n/**\r\n * Render do dropdown multiselect — lista checkboxes com toggle.\r\n * Usado em ambos os contextos (modal advanced + fast filter popover).\r\n */\r\n/** Normaliza value pra array — aceita string/number escalar OU array.\r\n * Cenário: presets/saved views podem hidratar o filterModel com `value: \"active\"`\r\n * (escalar) + `operator: \"equals\"`, mas o widget renderiza igual ao multiSelect\r\n * (filterType da column é \"multiSelect\"). Mesmo critério usado em\r\n * `renderChipValue` e `matchesFilter` mais abaixo. */\r\nconst toArray = (value: unknown): Array<string | number> => {\r\n if (Array.isArray(value)) return value as Array<string | number>;\r\n if (value == null || value === \"\") return [];\r\n return [value as string | number];\r\n};\r\n\r\nfunction MultiSelectDropdown({\r\n value,\r\n onChange,\r\n options = [],\r\n renderOption,\r\n}: FastFilterInputProps) {\r\n const selected = toArray(value);\r\n const toggle = (val: string | number) => {\r\n const set = new Set(selected.map(String));\r\n if (set.has(String(val))) set.delete(String(val));\r\n else set.add(String(val));\r\n onChange(Array.from(set));\r\n };\r\n\r\n return (\r\n <div className=\"flex flex-col gap-gp-2xs p-pad-2xs min-w-[200px]\">\r\n {options.length === 0 && (\r\n <p className=\"text-body-xs font-normal text-fg-muted px-pad-md py-pad-sm\">\r\n Sem opções disponíveis\r\n </p>\r\n )}\r\n {options.map((opt) => {\r\n const isChecked = selected.map(String).includes(String(opt.value));\r\n return (\r\n <label\r\n key={String(opt.value)}\r\n className={cn(\r\n \"flex items-center gap-gp-md w-full\",\r\n \"px-pad-md py-pad-sm rounded-radius-md\",\r\n \"text-body-md text-fg-default text-left cursor-pointer\",\r\n \"hover:bg-bg-muted focus-within:bg-bg-muted\",\r\n \"transition-colors duration-100\",\r\n )}\r\n >\r\n <Checkbox\r\n checked={isChecked}\r\n onCheckedChange={() => toggle(opt.value)}\r\n aria-label={opt.label}\r\n className=\"shrink-0\"\r\n />\r\n <span className=\"flex-1 min-w-0 truncate\">\r\n {renderOption ? renderOption(opt) : (opt.label as ReactNode)}\r\n </span>\r\n </label>\r\n );\r\n })}\r\n </div>\r\n );\r\n}\r\n\r\n/** Trigger compacto + popover pra uso no modal advanced — economiza espaço\r\n * comparado a renderizar a lista de checkboxes inline. */\r\nfunction MultiSelectFieldDropdown(props: FilterInputProps) {\r\n const { value, options = [] } = props;\r\n const selected = toArray(value);\r\n const labels = selected.map((v) => {\r\n const opt = options.find((o) => String(o.value) === String(v));\r\n return opt?.label ?? String(v);\r\n });\r\n const display =\r\n labels.length === 0\r\n ? \"\"\r\n : labels.length <= 2\r\n ? labels.join(\", \")\r\n : `${labels.length} selecionados`;\r\n return (\r\n <Popover>\r\n <PopoverTrigger asChild>\r\n <button type=\"button\" className={FILTER_FIELD_CLASS}>\r\n <span className={display ? \"truncate\" : \"text-fg-muted opacity-70 truncate\"}>\r\n {display || \"Selecione...\"}\r\n </span>\r\n <ChevronDown className=\"size-icon-xs text-fg-muted shrink-0\" />\r\n </button>\r\n </PopoverTrigger>\r\n <PopoverContent\r\n align=\"start\"\r\n // mobileSheet OFF: como select normal, o dropdown abre ancorado abaixo do\r\n // trigger no mobile (em vez de virar sheet bottom-up) — facilita a seleção.\r\n mobileSheet={false}\r\n className=\"p-0 w-[var(--radix-popover-trigger-width)] min-w-[200px]\"\r\n >\r\n <MultiSelectDropdown {...props} />\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n\r\nexport const MultiSelectColumnType: ColumnTypeDefinition = {\r\n type: \"multiSelect\",\r\n // Labels alinhados com `DEFAULT_OP_LABELS` do ToolbarApplied — chip e popover\r\n // devem usar o MESMO label pra cada operator (consistência visual). \"é\"/\"não é\"\r\n // ao invés de \"é um de\"/\"não é nenhum de\" — mais curto e bate com o chip.\r\n operators: [\r\n { id: \"isAnyOf\", label: \"é\" },\r\n { id: \"isNoneOf\", label: \"não é\" },\r\n { id: \"isEmpty\", label: \"está vazio\" },\r\n { id: \"isNotEmpty\", label: \"não está vazio\" },\r\n ],\r\n /** Modal advanced: trigger + popover (compacto).\r\n * isEmpty/isNotEmpty: operator se basta — não precisa de input. */\r\n renderFilterInput: (props) => {\r\n if (props.operator === \"isEmpty\" || props.operator === \"isNotEmpty\") {\r\n return <span className=\"text-fg-muted text-body-sm pl-pad-md\">(sem valor)</span>;\r\n }\r\n return <MultiSelectFieldDropdown {...props} />;\r\n },\r\n /** Chip fast filter: já está dentro de um popover, renderiza inline. */\r\n renderFastFilterInput: (props) => <MultiSelectDropdown {...props} />,\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = cellValue == null ? \"\" : String(cellValue);\r\n if (operator === \"isEmpty\") return cell.length === 0;\r\n if (operator === \"isNotEmpty\") return cell.length > 0;\r\n const arr = Array.isArray(filterValue)\r\n ? filterValue.map(String)\r\n : filterValue == null\r\n ? []\r\n : [String(filterValue)];\r\n if (arr.length === 0) return true; // filtro vazio = passa tudo\r\n if (operator === \"isAnyOf\" || operator === \"equals\") {\r\n return arr.includes(cell);\r\n }\r\n if (operator === \"isNoneOf\" || operator === \"neq\") {\r\n return !arr.includes(cell);\r\n }\r\n return null;\r\n },\r\n renderChipValue: (value, options) => {\r\n const arr = Array.isArray(value)\r\n ? (value as Array<string | number>)\r\n : value == null\r\n ? []\r\n : [value as string | number];\r\n if (arr.length === 0) return null;\r\n const labelOf = (v: string | number) =>\r\n options?.find((o) => String(o.value) === String(v))?.label ?? String(v);\r\n if (arr.length === 1) return labelOf(arr[0]);\r\n if (arr.length === 2) return `${labelOf(arr[0])}, ${labelOf(arr[1])}`;\r\n return `${arr.length} selecionados`;\r\n },\r\n};\r\n","import { Check, X, ToggleLeft } from \"lucide-react\";\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from \"@/components/shadcn/select\";\r\nimport { FILTER_FIELD_SIZE, FastSingleSelectList } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\n\r\nfunction toBool(v: unknown): boolean | null {\r\n if (v === true || v === \"true\" || v === 1 || v === \"1\") return true;\r\n if (v === false || v === \"false\" || v === 0 || v === \"0\") return false;\r\n return null;\r\n}\r\n\r\n/** Radix Select exige `value` STRING. O filterModel guarda boolean (true/false),\r\n * então `(value as string)` passava um boolean cru pro Select → nunca casava o\r\n * SelectItem (\"true\"/\"false\"), o valor não aparecia e o popover do chip quebrava\r\n * posicionamento/fechamento. Normaliza pra \"true\"/\"false\"/\"\" (mesma estratégia\r\n * do `toScalar` do select-column-type). */\r\nfunction toBoolStr(v: unknown): string {\r\n const b = toBool(v);\r\n return b === null ? \"\" : b ? \"true\" : \"false\";\r\n}\r\n\r\nexport const BooleanColumnType: ColumnTypeDefinition = {\r\n type: \"boolean\",\r\n operators: [{ id: \"equals\", label: \"é\" }],\r\n renderFilterInput: ({ value, onChange }) => (\r\n <Select\r\n value={toBoolStr(value)}\r\n onValueChange={(v) => onChange(v === \"true\")}\r\n >\r\n <SelectTrigger className={FILTER_FIELD_SIZE}>\r\n <SelectValue placeholder=\"Selecionar...\" />\r\n </SelectTrigger>\r\n <SelectContent>\r\n <SelectItem value=\"true\">Sim</SelectItem>\r\n <SelectItem value=\"false\">Não</SelectItem>\r\n </SelectContent>\r\n </Select>\r\n ),\r\n renderFastFilterInput: ({ value, onChange, onClose }) => (\r\n <FastSingleSelectList\r\n options={[\r\n { value: \"true\", label: \"Sim\" },\r\n { value: \"false\", label: \"Não\" },\r\n ]}\r\n selected={toBoolStr(value)}\r\n onSelect={(v) => {\r\n onChange(v === \"true\");\r\n onClose?.();\r\n }}\r\n />\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = toBool(cellValue);\r\n const filter = toBool(filterValue);\r\n if (cell === null || filter === null) return false;\r\n if (operator === \"equals\") return cell === filter;\r\n return null;\r\n },\r\n renderChipValue: (value) => (value ? \"Sim\" : \"Não\"),\r\n\r\n /* G.2 — render como ícone Check (verde) ou X (cinza). */\r\n renderCell: ({ value }) => {\r\n const b = toBool(value);\r\n if (b === null) return null;\r\n return b ? (\r\n <Check className=\"size-icon-sm text-fg-success\" aria-label=\"Sim\" />\r\n ) : (\r\n <X className=\"size-icon-sm text-fg-muted\" aria-label=\"Não\" />\r\n );\r\n },\r\n formatValue: (v) => {\r\n const b = toBool(v);\r\n if (b === null) return \"\";\r\n return b ? \"Sim\" : \"Não\";\r\n },\r\n defaultAlign: \"center\",\r\n defaultWidth: 80,\r\n defaultSortable: true,\r\n defaultIcon: ToggleLeft,\r\n};\r\n","import { DollarSign } from \"lucide-react\";\r\nimport { Input } from \"@/components/shadcn/input\";\r\nimport { FILTER_FIELD_SIZE } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\nimport { toNumber } from \"../_shared\";\r\n\r\n/** typeOptions esperadas (opcional): { currency?: \"BRL\" | \"USD\" | \"EUR\" | string, locale?: string } */\r\ntype CurrencyTypeOptions = {\r\n currency?: string;\r\n locale?: string;\r\n};\r\n\r\nfunction toCurrency(value: unknown, opts?: CurrencyTypeOptions): string {\r\n if (value == null || value === \"\" || Number.isNaN(Number(value))) return \"\";\r\n const num = Number(value);\r\n const locale = opts?.locale ?? \"pt-BR\";\r\n const currency = opts?.currency ?? \"BRL\";\r\n try {\r\n return new Intl.NumberFormat(locale, {\r\n style: \"currency\",\r\n currency,\r\n minimumFractionDigits: 2,\r\n maximumFractionDigits: 2,\r\n }).format(num);\r\n } catch {\r\n return num.toFixed(2);\r\n }\r\n}\r\n\r\nexport const CurrencyColumnType: ColumnTypeDefinition = {\r\n type: \"currency\",\r\n operators: [\r\n { id: \"equals\", label: \"é\" },\r\n { id: \"gt\", label: \"maior que\" },\r\n { id: \"lt\", label: \"menor que\" },\r\n { id: \"gte\", label: \"maior ou igual a\" },\r\n { id: \"lte\", label: \"menor ou igual a\" },\r\n { id: \"between\", label: \"entre\" },\r\n ],\r\n renderFilterInput: ({ value, onChange, operator }) => {\r\n if (operator === \"between\") {\r\n const arr = Array.isArray(value) ? value : [null, null];\r\n const minVal = toNumber(arr[0]);\r\n const maxVal = toNumber(arr[1]);\r\n return (\r\n <div className=\"flex items-center gap-gp-md\">\r\n <Input\r\n type=\"number\"\r\n size=\"sm\"\r\n className={FILTER_FIELD_SIZE}\r\n placeholder=\"min\"\r\n value={minVal == null ? \"\" : String(minVal)}\r\n onChange={(e) => {\r\n const v = e.target.value === \"\" ? null : Number(e.target.value);\r\n onChange([v, maxVal] as [number | null, number | null]);\r\n }}\r\n />\r\n <span className=\"text-fg-muted\">–</span>\r\n <Input\r\n type=\"number\"\r\n size=\"sm\"\r\n className={FILTER_FIELD_SIZE}\r\n placeholder=\"max\"\r\n value={maxVal == null ? \"\" : String(maxVal)}\r\n onChange={(e) => {\r\n const v = e.target.value === \"\" ? null : Number(e.target.value);\r\n onChange([minVal, v] as [number | null, number | null]);\r\n }}\r\n />\r\n </div>\r\n );\r\n }\r\n return (\r\n <Input\r\n type=\"number\"\r\n size=\"sm\"\r\n className={FILTER_FIELD_SIZE}\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(e) => onChange(e.target.value === \"\" ? null : Number(e.target.value))}\r\n placeholder=\"0,00\"\r\n />\r\n );\r\n },\r\n renderFastFilterInput: ({ value, onChange }) => (\r\n <div className=\"p-pad-md\">\r\n <Input\r\n type=\"number\"\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(e) => onChange(e.target.value === \"\" ? null : Number(e.target.value))}\r\n placeholder=\"0,00\"\r\n autoFocus\r\n />\r\n </div>\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = toNumber(cellValue);\r\n if (cell === null) return false;\r\n if (operator === \"between\") {\r\n if (!Array.isArray(filterValue)) return null;\r\n const min = toNumber(filterValue[0]);\r\n const max = toNumber(filterValue[1]);\r\n if (min !== null && max !== null) return cell >= min && cell <= max;\r\n if (min !== null) return cell >= min;\r\n if (max !== null) return cell <= max;\r\n return false;\r\n }\r\n const filter = toNumber(filterValue);\r\n if (filter === null) return false;\r\n if (operator === \"equals\") return cell === filter;\r\n if (operator === \"gt\") return cell > filter;\r\n if (operator === \"lt\") return cell < filter;\r\n if (operator === \"gte\") return cell >= filter;\r\n if (operator === \"lte\") return cell <= filter;\r\n return null;\r\n },\r\n renderChipValue: (value) => {\r\n if (Array.isArray(value)) {\r\n const from = toNumber(value[0]);\r\n const to = toNumber(value[1]);\r\n if (from != null && to != null) return `${toCurrency(from)} → ${toCurrency(to)}`;\r\n if (from != null) return `≥ ${toCurrency(from)}`;\r\n if (to != null) return `≤ ${toCurrency(to)}`;\r\n return \"\";\r\n }\r\n return toCurrency(value);\r\n },\r\n\r\n /* G.2 slots */\r\n renderCell: ({ value, column }) => {\r\n const opts = column?.typeOptions as CurrencyTypeOptions | undefined;\r\n return (\r\n <span className=\"font-semibold tabular-nums\">{toCurrency(value, opts)}</span>\r\n );\r\n },\r\n formatValue: (v) => toCurrency(v),\r\n defaultAlign: \"right\",\r\n defaultWidth: 130,\r\n defaultSortable: true,\r\n defaultIcon: DollarSign,\r\n};\r\n","import { Percent } from \"lucide-react\";\r\nimport { Input } from \"@/components/shadcn/input\";\r\nimport { FILTER_FIELD_SIZE } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\nimport { toNumber } from \"../_shared\";\r\n\r\n/** typeOptions esperadas (opcional): { decimals?: number, locale?: string } */\r\ntype PercentageTypeOptions = {\r\n decimals?: number;\r\n locale?: string;\r\n};\r\n\r\nfunction toPercent(value: unknown, opts?: PercentageTypeOptions): string {\r\n if (value == null || value === \"\" || Number.isNaN(Number(value))) return \"\";\r\n const num = Number(value);\r\n const decimals = opts?.decimals ?? 0;\r\n const locale = opts?.locale ?? \"pt-BR\";\r\n try {\r\n return new Intl.NumberFormat(locale, {\r\n style: \"percent\",\r\n minimumFractionDigits: decimals,\r\n maximumFractionDigits: decimals,\r\n }).format(num / 100);\r\n } catch {\r\n return `${num.toFixed(decimals)}%`;\r\n }\r\n}\r\n\r\nexport const PercentageColumnType: ColumnTypeDefinition = {\r\n type: \"percentage\",\r\n operators: [\r\n { id: \"equals\", label: \"é\" },\r\n { id: \"gt\", label: \"maior que\" },\r\n { id: \"lt\", label: \"menor que\" },\r\n { id: \"gte\", label: \"maior ou igual a\" },\r\n { id: \"lte\", label: \"menor ou igual a\" },\r\n ],\r\n renderFilterInput: ({ value, onChange }) => (\r\n <Input\r\n type=\"number\"\r\n size=\"sm\"\r\n className={FILTER_FIELD_SIZE}\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(e) => onChange(e.target.value === \"\" ? null : Number(e.target.value))}\r\n placeholder=\"0\"\r\n max={100}\r\n min={0}\r\n />\r\n ),\r\n renderFastFilterInput: ({ value, onChange }) => (\r\n <div className=\"p-pad-md\">\r\n <Input\r\n type=\"number\"\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(e) => onChange(e.target.value === \"\" ? null : Number(e.target.value))}\r\n placeholder=\"0\"\r\n max={100}\r\n min={0}\r\n autoFocus\r\n />\r\n </div>\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = toNumber(cellValue);\r\n const filter = toNumber(filterValue);\r\n if (cell === null || filter === null) return false;\r\n if (operator === \"equals\") return cell === filter;\r\n if (operator === \"gt\") return cell > filter;\r\n if (operator === \"lt\") return cell < filter;\r\n if (operator === \"gte\") return cell >= filter;\r\n if (operator === \"lte\") return cell <= filter;\r\n return null;\r\n },\r\n renderChipValue: (value) => toPercent(value),\r\n\r\n renderCell: ({ value, column }) => {\r\n const opts = column?.typeOptions as PercentageTypeOptions | undefined;\r\n return <span className=\"tabular-nums\">{toPercent(value, opts)}</span>;\r\n },\r\n formatValue: (v) => toPercent(v),\r\n defaultAlign: \"right\",\r\n defaultWidth: 110,\r\n defaultSortable: true,\r\n defaultIcon: Percent,\r\n};\r\n","import { AtSign } from \"lucide-react\";\r\nimport { Input } from \"@/components/shadcn/input\";\r\nimport { FILTER_FIELD_SIZE } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\n\r\nexport const EmailColumnType: ColumnTypeDefinition = {\r\n type: \"email\",\r\n operators: [\r\n { id: \"contains\", label: \"contém\" },\r\n { id: \"equals\", label: \"é\" },\r\n { id: \"neq\", label: \"não é\" },\r\n ],\r\n renderFilterInput: ({ value, onChange }) => (\r\n <Input\r\n type=\"email\"\r\n size=\"sm\"\r\n className={FILTER_FIELD_SIZE}\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder=\"usuario@exemplo.com\"\r\n />\r\n ),\r\n renderFastFilterInput: ({ value, onChange }) => (\r\n <div className=\"p-pad-md\">\r\n <Input\r\n type=\"email\"\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder=\"usuario@exemplo.com\"\r\n autoFocus\r\n />\r\n </div>\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = cellValue == null ? \"\" : String(cellValue).toLowerCase();\r\n const filter = filterValue == null ? \"\" : String(filterValue).toLowerCase();\r\n if (operator === \"contains\") return cell.includes(filter);\r\n if (operator === \"equals\") return cell === filter;\r\n if (operator === \"neq\") return cell !== filter;\r\n return null;\r\n },\r\n\r\n renderCell: ({ value }) => {\r\n const email = value == null ? \"\" : String(value);\r\n if (!email) return null;\r\n return (\r\n <a\r\n href={`mailto:${email}`}\r\n className=\"text-fg-brand hover:underline truncate\"\r\n onClick={(e) => e.stopPropagation()}\r\n >\r\n {email}\r\n </a>\r\n );\r\n },\r\n formatValue: (v) => (v == null ? \"\" : String(v)),\r\n defaultAlign: \"left\",\r\n defaultWidth: 240,\r\n defaultEllipsis: true,\r\n defaultSortable: true,\r\n defaultIcon: AtSign,\r\n};\r\n","import { Phone } from \"lucide-react\";\r\nimport { Input } from \"@/components/shadcn/input\";\r\nimport { FILTER_FIELD_SIZE } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\n\r\nexport const PhoneColumnType: ColumnTypeDefinition = {\r\n type: \"phone\",\r\n operators: [\r\n { id: \"contains\", label: \"contém\" },\r\n { id: \"equals\", label: \"é\" },\r\n ],\r\n renderFilterInput: ({ value, onChange }) => (\r\n <Input\r\n type=\"tel\"\r\n size=\"sm\"\r\n className={FILTER_FIELD_SIZE}\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder=\"+55 ...\"\r\n />\r\n ),\r\n renderFastFilterInput: ({ value, onChange }) => (\r\n <div className=\"p-pad-md\">\r\n <Input\r\n type=\"tel\"\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder=\"+55 ...\"\r\n autoFocus\r\n />\r\n </div>\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const normalize = (s: unknown) =>\r\n s == null ? \"\" : String(s).replace(/\\D/g, \"\").toLowerCase();\r\n const cell = normalize(cellValue);\r\n const filter = normalize(filterValue);\r\n if (operator === \"contains\") return cell.includes(filter);\r\n if (operator === \"equals\") return cell === filter;\r\n return null;\r\n },\r\n\r\n renderCell: ({ value }) => {\r\n const phone = value == null ? \"\" : String(value);\r\n if (!phone) return null;\r\n const digits = phone.replace(/\\D/g, \"\");\r\n return (\r\n <a\r\n href={`tel:${digits}`}\r\n className=\"text-fg-brand hover:underline tabular-nums\"\r\n onClick={(e) => e.stopPropagation()}\r\n >\r\n {phone}\r\n </a>\r\n );\r\n },\r\n formatValue: (v) => (v == null ? \"\" : String(v)),\r\n defaultAlign: \"left\",\r\n defaultWidth: 170,\r\n defaultSortable: false,\r\n defaultIcon: Phone,\r\n};\r\n","import { ExternalLink, Link as LinkIcon } from \"lucide-react\";\r\nimport { Input } from \"@/components/shadcn/input\";\r\nimport { FILTER_FIELD_SIZE } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\n\r\nexport const UrlColumnType: ColumnTypeDefinition = {\r\n type: \"url\",\r\n operators: [\r\n { id: \"contains\", label: \"contém\" },\r\n { id: \"equals\", label: \"é\" },\r\n ],\r\n renderFilterInput: ({ value, onChange }) => (\r\n <Input\r\n type=\"url\"\r\n size=\"sm\"\r\n className={FILTER_FIELD_SIZE}\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder=\"https://...\"\r\n />\r\n ),\r\n renderFastFilterInput: ({ value, onChange }) => (\r\n <div className=\"p-pad-md\">\r\n <Input\r\n type=\"url\"\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder=\"https://...\"\r\n autoFocus\r\n />\r\n </div>\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = cellValue == null ? \"\" : String(cellValue).toLowerCase();\r\n const filter = filterValue == null ? \"\" : String(filterValue).toLowerCase();\r\n if (operator === \"contains\") return cell.includes(filter);\r\n if (operator === \"equals\") return cell === filter;\r\n return null;\r\n },\r\n\r\n renderCell: ({ value }) => {\r\n const url = value == null ? \"\" : String(value);\r\n if (!url) return null;\r\n // Strip protocol pra display, mas mantém no href\r\n const display = url.replace(/^https?:\\/\\//, \"\");\r\n return (\r\n <a\r\n href={url}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"text-fg-brand hover:underline truncate inline-flex items-center gap-gp-2xs\"\r\n onClick={(e) => e.stopPropagation()}\r\n >\r\n <span className=\"truncate\">{display}</span>\r\n <ExternalLink className=\"size-icon-2xs shrink-0 opacity-60\" aria-hidden />\r\n </a>\r\n );\r\n },\r\n formatValue: (v) => (v == null ? \"\" : String(v)),\r\n defaultAlign: \"left\",\r\n defaultWidth: 200,\r\n defaultEllipsis: true,\r\n defaultSortable: false,\r\n defaultIcon: LinkIcon,\r\n};\r\n","import { User } from \"lucide-react\";\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from \"@/components/shadcn/select\";\r\nimport { Avatar } from \"../../../avatar-ig\";\r\nimport { FILTER_FIELD_SIZE } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\n\r\n/** Estrutura esperada em `typeOptions.users` — dicionário id → user info. */\r\ntype UserInfo = {\r\n name: string;\r\n avatar?: string;\r\n initials?: string;\r\n color?: string;\r\n};\r\n\r\ntype UserTypeOptions = {\r\n users?: Record<string, UserInfo>;\r\n};\r\n\r\nfunction lookupUser(value: unknown, opts?: UserTypeOptions): UserInfo | null {\r\n if (value == null) return null;\r\n const key = String(value);\r\n return opts?.users?.[key] ?? null;\r\n}\r\n\r\nfunction initialsFromName(name: string): string {\r\n return name\r\n .split(/\\s+/)\r\n .filter(Boolean)\r\n .slice(0, 2)\r\n .map((s) => s[0]?.toUpperCase() ?? \"\")\r\n .join(\"\");\r\n}\r\n\r\n/** Gera cor consistente pelo hash do nome — quando user não tem `color` no\r\n * typeOptions, usa essa fallback estável (mesmo nome = mesma cor sempre).\r\n * Paleta de 8 cores semânticas. */\r\nconst FALLBACK_COLORS = [\r\n \"#0a3a2e\", // brand-deep\r\n \"#f59e0b\", // warning\r\n \"#8754ec\", // purple\r\n \"#ef4444\", // danger\r\n \"#06b6d4\", // cyan\r\n \"#22c55e\", // success\r\n \"#ec4899\", // pink\r\n \"#3b82f6\", // info\r\n];\r\n\r\nfunction hashName(name: string): number {\r\n let h = 0;\r\n for (let i = 0; i < name.length; i++) {\r\n h = (h * 31 + name.charCodeAt(i)) | 0;\r\n }\r\n return Math.abs(h);\r\n}\r\n\r\nfunction colorForName(name: string): string {\r\n return FALLBACK_COLORS[hashName(name) % FALLBACK_COLORS.length];\r\n}\r\n\r\n\r\nexport const UserColumnType: ColumnTypeDefinition = {\r\n type: \"user\",\r\n operators: [\r\n { id: \"equals\", label: \"é\" },\r\n { id: \"neq\", label: \"não é\" },\r\n { id: \"isAnyOf\", label: \"é um de\" },\r\n ],\r\n renderFilterInput: ({ value, onChange, options }) => (\r\n <Select\r\n value={value == null ? \"\" : String(value)}\r\n onValueChange={(v) => onChange(v)}\r\n >\r\n <SelectTrigger className={FILTER_FIELD_SIZE}>\r\n <SelectValue placeholder=\"Selecione usuário...\" />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {(options ?? []).map((o) => (\r\n <SelectItem key={String(o.value)} value={String(o.value)}>\r\n {o.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n ),\r\n renderFastFilterInput: ({ value, onChange, options }) => (\r\n <div className=\"p-pad-md\">\r\n <Select\r\n defaultOpen\r\n value={value == null ? \"\" : String(value)}\r\n onValueChange={(v) => onChange(v)}\r\n >\r\n <SelectTrigger>\r\n <SelectValue placeholder=\"Selecione usuário...\" />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {(options ?? []).map((o) => (\r\n <SelectItem key={String(o.value)} value={String(o.value)}>\r\n {o.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n </div>\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = cellValue == null ? \"\" : String(cellValue);\r\n if (operator === \"equals\") return cell === String(filterValue ?? \"\");\r\n if (operator === \"neq\") return cell !== String(filterValue ?? \"\");\r\n if (operator === \"isAnyOf\") {\r\n // Aceita escalar (do preset) ou array — normaliza pra array.\r\n const arr = Array.isArray(filterValue)\r\n ? filterValue.map(String)\r\n : filterValue == null\r\n ? []\r\n : [String(filterValue)];\r\n return arr.includes(cell);\r\n }\r\n return null;\r\n },\r\n renderChipValue: (value, options) => {\r\n if (value == null) return \"\";\r\n const opt = options?.find((o) => String(o.value) === String(value));\r\n return opt?.label ?? String(value);\r\n },\r\n\r\n renderCell: ({ value, column }) => {\r\n const opts = column?.typeOptions as UserTypeOptions | undefined;\r\n const user = lookupUser(value, opts);\r\n if (!user) {\r\n // Sem typeOptions.users registrado, fallback: usa o valor raw como nome\r\n const fallbackName = value == null ? \"\" : String(value);\r\n if (!fallbackName) return null;\r\n const initials = initialsFromName(fallbackName);\r\n const color = colorForName(fallbackName);\r\n return (\r\n <span\r\n className=\"inline-flex items-center gap-gp-md whitespace-nowrap\"\r\n title={fallbackName}\r\n >\r\n <Avatar size=\"sm\" colorHex={color}>{initials}</Avatar>\r\n <span className=\"truncate text-fg-default font-medium\">{fallbackName}</span>\r\n </span>\r\n );\r\n }\r\n const initials = user.initials ?? initialsFromName(user.name);\r\n const color = user.color ?? colorForName(user.name);\r\n return (\r\n <span\r\n className=\"inline-flex items-center gap-gp-md whitespace-nowrap\"\r\n title={user.name}\r\n >\r\n <Avatar size=\"sm\" colorHex={color}>{initials}</Avatar>\r\n <span className=\"truncate text-fg-default font-medium\">{user.name}</span>\r\n </span>\r\n );\r\n },\r\n formatValue: (v) => (v == null ? \"\" : String(v)),\r\n defaultAlign: \"left\",\r\n defaultWidth: 170,\r\n defaultSortable: true,\r\n defaultEllipsis: true,\r\n defaultIcon: User,\r\n};\r\n","import { Tag, CheckCircle2 } from \"lucide-react\";\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from \"@/components/shadcn/select\";\r\nimport { Chip } from \"../../../Chip/chip\";\r\nimport { FILTER_FIELD_SIZE } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\nimport { resolveChipColor, findOption } from \"../_shared\";\r\n\r\nexport const BadgeColumnType: ColumnTypeDefinition = {\r\n type: \"badge\",\r\n operators: [\r\n { id: \"equals\", label: \"é\" },\r\n { id: \"neq\", label: \"não é\" },\r\n { id: \"isAnyOf\", label: \"é um de\" },\r\n ],\r\n renderFilterInput: ({ value, onChange, options }) => (\r\n <Select\r\n value={value == null ? \"\" : String(value)}\r\n onValueChange={(v) => onChange(v)}\r\n >\r\n <SelectTrigger className={FILTER_FIELD_SIZE}>\r\n <SelectValue placeholder=\"Selecione...\" />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {(options ?? []).map((o) => (\r\n <SelectItem key={String(o.value)} value={String(o.value)}>\r\n {o.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n ),\r\n renderFastFilterInput: ({ value, onChange, options }) => (\r\n <div className=\"p-pad-md\">\r\n <Select\r\n defaultOpen\r\n value={value == null ? \"\" : String(value)}\r\n onValueChange={(v) => onChange(v)}\r\n >\r\n <SelectTrigger>\r\n <SelectValue placeholder=\"Selecione...\" />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {(options ?? []).map((o) => (\r\n <SelectItem key={String(o.value)} value={String(o.value)}>\r\n {o.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n </div>\r\n ),\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = cellValue == null ? \"\" : String(cellValue);\r\n if (operator === \"equals\") return cell === String(filterValue ?? \"\");\r\n if (operator === \"neq\") return cell !== String(filterValue ?? \"\");\r\n if (operator === \"isAnyOf\") {\r\n // Aceita escalar (do preset) ou array — normaliza pra array.\r\n const arr = Array.isArray(filterValue)\r\n ? filterValue.map(String)\r\n : filterValue == null\r\n ? []\r\n : [String(filterValue)];\r\n return arr.includes(cell);\r\n }\r\n return null;\r\n },\r\n renderChipValue: (value, options) => {\r\n if (value == null) return \"\";\r\n const opt = findOption(value, options);\r\n return opt?.label ?? String(value);\r\n },\r\n\r\n renderCell: ({ value, options }) => {\r\n const opt = findOption(value, options);\r\n if (!opt) {\r\n if (value == null) return null;\r\n return <Chip size=\"sm\">{String(value)}</Chip>;\r\n }\r\n return (\r\n <Chip size=\"sm\" color={resolveChipColor(opt.color)}>\r\n {opt.label}\r\n </Chip>\r\n );\r\n },\r\n formatValue: (v) => (v == null ? \"\" : String(v)),\r\n defaultAlign: \"left\",\r\n defaultWidth: 140,\r\n defaultSortable: true,\r\n defaultIcon: Tag,\r\n};\r\n\r\n/** Alias `status` = `badge`. Status é um conceito semântico (active/pending/etc)\r\n * mas o render é o mesmo de badge. Registramos ambos pra DX. */\r\nexport const StatusColumnType: ColumnTypeDefinition = {\r\n ...BadgeColumnType,\r\n type: \"status\",\r\n defaultIcon: CheckCircle2,\r\n};\r\n","import { Tags, ChevronDown } from \"lucide-react\";\r\nimport { Chip } from \"../../../Chip/chip\";\r\nimport { Checkbox } from \"@/components/shadcn/checkbox\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/shadcn/popover\";\r\nimport { FILTER_FIELD_CLASS } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\nimport { resolveChipColor, findOption, toStringArray } from \"../_shared\";\r\n\r\nexport const TagsColumnType: ColumnTypeDefinition = {\r\n type: \"tags\",\r\n operators: [\r\n { id: \"isAnyOf\", label: \"tem qualquer\" },\r\n { id: \"isNoneOf\", label: \"não tem\" },\r\n { id: \"contains\", label: \"contém\" },\r\n ],\r\n renderFilterInput: ({ value, onChange, options }) => {\r\n const selected = new Set(toStringArray(value));\r\n const toggle = (v: string) => {\r\n const next = new Set(selected);\r\n if (next.has(v)) next.delete(v);\r\n else next.add(v);\r\n onChange(Array.from(next));\r\n };\r\n const labels = Array.from(selected).map((v) => {\r\n const opt = findOption(v, options);\r\n return opt?.label ?? v;\r\n });\r\n const display =\r\n labels.length === 0\r\n ? \"\"\r\n : labels.length <= 2\r\n ? labels.join(\", \")\r\n : `${labels.length} selecionados`;\r\n return (\r\n <Popover>\r\n <PopoverTrigger asChild>\r\n <button type=\"button\" className={FILTER_FIELD_CLASS}>\r\n <span className={display ? \"truncate\" : \"text-fg-muted opacity-70 truncate\"}>\r\n {display || \"Selecione tags...\"}\r\n </span>\r\n <ChevronDown className=\"size-icon-xs text-fg-muted shrink-0\" />\r\n </button>\r\n </PopoverTrigger>\r\n <PopoverContent align=\"start\" className=\"p-0 w-[var(--radix-popover-trigger-width)] min-w-[200px]\">\r\n <div className=\"flex flex-col gap-gp-2xs p-pad-md max-h-[240px] overflow-auto\">\r\n {(options ?? []).map((o) => (\r\n <label\r\n key={String(o.value)}\r\n className=\"flex items-center gap-gp-md p-pad-xs rounded-radius-sm hover:bg-bg-muted cursor-pointer\"\r\n >\r\n <Checkbox\r\n checked={selected.has(String(o.value))}\r\n onCheckedChange={() => toggle(String(o.value))}\r\n />\r\n <span className=\"text-body-md text-fg-default\">{o.label}</span>\r\n </label>\r\n ))}\r\n </div>\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n },\r\n renderFastFilterInput: ({ value, onChange, options }) => {\r\n const selected = new Set(toStringArray(value));\r\n const toggle = (v: string) => {\r\n const next = new Set(selected);\r\n if (next.has(v)) next.delete(v);\r\n else next.add(v);\r\n onChange(Array.from(next));\r\n };\r\n return (\r\n <div className=\"flex flex-col gap-gp-2xs p-pad-md max-h-[240px] overflow-auto\">\r\n {(options ?? []).map((o) => (\r\n <label\r\n key={String(o.value)}\r\n className=\"flex items-center gap-gp-md p-pad-xs rounded-radius-sm hover:bg-bg-muted cursor-pointer\"\r\n >\r\n <Checkbox\r\n checked={selected.has(String(o.value))}\r\n onCheckedChange={() => toggle(String(o.value))}\r\n />\r\n <span className=\"text-body-md text-fg-default\">{o.label}</span>\r\n </label>\r\n ))}\r\n </div>\r\n );\r\n },\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = toStringArray(cellValue);\r\n const filter = toStringArray(filterValue);\r\n if (operator === \"isAnyOf\") return filter.some((f) => cell.includes(f));\r\n if (operator === \"isNoneOf\") return !filter.some((f) => cell.includes(f));\r\n if (operator === \"contains\") return filter.every((f) => cell.includes(f));\r\n return null;\r\n },\r\n renderChipValue: (value, options) => {\r\n const arr = toStringArray(value);\r\n if (arr.length === 0) return \"\";\r\n const labels = arr.map(\r\n (v) => findOption(v, options)?.label ?? v,\r\n );\r\n if (labels.length <= 2) return labels.join(\", \");\r\n return `${labels.length} selecionados`;\r\n },\r\n\r\n renderCell: ({ value, options }) => {\r\n const arr = toStringArray(value);\r\n if (arr.length === 0) return null;\r\n return (\r\n <span className=\"inline-flex items-center flex-wrap gap-gp-2xs\">\r\n {arr.map((v) => {\r\n const opt = findOption(v, options);\r\n return (\r\n <Chip key={v} size=\"sm\" color={resolveChipColor(opt?.color)}>\r\n {opt?.label ?? v}\r\n </Chip>\r\n );\r\n })}\r\n </span>\r\n );\r\n },\r\n formatValue: (v) => toStringArray(v).join(\", \"),\r\n defaultAlign: \"left\",\r\n defaultWidth: 200,\r\n defaultEllipsis: true,\r\n defaultSortable: false,\r\n defaultIcon: Tags,\r\n};\r\n","import { CalendarClock } from \"lucide-react\";\r\nimport { Calendar } from \"@/components/shadcn/calendar\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/shadcn/popover\";\r\nimport { FILTER_FIELD_CLASS } from \"../_filter-field\";\r\nimport type { ColumnTypeDefinition } from \"../column-types.types\";\r\nimport { toDateMs, dayStart, toDate, toIsoDate } from \"../_shared\";\r\n\r\nconst ptBrShort = new Intl.DateTimeFormat(\"pt-BR\", {\r\n day: \"2-digit\",\r\n month: \"short\",\r\n});\r\n\r\n/**\r\n * Célula e export — **com ano**. Até 2026-08-19 era `{day, month, hour, minute}`, sem ano:\r\n * \"14 de mar 09:30\". Mesmo defeito do `type: \"date\"` e pior, porque data-hora costuma ser\r\n * registro de auditoria, onde o ano é o que separa um evento de outro. Numérico pra caber\r\n * o ano sem estourar a coluna: \"14/03/2023 09:30\".\r\n */\r\nconst ptBrDataHora = new Intl.DateTimeFormat(\"pt-BR\", {\r\n day: \"2-digit\",\r\n month: \"2-digit\",\r\n year: \"numeric\",\r\n hour: \"2-digit\",\r\n minute: \"2-digit\",\r\n});\r\n\r\n/** Trigger do filtro — compacto, sem ano (ver a mesma nota em `date-column-type`). */\r\nfunction formatShort(v: unknown): string {\r\n const d = toDate(v);\r\n if (!d) return \"\";\r\n return ptBrShort.format(d).replace(\".\", \"\");\r\n}\r\n\r\n/** Célula / export / clipboard — com ano. */\r\nfunction formatDataHora(v: unknown): string {\r\n const d = toDate(v);\r\n if (!d) return \"\";\r\n return ptBrDataHora.format(d).replace(\",\", \"\");\r\n}\r\n\r\nexport const DatetimeColumnType: ColumnTypeDefinition = {\r\n type: \"datetime\",\r\n // `between` é o default pra datas (operators[0]) — ver date-column-type.\r\n operators: [\r\n { id: \"between\", label: \"entre\" },\r\n { id: \"equals\", label: \"é\" },\r\n { id: \"gt\", label: \"depois de\" },\r\n { id: \"lt\", label: \"antes de\" },\r\n { id: \"gte\", label: \"em ou depois de\" },\r\n { id: \"lte\", label: \"em ou antes de\" },\r\n ],\r\n renderFilterInput: ({ value, onChange, operator }) => {\r\n const isRange = operator === \"between\";\r\n const displayValue = (() => {\r\n if (isRange && Array.isArray(value)) {\r\n const from = formatShort(value[0]);\r\n const to = formatShort(value[1]);\r\n if (from && to) return `${from} → ${to}`;\r\n if (from) return `desde ${from}`;\r\n if (to) return `até ${to}`;\r\n return \"\";\r\n }\r\n return formatShort(value);\r\n })();\r\n return (\r\n <Popover>\r\n <PopoverTrigger asChild>\r\n <button type=\"button\" className={FILTER_FIELD_CLASS}>\r\n <span className={displayValue ? \"truncate\" : \"text-fg-muted opacity-70 truncate\"}>\r\n {displayValue || (isRange ? \"Selecione período\" : \"Selecione data\")}\r\n </span>\r\n <CalendarClock className=\"size-icon-xs text-fg-muted shrink-0\" />\r\n </button>\r\n </PopoverTrigger>\r\n <PopoverContent align=\"start\" className=\"p-pad-md w-auto\">\r\n {isRange ? (\r\n <Calendar\r\n mode=\"range\"\r\n selected={\r\n Array.isArray(value)\r\n ? { from: toDate(value[0]), to: toDate(value[1]) }\r\n : { from: undefined, to: undefined }\r\n }\r\n onSelect={(r) => {\r\n onChange([\r\n toIsoDate(r?.from ?? null),\r\n toIsoDate(r?.to ?? null),\r\n ]);\r\n }}\r\n />\r\n ) : (\r\n <Calendar\r\n mode=\"single\"\r\n selected={toDate(value)}\r\n onSelect={(d) => onChange(toIsoDate(d ?? null))}\r\n />\r\n )}\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n },\r\n renderFastFilterInput: ({ value, onChange }) => {\r\n const isRange = Array.isArray(value);\r\n if (isRange) {\r\n const range = { from: toDate(value[0]), to: toDate(value[1]) };\r\n return (\r\n <div className=\"p-pad-md\">\r\n <Calendar\r\n mode=\"range\"\r\n selected={range}\r\n onSelect={(r) => {\r\n onChange([toIsoDate(r?.from ?? null), toIsoDate(r?.to ?? null)]);\r\n }}\r\n />\r\n </div>\r\n );\r\n }\r\n return (\r\n <div className=\"p-pad-md\">\r\n <Calendar\r\n mode=\"single\"\r\n selected={toDate(value)}\r\n onSelect={(d) => onChange(toIsoDate(d ?? null))}\r\n />\r\n </div>\r\n );\r\n },\r\n renderChipValue: (value) => {\r\n if (Array.isArray(value)) {\r\n const from = formatShort(value[0]);\r\n const to = formatShort(value[1]);\r\n if (from && to) return `${from} → ${to}`;\r\n if (from) return `desde ${from}`;\r\n if (to) return `até ${to}`;\r\n return \"\";\r\n }\r\n return formatShort(value);\r\n },\r\n matchesFilter: (cellValue, filterValue, operator) => {\r\n const cell = toDateMs(cellValue);\r\n if (cell === null) return false;\r\n const cellDay = dayStart(cell);\r\n if (operator === \"between\") {\r\n if (!Array.isArray(filterValue)) return null;\r\n const startMs = toDateMs(filterValue[0]);\r\n const endMs = toDateMs(filterValue[1]);\r\n if (startMs !== null && endMs !== null) {\r\n return cellDay >= dayStart(startMs) && cellDay <= dayStart(endMs);\r\n }\r\n if (startMs !== null) return cellDay >= dayStart(startMs);\r\n if (endMs !== null) return cellDay <= dayStart(endMs);\r\n return false;\r\n }\r\n const filter = toDateMs(filterValue);\r\n if (filter === null) return false;\r\n const filterDay = dayStart(filter);\r\n if (operator === \"equals\") return cellDay === filterDay;\r\n if (operator === \"gt\") return cellDay > filterDay;\r\n if (operator === \"lt\") return cellDay < filterDay;\r\n if (operator === \"gte\") return cellDay >= filterDay;\r\n if (operator === \"lte\") return cellDay <= filterDay;\r\n return null;\r\n },\r\n\r\n // `column.valueFormatter` vence o formato do tipo — mesmo escape hatch do `date`.\r\n renderCell: ({ value, column }) => (\r\n <span className=\"text-fg-muted tabular-nums\">\r\n {column?.valueFormatter ? column.valueFormatter(value) : formatDataHora(value)}\r\n </span>\r\n ),\r\n formatValue: (v) => formatDataHora(v),\r\n defaultAlign: \"left\",\r\n defaultWidth: 160,\r\n defaultSortable: true,\r\n defaultIcon: CalendarClock,\r\n};\r\n","/**\r\n * Column Types Registry — sistema extensivel de tipos de coluna do DataTable.\r\n *\r\n * Cada tipo declara:\r\n * - operators suportados\r\n * - render no modal Filtros (advanced)\r\n * - render no chip popover (fast filter)\r\n * - logica de match runtime (rows.filter)\r\n * - render do chip value (opcional, default uso simples)\r\n *\r\n * Os tipos default são os do `registerMany` no fim deste arquivo — essa lista é a FONTE.\r\n * (Até 2026-08-14 este cabeçalho dizia \"text, number, date, select, multiSelect, boolean\",\r\n * seis de dezesseis: a lista tinha crescido e a frase não.)\r\n *\r\n * ⚠️ **Um arquivo pode registrar MAIS DE UM tipo, e hoje há uma exceção só** — ela custa\r\n * duas buscas a quem procura pelo nome do tipo: **`status` NÃO tem\r\n * `definitions/status-column-type.tsx`**. Ele é registrado dentro de\r\n * `definitions/badge-column-type.tsx` (mesma UI de chip, semântica diferente), e exportado\r\n * como `StatusColumnType`. Procurar pelo nome do tipo — o reflexo natural — não acha nada.\r\n * Ao criar tipo novo, prefira 1 arquivo por tipo; se agrupar, anote aqui.\r\n *\r\n * Pra adicionar tipo customizado:\r\n * columnTypeRegistry.register({ type: \"currency\", operators: [...], renderFilterInput: ..., ... });\r\n */\r\n\r\nexport { columnTypeRegistry } from \"./column-type-registry\";\r\nexport type {\r\n ColumnTypeDefinition,\r\n ColumnTypeId,\r\n ColumnTypeOperator,\r\n ColumnOption,\r\n FilterInputProps,\r\n FastFilterInputProps,\r\n} from \"./column-types.types\";\r\n\r\n// Registra os tipos default automaticamente no import\r\nimport { columnTypeRegistry } from \"./column-type-registry\";\r\nimport { TextColumnType } from \"./definitions/text-column-type\";\r\nimport { NumberColumnType } from \"./definitions/number-column-type\";\r\nimport { DateColumnType } from \"./definitions/date-column-type\";\r\nimport { SelectColumnType } from \"./definitions/select-column-type\";\r\nimport { MultiSelectColumnType } from \"./definitions/multi-select-column-type\";\r\nimport { BooleanColumnType } from \"./definitions/boolean-column-type\";\r\n// Fase G.3 — tipos prebuilt\r\nimport { CurrencyColumnType } from \"./definitions/currency-column-type\";\r\nimport { PercentageColumnType } from \"./definitions/percentage-column-type\";\r\nimport { EmailColumnType } from \"./definitions/email-column-type\";\r\nimport { PhoneColumnType } from \"./definitions/phone-column-type\";\r\nimport { UrlColumnType } from \"./definitions/url-column-type\";\r\nimport { UserColumnType } from \"./definitions/user-column-type\";\r\nimport {\r\n BadgeColumnType,\r\n StatusColumnType,\r\n} from \"./definitions/badge-column-type\";\r\nimport { TagsColumnType } from \"./definitions/tags-column-type\";\r\nimport { DatetimeColumnType } from \"./definitions/datetime-column-type\";\r\n\r\ncolumnTypeRegistry.registerMany([\r\n TextColumnType,\r\n NumberColumnType,\r\n DateColumnType,\r\n SelectColumnType,\r\n MultiSelectColumnType,\r\n BooleanColumnType,\r\n CurrencyColumnType,\r\n PercentageColumnType,\r\n EmailColumnType,\r\n PhoneColumnType,\r\n UrlColumnType,\r\n UserColumnType,\r\n BadgeColumnType,\r\n StatusColumnType,\r\n TagsColumnType,\r\n DatetimeColumnType,\r\n]);\r\n\r\nexport {\r\n TextColumnType,\r\n NumberColumnType,\r\n DateColumnType,\r\n SelectColumnType,\r\n MultiSelectColumnType,\r\n BooleanColumnType,\r\n CurrencyColumnType,\r\n PercentageColumnType,\r\n EmailColumnType,\r\n PhoneColumnType,\r\n UrlColumnType,\r\n UserColumnType,\r\n BadgeColumnType,\r\n StatusColumnType,\r\n TagsColumnType,\r\n DatetimeColumnType,\r\n};\r\n","/**\r\n * Helpers compartilhados de operação de filtro — fonte ÚNICA da escrita no\r\n * FilterModel. Antes essa lógica estava duplicada em 4 lugares (2× no\r\n * use-filter-popover-adapter, 1× no controller, 1× no simple-filter-drawer),\r\n * com comportamentos sutilmente divergentes (o drawer só promovia equals→isAnyOf,\r\n * o controller promovia sem checar array, os adapters checavam array). Aqui há\r\n * um único contrato.\r\n */\r\nimport type {\r\n DataTableColumnDef,\r\n FilterOperator,\r\n} from \"../data-table.types\";\r\nimport { columnTypeRegistry } from \"../column-types\";\r\n\r\n/**\r\n * Operadores que carregam MÚLTIPLOS valores numa condição (chip+popover) —\r\n * multiSelect/tags. O FilterModel guarda 1 item por valor (spread).\r\n */\r\nexport const MULTI_VALUE_OPERATORS = new Set<FilterOperator>([\r\n \"isAnyOf\",\r\n \"isNoneOf\",\r\n]);\r\n\r\n/** ID estável pra um FilterItem — `crypto.randomUUID()` com fallback timestamp. */\r\nexport function genFilterId(): string {\r\n if (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto) {\r\n return crypto.randomUUID();\r\n }\r\n return `f-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\r\n}\r\n\r\n/**\r\n * True quando um `FilterValue` é \"vazio\" (sem efeito) — null/undefined, string\r\n * vazia, ou tupla/array com todos os sides nulos/strings vazias.\r\n *\r\n * ⚠️ Checa só o VALUE. Pra saber se um FilterItem está ATIVO (operadores\r\n * `isEmpty`/`isNotEmpty` são ativos sem valor), use a lógica do processor.\r\n */\r\nexport function filterValueIsEmpty(v: unknown): boolean {\r\n if (v == null) return true;\r\n if (typeof v === \"string\") return v.length === 0;\r\n if (Array.isArray(v)) {\r\n return v.every(\r\n (x) => x == null || (typeof x === \"string\" && x.length === 0),\r\n );\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Promove operador escalar → multi quando a coluna é `filterType: \"multiSelect\"`.\r\n *\r\n * Invariante: coluna multiSelect SEMPRE usa `isAnyOf`/`isNoneOf` (o widget\r\n * MultiSelectFieldDropdown sempre togglea com array). Sem isso, presets\r\n * declarados como `{ field, value }` (operator default `equals`) ou shortcuts\r\n * de header ficam com operator escalar inconsistente — chip mostra\r\n * \"Status = active, pending\" em vez de \"é um de\", e o filterModel cria N items\r\n * separados em vez de 1 grupo.\r\n *\r\n * - `equals` → `isAnyOf`\r\n * - `neq` → `isNoneOf`\r\n * - demais operadores / colunas não-multiSelect → inalterados\r\n */\r\nexport function promoteOperatorForFilterType(\r\n operator: FilterOperator,\r\n filterType: string | undefined,\r\n): FilterOperator {\r\n if (filterType !== \"multiSelect\") return operator;\r\n if (operator === \"equals\") return \"isAnyOf\";\r\n if (operator === \"neq\") return \"isNoneOf\";\r\n return operator;\r\n}\r\n\r\n/** Conveniência: mesma promoção a partir de uma `DataTableColumnDef`. */\r\nexport function promoteOperatorForColumn<T>(\r\n operator: FilterOperator,\r\n col: DataTableColumnDef<T> | undefined,\r\n): FilterOperator {\r\n return promoteOperatorForFilterType(operator, col?.filterType);\r\n}\r\n\r\n/**\r\n * Operador default de um tipo de filtro — derivado do REGISTRY (`operators[0]`),\r\n * fonte única. Sem switch hardcoded: um column-type novo já traz seu default\r\n * correto (ex: currency → equals, date → between, multiSelect → isAnyOf), e\r\n * nunca cai num `\"contains\"` que o tipo não suporta.\r\n */\r\nexport function defaultOperatorForFilterType(\r\n filterType: string | undefined,\r\n): FilterOperator {\r\n const def = columnTypeRegistry.get(filterType ?? \"text\");\r\n return (def.operators?.[0]?.id as FilterOperator) ?? \"contains\";\r\n}\r\n","import { useMemo } from \"react\";\r\nimport { SlidersHorizontal, X } from \"lucide-react\";\r\nimport { FloatingPanel } from \"../../FloatingPanel\";\r\nimport { Button } from \"../../Button/button\";\r\n// FormField do DS — wrapper padrão pra label+input. Sem ele, labels têm\r\n// font-weight inconsistente (font-medium em vez de font-semibold) e cor\r\n// errada no dark (sempre fg-default em vez de fg-muted). Pattern obrigatório\r\n// pra qualquer form do projeto — ver lesson L-023.\r\nimport { FormField } from \"../../FormField\";\r\n// Coupling-aceita: TableToolbar consome utilities do DataTable que são API\r\n// pública (ColumnTypeRegistry, operator mapping, FilterModel types). O mesmo\r\n// pattern já existe em FilterPopover que importa `ColumnOption`. Coupling\r\n// reverso (DataTable → TableToolbar) continua proibido.\r\nimport { columnTypeRegistry } from \"../../DataTable/column-types\";\r\nimport type { ColumnOption } from \"../../DataTable/column-types\";\r\nimport type {\r\n FilterItem,\r\n FilterModel,\r\n FilterOperator,\r\n} from \"../../DataTable/data-table.types\";\r\nimport {\r\n genFilterId,\r\n filterValueIsEmpty as isEmpty,\r\n promoteOperatorForFilterType,\r\n defaultOperatorForFilterType,\r\n} from \"../../DataTable/utils/filter-ops\";\r\nimport type { FilterPopoverColumn } from \"../popovers/filter-popover\";\r\n\r\n/**\r\n * SimpleFilterDrawer — alternativa simplificada ao query builder do FilterPopover.\r\n *\r\n * Renderiza uma lista vertical com TODOS os campos filtráveis das colunas\r\n * (cada linha: label da coluna + widget de filtro do column-type). Sem\r\n * \"Adicionar condição\" — todos os campos estão sempre visíveis.\r\n *\r\n * Aplicação LIVE — não tem botão \"Aplicar\". Cada mudança no widget atualiza\r\n * `filterModel` na hora (mesmo flow do filter shortcut do header). User vê\r\n * a tabela filtrar enquanto edita.\r\n *\r\n * Comportamento:\r\n * - Cada coluna filtrável vira 1 linha (escondida se field listado em hiddenFields)\r\n * - Operator é INFERIDO automaticamente do filterType (multiSelect → isAnyOf,\r\n * text → contains, etc) — user não escolhe operator no drawer (pra isso,\r\n * existe o query builder via chevron)\r\n * - Footer: \"Limpar todos\" remove todos items do filterModel\r\n * - Drawer é non-modal — coexiste com tabela atrás\r\n */\r\n\r\nexport type ToolbarSimpleFilterDrawerProps = {\r\n open: boolean;\r\n onOpenChange: (open: boolean) => void;\r\n\r\n /** Colunas filtráveis — vem do filterPopoverColumns do adapter. */\r\n columns: FilterPopoverColumn[];\r\n\r\n /** FilterModel atual + setter. */\r\n filterModel: FilterModel;\r\n onFilterModelChange: (model: FilterModel) => void;\r\n\r\n /**\r\n * Lista de field names que NÃO devem aparecer no drawer (mesmo sendo\r\n * filtráveis). Útil pra ocultar filtros que só fazem sentido no advanced\r\n * (ex: filtros internos). Default: array vazio (mostra todos).\r\n */\r\n hiddenFields?: string[];\r\n\r\n /** Override do título do drawer. Default: \"Filtros\". */\r\n title?: string;\r\n\r\n /** Override da descrição do drawer. Default: contagem de filtros ativos. */\r\n description?: string;\r\n\r\n /**\r\n * Tamanho do drawer. Default: \"md\" (400px). Use \"lg\" (560px) se há muitos\r\n * campos com widgets largos (dates, multi-select com muitas options).\r\n */\r\n size?: \"sm\" | \"md\" | \"lg\" | \"xl\";\r\n};\r\n\r\n\r\n\r\nexport function ToolbarSimpleFilterDrawer({\r\n open,\r\n onOpenChange,\r\n columns,\r\n filterModel,\r\n onFilterModelChange,\r\n hiddenFields,\r\n title = \"Filtros\",\r\n description,\r\n size = \"md\",\r\n}: ToolbarSimpleFilterDrawerProps) {\r\n const hiddenSet = useMemo(\r\n () => new Set(hiddenFields ?? []),\r\n [hiddenFields],\r\n );\r\n\r\n /** Colunas que aparecem no drawer (não escondidas). */\r\n const visibleColumns = useMemo(\r\n () => columns.filter(c => !hiddenSet.has(c.key)),\r\n [columns, hiddenSet],\r\n );\r\n\r\n /** Map field → items do filterModel pra esse field (pode ser N pra multi). */\r\n const itemsByField = useMemo(() => {\r\n const m = new Map<string, FilterItem[]>();\r\n for (const item of filterModel.items) {\r\n if (!m.has(item.field)) m.set(item.field, []);\r\n m.get(item.field)!.push(item);\r\n }\r\n return m;\r\n }, [filterModel]);\r\n\r\n /** Contagem de filtros ativos (com valor) pra header. */\r\n const activeCount = useMemo(\r\n () => filterModel.items.filter(i => !isEmpty(i.value)).length,\r\n [filterModel],\r\n );\r\n\r\n /** Atualiza valor de um field — substitui items existentes pelo novo array\r\n * de items (1 por valor pra multi; 1 single pros demais). Mantém posição\r\n * original dos items NO array preservando ordem de outros fields. */\r\n const updateFieldValue = (field: string, newValue: unknown, filterType: string | undefined) => {\r\n // multiSelect ⇒ operador sempre isAnyOf/isNoneOf (ver promoteOperatorForFilterType).\r\n const effectiveOperator: FilterOperator = promoteOperatorForFilterType(\r\n defaultOperatorForFilterType(filterType),\r\n filterType,\r\n );\r\n\r\n // Constrói os novos items pro field\r\n const newItems: FilterItem[] = [];\r\n if (effectiveOperator === \"isAnyOf\" || effectiveOperator === \"isNoneOf\") {\r\n const arr = Array.isArray(newValue) ? newValue : (newValue != null && newValue !== \"\" ? [newValue] : []);\r\n for (const v of arr) {\r\n if (v == null || v === \"\") continue;\r\n newItems.push({ id: genFilterId(), field, operator: effectiveOperator, value: v as FilterItem[\"value\"] });\r\n }\r\n } else if (effectiveOperator === \"between\") {\r\n // Date/number range — value é tupla\r\n if (!isEmpty(newValue)) {\r\n newItems.push({ id: genFilterId(), field, operator: effectiveOperator, value: newValue as FilterItem[\"value\"] });\r\n }\r\n } else {\r\n // Single value (text/number/select)\r\n if (!isEmpty(newValue)) {\r\n newItems.push({ id: genFilterId(), field, operator: effectiveOperator, value: newValue as FilterItem[\"value\"] });\r\n }\r\n }\r\n\r\n // Substitui items do field NA POSIÇÃO ORIGINAL — preserva ordem de outros fields\r\n const reconstructed: FilterItem[] = [];\r\n let inserted = false;\r\n for (const item of filterModel.items) {\r\n if (item.field === field) {\r\n if (!inserted) {\r\n reconstructed.push(...newItems);\r\n inserted = true;\r\n }\r\n // skip — substituído pelo spread acima\r\n } else {\r\n reconstructed.push(item);\r\n }\r\n }\r\n if (!inserted) reconstructed.push(...newItems);\r\n\r\n onFilterModelChange({ ...filterModel, items: reconstructed });\r\n };\r\n\r\n /** Remove TODOS items do filterModel. */\r\n const clearAll = () => {\r\n onFilterModelChange({ ...filterModel, items: [] });\r\n };\r\n\r\n return (\r\n <FloatingPanel\r\n open={open}\r\n onOpenChange={onOpenChange}\r\n side=\"right\"\r\n size={size}\r\n // O corpo já aplica px-[18px] py-[14px] próprio abaixo.\r\n bodyPadded={false}\r\n title={title}\r\n description={description ?? `${activeCount} ${activeCount === 1 ? \"filtro ativo\" : \"filtros ativos\"}`}\r\n titleIcon={SlidersHorizontal}\r\n footer={\r\n <div className=\"flex items-center justify-between w-full\">\r\n <Button\r\n variant=\"ghost\"\r\n color=\"secondary\"\r\n size=\"sm\"\r\n onClick={clearAll}\r\n disabled={activeCount === 0}\r\n iconLeft={<X />}\r\n >\r\n Limpar todos\r\n </Button>\r\n <Button\r\n variant=\"filled\"\r\n color=\"primary\"\r\n size=\"sm\"\r\n onClick={() => onOpenChange(false)}\r\n >\r\n Fechar\r\n </Button>\r\n </div>\r\n }\r\n >\r\n {/* Padding interno alinhado com header/footer do FloatingPanel (px-[18px] py-[14px]).\r\n * O body do FloatingPanel é genérico (sem padding default) — cada consumer\r\n * define o seu. Aqui usamos os mesmos valores do header/footer pra ter\r\n * alinhamento visual consistente quando user lê o drawer de cima até a base.\r\n *\r\n * Gap entre campos: form-gap (20px) — token DS dedicado pra forms com\r\n * FormField units empilhados (L-024). Não usar gap-gp-* semântico aqui. */}\r\n <div className=\"flex flex-col gap-form-gap px-[18px] py-[14px]\">\r\n {visibleColumns.length === 0 && (\r\n <p className=\"text-body-sm text-fg-muted text-center py-pad-2xl\">\r\n Nenhuma coluna filtrável disponível.\r\n </p>\r\n )}\r\n\r\n {visibleColumns.map((col) => {\r\n const items = itemsByField.get(col.key) ?? [];\r\n const operator = defaultOperatorForFilterType(col.filterType);\r\n const typeId = col.filterType ?? col.type ?? \"text\";\r\n const def = columnTypeRegistry.get(typeId);\r\n\r\n // currentValue depende do tipo:\r\n // - multi: agregado dos items[].value (array)\r\n // - tuple (between): primeiro item.value (já é tupla)\r\n // - single: primeiro item.value\r\n const isMultiOp = operator === \"isAnyOf\" || operator === \"isNoneOf\";\r\n const isTupleOp = operator === \"between\";\r\n const currentValue = isMultiOp\r\n ? items\r\n .flatMap(it => Array.isArray(it.value) ? (it.value as unknown[]) : (it.value != null ? [it.value] : []))\r\n .filter(v => v != null && v !== \"\")\r\n : isTupleOp\r\n ? items[0]?.value\r\n : items[0]?.value;\r\n\r\n const filterOp = operator;\r\n const options = (col.options ?? []) as ColumnOption[];\r\n\r\n // Usa <FormField> do DS — garante label com font-semibold + cor\r\n // dark-mode-aware (fg-default light / fg-muted dark). Children\r\n // render-prop recebe id pra linkar htmlFor; o widget vem do\r\n // columnTypeRegistry e não consome o id automaticamente, mas o\r\n // padrão visual (label + spacing + dark mode) fica correto.\r\n return (\r\n <FormField\r\n key={col.key}\r\n label={typeof col.label === \"string\" ? col.label : String(col.label)}\r\n >\r\n {() => (\r\n <div className=\"w-full\">\r\n {def.renderFilterInput({\r\n value: currentValue as never,\r\n onChange: (v: unknown) => updateFieldValue(col.key, v, col.filterType),\r\n operator: filterOp as never,\r\n options,\r\n })}\r\n </div>\r\n )}\r\n </FormField>\r\n );\r\n })}\r\n </div>\r\n </FloatingPanel>\r\n );\r\n}\r\n","import {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from \"@/components/shadcn/select\";\r\nimport {\r\n Pagination,\r\n PaginationContent,\r\n PaginationEllipsis,\r\n PaginationFirst,\r\n PaginationItem,\r\n PaginationLast,\r\n PaginationLink,\r\n PaginationNext,\r\n PaginationPrevious,\r\n getPaginationRange,\r\n} from \"@/components/shadcn/pagination\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport type { FooterTableProps } from \"./footer-table.types\";\r\n\r\nconst DEFAULT_PAGE_SIZES = [10, 25, 50, 100];\r\n\r\n/**\r\n * FooterTable — footer completo de tabela com paginação + page-size + range.\r\n *\r\n * Compõe:\r\n * - Select de \"Linhas\" por página (Select do shadcn)\r\n * - Range \"1–10 de 87 rows\"\r\n * - Contagem de seleção opcional (\"· 1 selecionado\")\r\n * - Pagination (« ‹ pages › ») com ellipsis automática\r\n *\r\n * Layout: flex justify-between, mobile empilha (flex-col).\r\n *\r\n * Replica o `.tbl-footer` do design-and-table-v2.\r\n */\r\nexport function FooterTable({\r\n totalCount,\r\n page,\r\n pageSize,\r\n onPageChange,\r\n onPageSizeChange,\r\n pageSizeOptions = DEFAULT_PAGE_SIZES,\r\n selectionCount = 0,\r\n pageSizeLabel = \"Linhas\",\r\n rowLabel = \"rows\",\r\n locale = \"pt-BR\",\r\n hidePageSize,\r\n hideRange,\r\n hideFirstLast,\r\n className,\r\n}: FooterTableProps) {\r\n const lastPage = Math.max(1, Math.ceil(totalCount / pageSize));\r\n const safePage = Math.min(Math.max(1, page), lastPage);\r\n const start = totalCount === 0 ? 0 : (safePage - 1) * pageSize + 1;\r\n const end = Math.min(safePage * pageSize, totalCount);\r\n const pages = getPaginationRange(safePage, lastPage);\r\n\r\n const fmt = (n: number) => n.toLocaleString(locale);\r\n\r\n return (\r\n <footer\r\n className={cn(\r\n // Mobile: só a paginação, centralizada (o bloco esquerdo some).\r\n \"flex flex-col sm:flex-row max-sm:items-center sm:items-center sm:justify-between\",\r\n \"gap-gp-2xl\",\r\n \"text-body-sm font-normal text-fg-default\",\r\n className,\r\n )}\r\n >\r\n {/* ── Left: pageSize + range + selection — oculto no mobile ──── */}\r\n <div className=\"flex flex-wrap items-center gap-gp-2xl max-sm:hidden\">\r\n {!hidePageSize && (\r\n <label className=\"inline-flex items-center gap-gp-md text-fg-muted\">\r\n <span className=\"font-medium\">{pageSizeLabel}</span>\r\n <Select\r\n value={String(pageSize)}\r\n onValueChange={(v) => {\r\n onPageSizeChange(Number(v));\r\n onPageChange(1);\r\n }}\r\n >\r\n <SelectTrigger\r\n className=\"min-h-form-md w-auto pl-pad-2xl pr-pad-xl gap-gp-lg\"\r\n aria-label={pageSizeLabel}\r\n >\r\n <SelectValue />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {pageSizeOptions.map((n) => (\r\n <SelectItem key={n} value={String(n)}>\r\n {n}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n </label>\r\n )}\r\n\r\n {!hideRange && (\r\n <span className=\"text-fg-muted whitespace-nowrap\">\r\n <strong className=\"font-semibold text-fg-default\">\r\n {fmt(start)}–{fmt(end)}\r\n </strong>\r\n {\" de \"}\r\n <strong className=\"font-semibold text-fg-default\">\r\n {fmt(totalCount)}\r\n </strong>\r\n {\" \"}{rowLabel}\r\n </span>\r\n )}\r\n\r\n {selectionCount > 0 && (\r\n <span className=\"text-fg-muted whitespace-nowrap\">\r\n · {selectionCount} selecionado{selectionCount > 1 ? \"s\" : \"\"}\r\n </span>\r\n )}\r\n </div>\r\n\r\n {/* ── Right: Pagination (centralizada no mobile) ─────────────── */}\r\n <Pagination className=\"max-sm:w-full max-sm:justify-center\">\r\n {!hideFirstLast && (\r\n <PaginationFirst\r\n onClick={() => onPageChange(1)}\r\n disabled={safePage === 1}\r\n />\r\n )}\r\n <PaginationPrevious\r\n onClick={() => onPageChange(Math.max(1, safePage - 1))}\r\n disabled={safePage === 1}\r\n />\r\n <PaginationContent>\r\n {pages.map((p, i) =>\r\n p === \"ellipsis\" ? (\r\n <PaginationItem key={`e-${i}`}>\r\n <PaginationEllipsis />\r\n </PaginationItem>\r\n ) : (\r\n <PaginationItem key={p}>\r\n <PaginationLink\r\n isActive={p === safePage}\r\n onClick={() => onPageChange(p)}\r\n aria-label={`Página ${p}`}\r\n >\r\n {p}\r\n </PaginationLink>\r\n </PaginationItem>\r\n ),\r\n )}\r\n </PaginationContent>\r\n <PaginationNext\r\n onClick={() => onPageChange(Math.min(lastPage, safePage + 1))}\r\n disabled={safePage === lastPage}\r\n />\r\n {!hideFirstLast && (\r\n <PaginationLast\r\n onClick={() => onPageChange(lastPage)}\r\n disabled={safePage === lastPage}\r\n />\r\n )}\r\n </Pagination>\r\n </footer>\r\n );\r\n}\r\n\r\n/* ── Skeleton ─────────────────────────────────────────────────────────────── */\r\n\r\nexport type FooterTableSkeletonProps = {\r\n /** Quantos botões de página simular no skeleton. Default: 5. */\r\n pageButtonCount?: number;\r\n className?: string;\r\n};\r\n\r\n/**\r\n * Estado loading do FooterTable — usado pelo DataTable enquanto a primeira\r\n * chamada de `fetchData` não retornou totalCount.\r\n *\r\n * Mantém a mesma silhueta do footer real (page-size select + range + pagination)\r\n * pra evitar layout shift quando o conteúdo chega.\r\n */\r\nexport function FooterTableSkeleton({\r\n pageButtonCount = 5,\r\n className,\r\n}: FooterTableSkeletonProps) {\r\n return (\r\n <footer\r\n aria-busy=\"true\"\r\n aria-label=\"Carregando paginação\"\r\n className={cn(\r\n \"flex flex-col sm:flex-row sm:items-center sm:justify-between\",\r\n \"gap-gp-2xl\",\r\n className,\r\n )}\r\n >\r\n {/* Left: page-size select + range */}\r\n <div className=\"flex items-center gap-gp-2xl\">\r\n <div className=\"h-form-md w-[88px] rounded-radius-md bg-bg-muted animate-pulse\" />\r\n <div className=\"h-[14px] w-[140px] rounded-radius-sm bg-bg-muted animate-pulse\" />\r\n </div>\r\n {/* Right: prev + pages + next (mesma silhueta do <Pagination>) */}\r\n <div className=\"inline-flex items-center gap-gp-xs\">\r\n {Array.from({ length: pageButtonCount + 4 }, (_, i) => (\r\n <div\r\n key={i}\r\n className=\"h-form-md w-form-md rounded-radius-md bg-bg-muted animate-pulse\"\r\n />\r\n ))}\r\n </div>\r\n </footer>\r\n );\r\n}\r\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * Slots tv() pro <Kanban>.\r\n *\r\n * Réplica visual do TblKanban do sandbox `/design-and-table-v2`, agora consumindo\r\n * tokens DS de forma estrita. Header da coluna \"solto\" (mesma bg do col body),\r\n * cards com shadow-sm permanente flutuando sobre bg-muted da coluna.\r\n *\r\n * Valores fora da escala DS (296px width, line-clamp values, offsets posicionais\r\n * dos slots absolute) permanecem como arbitrary literal — calibração visual exata.\r\n */\r\n\r\n/* ── Board (container externo) ───────────────────────────────── */\r\n\r\nexport const root = tv({\r\n base: [\r\n \"flex flex-1 min-h-0 overflow-hidden\",\r\n // Sem moldura outer — kanban assume a área disponível\r\n ],\r\n});\r\n\r\nexport const board = tv({\r\n base: [\r\n \"flex flex-1 gap-gp-2xl p-0\",\r\n \"overflow-x-auto overflow-y-hidden scrollbar-thin\",\r\n ],\r\n});\r\n\r\n/* ── Column ──────────────────────────────────────────────────── */\r\n\r\nexport const column = tv({\r\n base: [\r\n \"flex flex-col w-[296px] shrink-0 max-h-full\",\r\n \"bg-bg-muted rounded-radius-xl\",\r\n \"overflow-hidden\",\r\n ],\r\n});\r\n\r\n/** Header da coluna — solto sobre o bg-muted, sem divider. */\r\nexport const columnHead = tv({\r\n base: [\r\n \"flex items-center gap-gp-md\",\r\n \"px-pad-xl pt-pad-xl pb-pad-sm\",\r\n \"bg-transparent\",\r\n ],\r\n});\r\n\r\nexport const columnDot = tv({\r\n base: \"size-[8px] rounded-radius-full shrink-0\",\r\n});\r\n\r\nexport const columnTitle = tv({\r\n base: [\r\n \"m-0 text-body-md font-medium text-fg-default\",\r\n // Não expande (badge fica grudado à direita do título)\r\n \"shrink min-w-0\",\r\n \"whitespace-nowrap overflow-hidden text-ellipsis\",\r\n ],\r\n});\r\n\r\nexport const columnCount = tv({\r\n base: [\r\n \"inline-flex items-center justify-center shrink-0\",\r\n \"min-w-[20px] h-[20px] px-pad-sm\",\r\n \"bg-bg-muted-hover rounded-radius-full\",\r\n \"text-caption-sm text-fg-muted\",\r\n \"[font-variant-numeric:tabular-nums]\",\r\n ],\r\n});\r\n\r\n/** Wrapper que empurra os botões de ação pro canto direito. */\r\nexport const columnActionsSpacer = tv({\r\n base: \"ml-auto inline-flex items-center gap-gp-2xs\",\r\n});\r\n\r\n/* ── Column body (lista de cards) ────────────────────────────── */\r\n\r\nexport const columnBody = tv({\r\n base: [\r\n \"flex flex-1 flex-col gap-gp-md min-h-0\",\r\n \"px-pad-md pt-sp-xs pb-pad-md\",\r\n \"overflow-y-auto overflow-x-hidden scrollbar-thin\",\r\n ],\r\n});\r\n\r\n/**\r\n * Empty state — flex-1 ocupa o resto do col-body e centraliza vertical.\r\n * Sem bg/border (transparente sobre col bg). Ícone + texto sutis pra não\r\n * competir com cards de colunas vizinhas.\r\n */\r\nexport const columnEmpty = tv({\r\n base: [\r\n \"flex flex-1 flex-col items-center justify-center gap-gp-sm\",\r\n \"py-pad-3xl px-pad-xl\",\r\n \"text-center text-body-sm font-normal text-fg-subtle\",\r\n ],\r\n});\r\n\r\n/** Ícone do empty state — discreto, mesma cor do texto. */\r\nexport const columnEmptyIcon = tv({\r\n base: \"size-icon-md text-fg-subtle opacity-70\",\r\n});\r\n\r\n/**\r\n * Botão \"+ Adicionar\" no rodapé da coluna — dashed centered.\r\n *\r\n * Mantido como `<button>` raw porque o variant dashed-ghost não existe no\r\n * `<Button>` DS. Estilos migrados pra tokens; min-h alinhado com size sm.\r\n */\r\nexport const columnAdd = tv({\r\n base: [\r\n \"inline-flex items-center justify-center gap-gp-sm\",\r\n \"mx-pad-md mb-pad-md mt-sp-2xs\",\r\n \"px-pad-lg min-h-form-sm\",\r\n \"bg-transparent border border-dashed border-border-input rounded-radius-md\",\r\n \"text-body-sm font-medium text-fg-muted\",\r\n \"cursor-pointer\",\r\n \"transition-[background-color,color,border-color] duration-150\",\r\n \"hover:bg-bg-surface hover:text-fg-default hover:border-border-default\",\r\n \"focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand\",\r\n ],\r\n});\r\n\r\n/* ── Card ────────────────────────────────────────────────────── */\r\n\r\nexport const card = tv({\r\n base: [\r\n \"group/kanban-card\",\r\n \"relative flex flex-col gap-gp-md\",\r\n \"p-pad-xl\",\r\n \"bg-bg-surface border border-border-subtle rounded-radius-lg\",\r\n \"shadow-sh-sm\",\r\n \"cursor-pointer text-left\",\r\n \"transition-[padding-left,background-color,border-color,box-shadow] duration-150 ease-out\",\r\n \"hover:border-border-default hover:shadow-sh-md\",\r\n // No light, hover mantém bg-surface (branco) — só border/shadow mudam.\r\n // No dark, escurece o card pra dar profundidade (em vez de \"ficar mais claro\"\r\n // que era o efeito padrão por causa da shadow sobre bg-surface dark).\r\n \"dark:hover:bg-bg-canvas\",\r\n \"focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand\",\r\n ],\r\n variants: {\r\n /** Card selecionado (checkbox marcado) — bg brand-subtle + strip lateral. */\r\n selected: {\r\n true: [\r\n \"bg-bg-brand-subtle border-border-brand-subtle\",\r\n \"before:content-[''] before:absolute before:left-0 before:top-[8px] before:bottom-[8px]\",\r\n \"before:w-[3px] before:bg-bg-brand before:rounded-r-[2px]\",\r\n \"before:pointer-events-none\",\r\n ].join(\" \"),\r\n },\r\n /** Card \"aberto\" no detail panel — destaque com border-brand e ring shadow. */\r\n open: {\r\n true: \"!border-border-brand shadow-sh-ring\",\r\n },\r\n /**\r\n * Reserva 24px à esquerda pro checkbox aparecer sem sobrepor o avatar.\r\n * Aplicado APENAS quando o board tem `onToggleSelect` (showCheckbox=true) —\r\n * caso contrário, hover não desloca o conteúdo (visual mais estável).\r\n */\r\n reserveCheck: {\r\n true: \"hover:pl-[36px] focus-visible:pl-[36px]\",\r\n },\r\n },\r\n compoundVariants: [\r\n // Card selected + reserveCheck → força sempre o pl reservado (mantém strip lateral visível)\r\n { selected: true, reserveCheck: true, class: \"!pl-[36px]\" },\r\n ],\r\n});\r\n\r\n/**\r\n * Checkbox absolute top-left — alinhado vertical com o avatar do head.\r\n *\r\n * Visibility: aparece em hover do card OU foco por teclado (focus-visible).\r\n * `focus-visible` (em vez de `focus-within`) evita que o checkbox permaneça\r\n * visível ao desmarcar via clique — o foco fica retido no input mas\r\n * `focus-visible` só ativa em navegação por teclado.\r\n */\r\nexport const cardCheck = tv({\r\n base: [\r\n \"absolute top-[18px] left-[12px] z-[1]\",\r\n \"opacity-0 transition-opacity duration-150\",\r\n \"group-hover/kanban-card:opacity-100\",\r\n \"group-focus-visible/kanban-card:opacity-100\",\r\n ],\r\n variants: {\r\n selected: { true: \"!opacity-100\" },\r\n },\r\n});\r\n\r\n/**\r\n * Wrapper de posicionamento do menu \"⋯\" no card.\r\n *\r\n * Apenas absolute positioning + opacity transitions. O visual do botão\r\n * (size, focus ring, hover bg) vem do `<Button>` DS.\r\n */\r\nexport const cardMenuSlot = tv({\r\n base: [\r\n \"absolute top-[6px] right-[6px] z-[2]\",\r\n \"opacity-0\",\r\n \"transition-opacity duration-150\",\r\n \"group-hover/kanban-card:opacity-100\",\r\n \"group-focus-visible/kanban-card:opacity-100\",\r\n ],\r\n});\r\n\r\n/** Head do card — avatar + título/subtítulo. Reserva 28px à direita pro menu. */\r\nexport const cardHead = tv({\r\n base: \"flex items-center gap-gp-md pr-[28px]\",\r\n});\r\n\r\nexport const cardTitleWrap = tv({\r\n base: \"flex-1 min-w-0 flex flex-col gap-gp-2xs\",\r\n});\r\n\r\nexport const cardTitle = tv({\r\n base: [\r\n \"text-body-md font-medium text-fg-default leading-[1.3]\",\r\n \"whitespace-nowrap overflow-hidden text-ellipsis\",\r\n ],\r\n});\r\n\r\nexport const cardSubtitle = tv({\r\n base: \"text-caption-sm text-fg-muted [font-variant-numeric:tabular-nums]\",\r\n});\r\n\r\n/** Descrição — line-clamp 2, fg-muted. */\r\nexport const cardDesc = tv({\r\n base: [\r\n \"m-0 text-body-sm font-normal leading-[1.45] text-fg-muted\",\r\n \"[display:-webkit-box] [-webkit-line-clamp:2] [-webkit-box-orient:vertical]\",\r\n \"overflow-hidden\",\r\n ],\r\n});\r\n\r\n/** Meta (chip + valor) — flex space-between. */\r\nexport const cardMeta = tv({\r\n base: \"flex items-center justify-between gap-gp-md\",\r\n});\r\n\r\nexport const cardValue = tv({\r\n base: \"text-body-sm font-semibold text-fg-default [font-variant-numeric:tabular-nums]\",\r\n});\r\n\r\n/** Footer (agent + data) — separador solid no top. */\r\nexport const cardFoot = tv({\r\n base: [\r\n \"flex items-center justify-between gap-gp-md\",\r\n \"pt-pad-md border-t border-border-subtle\",\r\n ],\r\n});\r\n\r\n/* ── DnD slots ─────────────────────────────────────────────── */\r\n\r\n/** Card sendo arrastado — opacity baixa + cursor grabbing. */\r\nexport const cardDragging = tv({\r\n base: \"opacity-40 cursor-grabbing\",\r\n});\r\n\r\n/**\r\n * Coluna candidata válida durante drag (over + canReceiveDrop !== false).\r\n * Outline brand + bg subtle pra indicar drop zone aceita.\r\n */\r\nexport const columnDropTarget = tv({\r\n base: \"outline outline-2 outline-offset-[-2px] outline-border-brand bg-bg-brand-subtle/30 transition-[outline,background-color] duration-150\",\r\n});\r\n\r\n/**\r\n * Coluna que não aceita drop (canReceiveDrop === false).\r\n * Atenuada SEMPRE durante drag (não só when over) — feedback visual que ela\r\n * está \"fora do jogo\". Cursor not-allowed quando o usuário insiste em over.\r\n */\r\nexport const columnDropInvalidDimmed = tv({\r\n base: \"opacity-50 transition-opacity duration-200\",\r\n});\r\n\r\nexport const columnDropInvalidOver = tv({\r\n base: \"cursor-not-allowed\",\r\n});\r\n\r\n/**\r\n * Drop placeholder — slot fino com ícone \"+\" renderizado na posição exata\r\n * onde o card vai aterrissar (antes/depois do card hovered, ou no fim da\r\n * coluna quando hover em área vazia). Visual sutil — uma \"linha\" indicando\r\n * inserção, não um card fantasma grande.\r\n */\r\nexport const dropPlaceholder = tv({\r\n base: [\r\n \"h-[36px] flex items-center justify-center shrink-0\",\r\n \"rounded-radius-md border border-dashed border-border-brand\",\r\n \"bg-bg-brand-subtle/40\",\r\n \"text-fg-brand\",\r\n \"transition-opacity duration-150\",\r\n \"[&>svg]:size-[14px]\",\r\n ],\r\n});\r\n","import { useCallback, useMemo, useState } from \"react\";\nimport {\n PointerSensor,\n KeyboardSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n type DragOverEvent,\n type DragStartEvent,\n} from \"@dnd-kit/core\";\nimport type { KanbanColumn } from \"../kanban.types\";\n\ntype UseKanbanDnDOptions = {\n enabled: boolean;\n columns: KanbanColumn[];\n /** Lookup `cardId → columnId` pra resolver drop em cima de card específico. */\n cardColumnLookup: Map<string, string>;\n onCardMove?: (cardId: string, from: string, to: string) => void | Promise<unknown>;\n};\n\ntype DragStartData = {\n cardId: string;\n fromColumnId: string;\n};\n\n/** Prefixos pra distinguir tipo de droppable no `over.id`. */\nconst COL_PREFIX = \"column:\";\nconst CARD_PREFIX = \"card:\";\n\nexport const droppableIdForColumn = (id: string) => `${COL_PREFIX}${id}`;\nexport const droppableIdForCard = (id: string) => `${CARD_PREFIX}${id}`;\n\n/**\n * Encapsula sensors + handlers do `@dnd-kit/core` pro Kanban.\n *\n * - PointerSensor com `distance: 5` evita ativar drag em cliques curtos\n * (preserva click-to-open do card).\n * - Tracks `activeCardId` + `fromColumnId` durante drag.\n * - Tracks `overColumnId` e `overCardId` em `onDragOver` — quando o cursor está\n * exatamente sobre outro card, `overCardId` aponta pra ele e `overColumnId`\n * resolve pra coluna desse card. Quando está na área vazia da coluna,\n * `overColumnId` aponta pra coluna e `overCardId` é null.\n * - Drop pode resolver pra `column:{id}` (fim da coluna) ou `card:{id}` (antes\n * do card hovered) — em ambos os casos, o `to` é a coluna resultante.\n *\n * Quando `enabled === false`, retorna estado inerte (handlers no-op).\n */\nexport function useKanbanDnD({\n enabled,\n columns,\n cardColumnLookup,\n onCardMove,\n}: UseKanbanDnDOptions) {\n const [dragState, setDragState] = useState<DragStartData | null>(null);\n const [overColumnId, setOverColumnId] = useState<string | null>(null);\n const [overCardId, setOverCardId] = useState<string | null>(null);\n\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n useSensor(KeyboardSensor),\n );\n\n const columnsById = useMemo(() => {\n const map = new Map<string, KanbanColumn>();\n for (const c of columns) map.set(c.id, c);\n return map;\n }, [columns]);\n\n /** Resolve `over.id` (namespaced) → columnId resultante + cardId opcional. */\n const resolveOver = useCallback(\n (overId: string | null): { columnId: string | null; cardId: string | null } => {\n if (!overId) return { columnId: null, cardId: null };\n if (overId.startsWith(COL_PREFIX)) {\n return { columnId: overId.slice(COL_PREFIX.length), cardId: null };\n }\n if (overId.startsWith(CARD_PREFIX)) {\n const cardId = overId.slice(CARD_PREFIX.length);\n return { columnId: cardColumnLookup.get(cardId) ?? null, cardId };\n }\n return { columnId: null, cardId: null };\n },\n [cardColumnLookup],\n );\n\n const handleDragStart = useCallback((event: DragStartEvent) => {\n if (!enabled) return;\n const data = event.active.data.current as DragStartData | undefined;\n if (!data) return;\n setDragState(data);\n }, [enabled]);\n\n const handleDragOver = useCallback((event: DragOverEvent) => {\n if (!enabled) return;\n const overId = event.over ? String(event.over.id) : null;\n const { columnId, cardId } = resolveOver(overId);\n setOverColumnId(columnId);\n setOverCardId(cardId);\n }, [enabled, resolveOver]);\n\n const handleDragEnd = useCallback((event: DragEndEvent) => {\n const active = dragState;\n setDragState(null);\n setOverColumnId(null);\n setOverCardId(null);\n if (!enabled || !active || !event.over) return;\n\n const { columnId: toColumnId } = resolveOver(String(event.over.id));\n if (!toColumnId || toColumnId === active.fromColumnId) return;\n\n const dest = columnsById.get(toColumnId);\n if (dest?.canReceiveDrop === false) return;\n\n onCardMove?.(active.cardId, active.fromColumnId, toColumnId);\n }, [enabled, dragState, columnsById, onCardMove, resolveOver]);\n\n const handleDragCancel = useCallback(() => {\n setDragState(null);\n setOverColumnId(null);\n setOverCardId(null);\n }, []);\n\n return {\n sensors,\n activeCardId: dragState?.cardId ?? null,\n fromColumnId: dragState?.fromColumnId ?? null,\n overColumnId,\n overCardId,\n handleDragStart,\n handleDragOver,\n handleDragEnd,\n handleDragCancel,\n };\n}\n","import { Fragment, useMemo, type KeyboardEvent, type MouseEvent, type ReactNode } from \"react\";\r\nimport { Inbox, MoreHorizontal, Plus } from \"lucide-react\";\r\nimport {\r\n DndContext,\r\n DragOverlay,\r\n closestCorners,\r\n useDraggable,\r\n useDroppable,\r\n} from \"@dnd-kit/core\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Button } from \"@/components/ui/Button\";\r\nimport { Checkbox } from \"@/components/shadcn/checkbox\";\r\nimport {\r\n DropdownMenu,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n DropdownMenuSeparator,\r\n DropdownMenuTrigger,\r\n} from \"@/components/shadcn/dropdown-menu\";\r\nimport * as s from \"./kanban.styles\";\r\nimport {\r\n droppableIdForCard,\r\n droppableIdForColumn,\r\n useKanbanDnD,\r\n} from \"./hooks/use-kanban-dnd\";\r\nimport type {\r\n KanbanCardData,\r\n KanbanColumn,\r\n KanbanMenuItem,\r\n KanbanProps,\r\n KanbanRenderCardParams,\r\n} from \"./kanban.types\";\r\n\r\n/**\r\n * Kanban — board com colunas verticais (estágios) e cards distribuídos.\r\n *\r\n * **Dumb primitive**: recebe `columns` + `cards` e callbacks de interação.\r\n * Não gerencia state de seleção / detail panel / menus / cards — tudo controlado.\r\n *\r\n * **Features**:\r\n * - Layout default do card (avatar/title/subtitle/description/chip/value/footer)\r\n * OU custom via `renderCard` (consumer fornece o miolo, primitive controla\r\n * wrapper/focus/checkbox/menu positioning).\r\n * - Menus padronizados via `getCardMenuItems` / `getColumnMenuItems` (items →\r\n * `<DropdownMenu>` automático) OU callbacks manuais (`onCardMenu` / `onColumnMenu`).\r\n * - DnD entre colunas via `enableDnD` + `onCardMove`. Constraints por coluna\r\n * (`canReceiveDrop`, `canDragFrom`). Primitive **não faz revert** automático;\r\n * consumer commita atualizando `cards` props.\r\n *\r\n * Visual alinhado com TblKanban do sandbox `/design-and-table-v2`, consumindo\r\n * tokens DS estritamente.\r\n */\r\nexport function Kanban({\r\n columns,\r\n cards,\r\n selectedIds,\r\n onToggleSelect,\r\n openCardId,\r\n onOpenCard,\r\n onAddCard,\r\n onColumnMenu,\r\n getColumnMenuItems,\r\n onAddInFooter,\r\n hideFooterAdd = false,\r\n onCardMenu,\r\n getCardMenuItems,\r\n renderCard,\r\n enableDnD = false,\r\n onCardMove,\r\n emptyLabel = \"Nenhum item neste estágio\",\r\n addLabel = \"Adicionar\",\r\n className,\r\n}: KanbanProps) {\r\n // Lookup `cardId → columnId` pro hook resolver drop em cima de card específico.\r\n const cardColumnLookup = useMemo(() => {\r\n const map = new Map<string, string>();\r\n for (const c of cards) map.set(c.id, c.columnId);\r\n return map;\r\n }, [cards]);\r\n\r\n const {\r\n sensors,\r\n activeCardId,\r\n fromColumnId,\r\n overColumnId,\r\n overCardId,\r\n handleDragStart,\r\n handleDragOver,\r\n handleDragEnd,\r\n handleDragCancel,\r\n } = useKanbanDnD({ enabled: enableDnD, columns, cardColumnLookup, onCardMove });\r\n\r\n const activeCard = activeCardId ? cards.find((c) => c.id === activeCardId) ?? null : null;\r\n\r\n const boardContent = (\r\n <div className={s.board()}>\r\n {columns.map((col) => {\r\n const colCards = cards.filter((c) => c.columnId === col.id);\r\n const count = col.count ?? colCards.length;\r\n return (\r\n <KanbanColumnInner\r\n key={col.id}\r\n column={col}\r\n count={count}\r\n cards={colCards}\r\n selectedIds={selectedIds}\r\n onToggleSelect={onToggleSelect}\r\n openCardId={openCardId}\r\n onOpenCard={onOpenCard}\r\n onAddCard={onAddCard}\r\n onColumnMenu={onColumnMenu}\r\n getColumnMenuItems={getColumnMenuItems}\r\n onAddInFooter={onAddInFooter}\r\n hideFooterAdd={hideFooterAdd}\r\n onCardMenu={onCardMenu}\r\n getCardMenuItems={getCardMenuItems}\r\n renderCard={renderCard}\r\n emptyLabel={emptyLabel}\r\n addLabel={addLabel}\r\n enableDnD={enableDnD}\r\n activeCardId={activeCardId}\r\n fromColumnId={fromColumnId}\r\n overColumnId={overColumnId}\r\n overCardId={overCardId}\r\n />\r\n );\r\n })}\r\n </div>\r\n );\r\n\r\n return (\r\n <div className={cn(s.root(), className)} role=\"region\" aria-label=\"Quadro Kanban\">\r\n {enableDnD ? (\r\n <DndContext\r\n sensors={sensors}\r\n collisionDetection={closestCorners}\r\n onDragStart={handleDragStart}\r\n onDragOver={handleDragOver}\r\n onDragEnd={handleDragEnd}\r\n onDragCancel={handleDragCancel}\r\n >\r\n {boardContent}\r\n <DragOverlay dropAnimation={null}>\r\n {activeCard && (\r\n <div className={cn(s.card({ selected: false, open: false }), \"rotate-2 opacity-90 shadow-sh-lg\")}>\r\n <KanbanCardContent\r\n card={activeCard}\r\n selected={false}\r\n open={false}\r\n renderCard={renderCard}\r\n />\r\n </div>\r\n )}\r\n </DragOverlay>\r\n </DndContext>\r\n ) : (\r\n boardContent\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n/* ─────────────────────────────────────────────────────────────\r\n * KanbanColumnInner — uma coluna do board\r\n * ───────────────────────────────────────────────────────────── */\r\n\r\ntype KanbanColumnInnerProps = {\r\n column: KanbanColumn;\r\n count: number;\r\n cards: KanbanCardData[];\r\n enableDnD: boolean;\r\n activeCardId: string | null;\r\n fromColumnId: string | null;\r\n overColumnId: string | null;\r\n overCardId: string | null;\r\n} & Pick<\r\n KanbanProps,\r\n | \"selectedIds\"\r\n | \"onToggleSelect\"\r\n | \"openCardId\"\r\n | \"onOpenCard\"\r\n | \"onAddCard\"\r\n | \"onColumnMenu\"\r\n | \"getColumnMenuItems\"\r\n | \"onAddInFooter\"\r\n | \"hideFooterAdd\"\r\n | \"onCardMenu\"\r\n | \"getCardMenuItems\"\r\n | \"renderCard\"\r\n | \"emptyLabel\"\r\n | \"addLabel\"\r\n>;\r\n\r\nfunction KanbanColumnInner({\r\n column,\r\n count,\r\n cards,\r\n selectedIds,\r\n onToggleSelect,\r\n openCardId,\r\n onOpenCard,\r\n onAddCard,\r\n onColumnMenu,\r\n getColumnMenuItems,\r\n onAddInFooter,\r\n hideFooterAdd,\r\n onCardMenu,\r\n getCardMenuItems,\r\n renderCard,\r\n emptyLabel,\r\n addLabel,\r\n enableDnD,\r\n activeCardId,\r\n fromColumnId,\r\n overColumnId,\r\n overCardId,\r\n}: KanbanColumnInnerProps) {\r\n const canReceive = column.canReceiveDrop !== false;\r\n // Coluna body é droppable pra capturar drop em área vazia (fora de qualquer\r\n // card específico). Registrada mesmo quando inválida — captura `over` pra\r\n // cursor not-allowed; drop em si é bloqueado no hook via canReceiveDrop.\r\n const { setNodeRef } = useDroppable({\r\n id: droppableIdForColumn(column.id),\r\n disabled: !enableDnD,\r\n });\r\n\r\n const isDragInProgress = activeCardId !== null && fromColumnId !== column.id;\r\n const isOverColumn = overColumnId === column.id;\r\n\r\n // Feedback visual em 3 estados:\r\n // - Coluna inválida, drag em progresso: sempre dim (atenuada — está \"fora do jogo\")\r\n // - Coluna inválida + over: extra cursor not-allowed\r\n // - Coluna válida + over: highlight outline brand + placeholder localizado\r\n const showInvalidDim = enableDnD && isDragInProgress && !canReceive;\r\n const showInvalidOver = showInvalidDim && isOverColumn;\r\n const showAsTarget = enableDnD && isDragInProgress && isOverColumn && canReceive;\r\n\r\n // Posição do placeholder dentro da lista de cards:\r\n // - Se hover sobre card específico desta coluna → antes desse card\r\n // - Senão, se hover na área vazia da coluna válida → no fim\r\n const placeholderBeforeCardId =\r\n showAsTarget && overCardId && cards.some((c) => c.id === overCardId) ? overCardId : null;\r\n const showPlaceholderAtEnd = showAsTarget && !placeholderBeforeCardId;\r\n\r\n return (\r\n <section\r\n className={cn(\r\n s.column(),\r\n showInvalidDim && s.columnDropInvalidDimmed(),\r\n showInvalidOver && s.columnDropInvalidOver(),\r\n showAsTarget && s.columnDropTarget(),\r\n )}\r\n data-column-id={column.id}\r\n >\r\n {/* HEAD: dot + título + badge ←—— spacer ——→ + ⋯ */}\r\n <header className={s.columnHead()}>\r\n <span\r\n className={s.columnDot()}\r\n style={{ background: column.dotColor ?? \"var(--color-fg-muted)\" }}\r\n aria-hidden\r\n />\r\n <h3 className={s.columnTitle()}>{column.label}</h3>\r\n <span className={s.columnCount()}>{count}</span>\r\n\r\n <div className={s.columnActionsSpacer()}>\r\n {onAddCard && (\r\n <Button\r\n variant=\"ghost\"\r\n color=\"secondary\"\r\n size=\"icon-2xs\"\r\n aria-label={`Adicionar em ${column.label}`}\r\n title=\"Adicionar\"\r\n onClick={() => onAddCard(column.id)}\r\n >\r\n <Plus />\r\n </Button>\r\n )}\r\n {renderColumnMenu({ column, getColumnMenuItems, onColumnMenu })}\r\n </div>\r\n </header>\r\n\r\n {/* BODY: lista de cards (ou empty state) — droppable */}\r\n <div ref={setNodeRef} className={s.columnBody()}>\r\n {cards.length === 0 && !showAsTarget ? (\r\n <div className={s.columnEmpty()}>\r\n <Inbox className={s.columnEmptyIcon()} aria-hidden />\r\n <span>{emptyLabel}</span>\r\n </div>\r\n ) : (\r\n <>\r\n {cards.map((card) => (\r\n <Fragment key={card.id}>\r\n {/* Placeholder antes deste card se for o card hovered durante drag */}\r\n {placeholderBeforeCardId === card.id && <DropPlaceholder />}\r\n <KanbanCardOuter\r\n card={card}\r\n selected={selectedIds?.has(card.id) ?? false}\r\n open={openCardId === card.id}\r\n showCheckbox={Boolean(onToggleSelect)}\r\n onToggleSelect={onToggleSelect}\r\n onOpenCard={onOpenCard}\r\n onCardMenu={onCardMenu}\r\n getCardMenuItems={getCardMenuItems}\r\n renderCard={renderCard}\r\n enableDnD={enableDnD && column.canDragFrom !== false}\r\n isBeingDragged={activeCardId === card.id}\r\n />\r\n </Fragment>\r\n ))}\r\n {/* Placeholder no fim quando hover em área vazia da coluna válida */}\r\n {showPlaceholderAtEnd && <DropPlaceholder />}\r\n </>\r\n )}\r\n </div>\r\n\r\n {/* FOOTER: botão \"+ Adicionar\" dashed centered */}\r\n {!hideFooterAdd && onAddInFooter && (\r\n <button\r\n type=\"button\"\r\n className={s.columnAdd()}\r\n onClick={() => onAddInFooter(column.id)}\r\n >\r\n <Plus size={14} strokeWidth={2} /> {addLabel}\r\n </button>\r\n )}\r\n </section>\r\n );\r\n}\r\n\r\n/* ─────────────────────────────────────────────────────────────\r\n * Column menu trigger — auto via items OU callback manual\r\n * ───────────────────────────────────────────────────────────── */\r\n\r\nfunction renderColumnMenu({\r\n column,\r\n getColumnMenuItems,\r\n onColumnMenu,\r\n}: {\r\n column: KanbanColumn;\r\n getColumnMenuItems?: (column: KanbanColumn) => KanbanMenuItem[];\r\n onColumnMenu?: (columnId: string, anchor: HTMLElement) => void;\r\n}): ReactNode {\r\n if (getColumnMenuItems) {\r\n const items = getColumnMenuItems(column);\r\n if (items.length === 0) return null;\r\n return (\r\n <KanbanAutoMenu\r\n items={items}\r\n ariaLabel={`Menu de ${column.label}`}\r\n title=\"Mais ações\"\r\n />\r\n );\r\n }\r\n if (onColumnMenu) {\r\n return (\r\n <Button\r\n variant=\"ghost\"\r\n color=\"secondary\"\r\n size=\"icon-2xs\"\r\n aria-label={`Menu de ${column.label}`}\r\n title=\"Mais ações\"\r\n onClick={(e) => onColumnMenu(column.id, e.currentTarget)}\r\n >\r\n <MoreHorizontal />\r\n </Button>\r\n );\r\n }\r\n return null;\r\n}\r\n\r\n/* ─────────────────────────────────────────────────────────────\r\n * DropPlaceholder — indicador visual sutil de posição de inserção\r\n * ───────────────────────────────────────────────────────────── */\r\n\r\nfunction DropPlaceholder() {\r\n return (\r\n <div className={s.dropPlaceholder()} aria-hidden>\r\n <Plus />\r\n </div>\r\n );\r\n}\r\n\r\n/* ─────────────────────────────────────────────────────────────\r\n * KanbanCardOuter — wrapper draggable + droppable + estrutura visual\r\n * ───────────────────────────────────────────────────────────── */\r\n\r\ntype KanbanCardOuterProps = {\r\n card: KanbanCardData;\r\n selected: boolean;\r\n open: boolean;\r\n showCheckbox: boolean;\r\n enableDnD: boolean;\r\n isBeingDragged: boolean;\r\n onToggleSelect?: (cardId: string) => void;\r\n onOpenCard?: (cardId: string) => void;\r\n onCardMenu?: (cardId: string, anchor: HTMLElement) => void;\r\n getCardMenuItems?: (card: KanbanCardData) => KanbanMenuItem[];\r\n renderCard?: (params: KanbanRenderCardParams) => ReactNode;\r\n};\r\n\r\nfunction KanbanCardOuter({\r\n card,\r\n selected,\r\n open,\r\n showCheckbox,\r\n enableDnD,\r\n isBeingDragged,\r\n onToggleSelect,\r\n onOpenCard,\r\n onCardMenu,\r\n getCardMenuItems,\r\n renderCard,\r\n}: KanbanCardOuterProps) {\r\n const {\r\n setNodeRef: setDraggableRef,\r\n attributes,\r\n listeners,\r\n } = useDraggable({\r\n id: card.id,\r\n disabled: !enableDnD,\r\n data: { cardId: card.id, fromColumnId: card.columnId },\r\n });\r\n\r\n // Card também é droppable — necessário pra hook saber em qual card específico\r\n // o cursor está sobre durante drag (placeholder localizado antes deste card).\r\n const { setNodeRef: setDroppableRef } = useDroppable({\r\n id: droppableIdForCard(card.id),\r\n disabled: !enableDnD,\r\n });\r\n\r\n // Combina os 2 refs do dnd-kit num único callback ref aplicável ao DOM node\r\n const setNodeRef = (node: HTMLElement | null) => {\r\n setDraggableRef(node);\r\n setDroppableRef(node);\r\n };\r\n\r\n // NOTA: não aplicamos `transform` no card source — o `<DragOverlay>` no root\r\n // renderiza um clone flutuante seguindo o cursor. O source permanece no lugar\r\n // (com opacity baixa via `cardDragging`), evitando scroll horizontal indesejado\r\n // na coluna quando o card seria translatado pra fora do overflow-y-auto.\r\n\r\n const handleClick = () => onOpenCard?.(card.id);\r\n const handleKey = (e: KeyboardEvent<HTMLDivElement>) => {\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n onOpenCard?.(card.id);\r\n }\r\n };\r\n const handleStop = (e: MouseEvent) => e.stopPropagation();\r\n\r\n // `useDraggable.attributes` já fornece role + tabIndex próprios — quando\r\n // DnD está ativo, usamos esses; quando inativo, fornecemos os nossos pra\r\n // manter o card focável e operável por teclado (Enter/Space abre detalhe).\r\n const a11yProps = enableDnD\r\n ? { ...attributes, ...listeners }\r\n : onOpenCard\r\n ? { role: \"button\" as const, tabIndex: 0 }\r\n : {};\r\n\r\n return (\r\n <article\r\n ref={enableDnD ? setNodeRef : undefined}\r\n className={cn(\r\n s.card({ selected, open, reserveCheck: showCheckbox }),\r\n isBeingDragged && s.cardDragging(),\r\n enableDnD && \"cursor-grab active:cursor-grabbing\",\r\n )}\r\n onClick={onOpenCard ? handleClick : undefined}\r\n onKeyDown={onOpenCard ? handleKey : undefined}\r\n data-card-id={card.id}\r\n {...a11yProps}\r\n >\r\n {showCheckbox && (\r\n <div className={s.cardCheck({ selected })} onClick={handleStop} onPointerDown={handleStop}>\r\n <Checkbox\r\n checked={selected}\r\n onCheckedChange={() => onToggleSelect?.(card.id)}\r\n aria-label=\"Selecionar card\"\r\n />\r\n </div>\r\n )}\r\n\r\n {renderCardMenu({ card, getCardMenuItems, onCardMenu })}\r\n\r\n <KanbanCardContent card={card} selected={selected} open={open} renderCard={renderCard} />\r\n </article>\r\n );\r\n}\r\n\r\n/* ─────────────────────────────────────────────────────────────\r\n * KanbanCardContent — miolo do card (default ou custom)\r\n * ───────────────────────────────────────────────────────────── */\r\n\r\nfunction KanbanCardContent({\r\n card,\r\n selected,\r\n open,\r\n renderCard,\r\n}: {\r\n card: KanbanCardData;\r\n selected: boolean;\r\n open: boolean;\r\n renderCard?: (params: KanbanRenderCardParams) => ReactNode;\r\n}) {\r\n if (renderCard) {\r\n return <Fragment>{renderCard({ card, selected, open })}</Fragment>;\r\n }\r\n\r\n return (\r\n <Fragment>\r\n {/* HEAD: avatar + título/subtítulo */}\r\n {(card.avatar || card.title || card.subtitle) && (\r\n <header className={s.cardHead()}>\r\n {card.avatar}\r\n <div className={s.cardTitleWrap()}>\r\n {card.title && <div className={s.cardTitle()}>{card.title}</div>}\r\n {card.subtitle && <div className={s.cardSubtitle()}>{card.subtitle}</div>}\r\n </div>\r\n </header>\r\n )}\r\n\r\n {card.description && <p className={s.cardDesc()}>{card.description}</p>}\r\n\r\n {(card.chip || card.value) && (\r\n <div className={s.cardMeta()}>\r\n {card.chip ?? <span />}\r\n {card.value && <span className={s.cardValue()}>{card.value}</span>}\r\n </div>\r\n )}\r\n\r\n {(card.footerLeft || card.footerRight) && (\r\n <footer className={s.cardFoot()}>\r\n {card.footerLeft ?? <span />}\r\n {card.footerRight ?? <span />}\r\n </footer>\r\n )}\r\n </Fragment>\r\n );\r\n}\r\n\r\n/* ─────────────────────────────────────────────────────────────\r\n * Card menu trigger — auto via items OU callback manual\r\n * ───────────────────────────────────────────────────────────── */\r\n\r\nfunction renderCardMenu({\r\n card,\r\n getCardMenuItems,\r\n onCardMenu,\r\n}: {\r\n card: KanbanCardData;\r\n getCardMenuItems?: (card: KanbanCardData) => KanbanMenuItem[];\r\n onCardMenu?: (cardId: string, anchor: HTMLElement) => void;\r\n}): ReactNode {\r\n const handleStop = (e: MouseEvent) => e.stopPropagation();\r\n\r\n if (getCardMenuItems) {\r\n const items = getCardMenuItems(card);\r\n if (items.length === 0) return null;\r\n return (\r\n <div className={s.cardMenuSlot()} onClick={handleStop} onPointerDown={handleStop}>\r\n <KanbanAutoMenu items={items} ariaLabel=\"Ações do card\" title=\"Ações\" />\r\n </div>\r\n );\r\n }\r\n if (onCardMenu) {\r\n return (\r\n <div className={s.cardMenuSlot()} onClick={handleStop} onPointerDown={handleStop}>\r\n <Button\r\n variant=\"ghost\"\r\n color=\"secondary\"\r\n size=\"icon-2xs\"\r\n aria-label=\"Ações do card\"\r\n title=\"Ações\"\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onCardMenu(card.id, e.currentTarget);\r\n }}\r\n >\r\n <MoreHorizontal />\r\n </Button>\r\n </div>\r\n );\r\n }\r\n return null;\r\n}\r\n\r\n/* ─────────────────────────────────────────────────────────────\r\n * KanbanAutoMenu — renderiza items padronizados via DropdownMenu DS\r\n * ───────────────────────────────────────────────────────────── */\r\n\r\nfunction KanbanAutoMenu({\r\n items,\r\n ariaLabel,\r\n title,\r\n}: {\r\n items: KanbanMenuItem[];\r\n ariaLabel: string;\r\n title: string;\r\n}) {\r\n return (\r\n <DropdownMenu>\r\n <DropdownMenuTrigger asChild>\r\n <Button\r\n variant=\"ghost\"\r\n color=\"secondary\"\r\n size=\"icon-2xs\"\r\n aria-label={ariaLabel}\r\n title={title}\r\n >\r\n <MoreHorizontal />\r\n </Button>\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent align=\"end\" sideOffset={4}>\r\n {items.map((item, idx) => {\r\n if (item.separator) {\r\n return <DropdownMenuSeparator key={`sep-${idx}`} />;\r\n }\r\n return (\r\n <DropdownMenuItem\r\n key={item.label ?? idx}\r\n variant={item.destructive ? \"destructive\" : \"default\"}\r\n disabled={item.disabled}\r\n onSelect={() => item.onClick?.()}\r\n >\r\n {item.icon}\r\n {item.label}\r\n </DropdownMenuItem>\r\n );\r\n })}\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n );\r\n}\r\n","import { tv, type VariantProps } from \"@/utils/tv\";\r\n\r\n/**\r\n * Slots tv() do <List>. Card reusa a \"receita\" do TableCardRow/Kanban\r\n * (bg-surface + border + estados selected/open com strip lateral brand).\r\n * Só tokens DS. Connectors via border-default.\r\n */\r\nexport const listStyles = tv({\r\n slots: {\r\n root: \"flex flex-col\",\r\n /* grupos */\r\n group: \"flex flex-col gap-gp-md\",\r\n groupHeader: \"flex items-center gap-gp-md px-pad-xs py-pad-2xs select-none\",\r\n groupToggle:\r\n \"inline-flex items-center justify-center size-[20px] shrink-0 rounded-radius-sm text-fg-muted transition-transform duration-150 hover:text-fg-default focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand\",\r\n groupDot: \"size-[8px] rounded-radius-full shrink-0\",\r\n groupTitle: \"text-body-md font-semibold text-fg-default\",\r\n groupCount:\r\n \"inline-flex items-center justify-center min-w-[20px] h-[20px] px-pad-sm bg-bg-muted rounded-radius-full text-caption-sm text-fg-muted [font-variant-numeric:tabular-nums]\",\r\n groupAdd:\r\n \"ml-auto inline-flex items-center gap-gp-xs text-body-sm font-medium text-fg-muted hover:text-fg-default transition-colors\",\r\n groupBody: \"flex flex-col\",\r\n\r\n /* card (item) */\r\n item:\r\n \"group/list-item relative flex items-center gap-gp-lg w-full p-pad-xl bg-bg-surface border border-border-subtle dark:border-border-default rounded-radius-lg shadow-sh-sm text-left transition-[background-color,border-color,box-shadow,padding] duration-150 ease-out\",\r\n handle:\r\n \"inline-flex items-center justify-center shrink-0 -ml-pad-xs size-[20px] text-fg-subtle hover:text-fg-muted cursor-grab active:cursor-grabbing transition-colors [&>svg]:size-[16px]\",\r\n checkbox: \"shrink-0\",\r\n leading: \"shrink-0 flex items-center\",\r\n content: \"flex min-w-0 flex-1 flex-col gap-gp-2xs\",\r\n title: \"text-body-md font-medium text-fg-default leading-[1.3] truncate\",\r\n subtitle: \"text-caption-sm text-fg-muted truncate\",\r\n description:\r\n \"text-body-sm text-fg-muted [display:-webkit-box] [-webkit-line-clamp:2] [-webkit-box-orient:vertical] overflow-hidden\",\r\n /* meta em colunas (ROLE/STATUS/LAST SEEN) */\r\n metaRow: \"hidden md:flex items-center gap-gp-3xl shrink-0\",\r\n metaCol: \"flex flex-col gap-gp-2xs min-w-[88px]\",\r\n metaLabel:\r\n \"text-caption-sm font-semibold uppercase tracking-wider text-fg-subtle\",\r\n metaValue: \"text-body-sm text-fg-default\",\r\n trailing: \"shrink-0 flex items-center gap-gp-md\",\r\n actions: \"shrink-0 flex items-center ml-pad-xs\",\r\n\r\n /* hierarquia */\r\n indent: \"shrink-0 self-stretch relative\",\r\n connector: \"absolute bg-fg-subtle/55\",\r\n\r\n /* dnd / estados */\r\n /** Painel sutil por grupo (prop groupSurface) — \"card fino\" que diferencia da superfície.\r\n * Padding uniforme (top == bottom); header tem só pb (gap pro 1º card). */\r\n groupPanel: \"rounded-radius-xl border border-border-subtle bg-bg-muted/50 p-pad-lg\",\r\n /** Realce da área de destino durante drag (isDraggingOver). */\r\n dropZoneActive:\r\n \"rounded-radius-lg bg-bg-brand-subtle/40 outline outline-1 outline-border-brand-subtle transition-colors\",\r\n emptyState:\r\n \"flex flex-col items-center justify-center gap-gp-sm py-pad-4xl px-pad-xl text-center text-body-sm text-fg-subtle\",\r\n skeleton:\r\n \"w-full p-pad-xl bg-bg-surface border border-border-subtle rounded-radius-lg\",\r\n skeletonBar: \"h-[12px] rounded-radius-full bg-bg-muted animate-pulse\",\r\n },\r\n\r\n variants: {\r\n density: {\r\n // root = standard (+2px vs groupBody, a pedido); groupBody (grouped) e o\r\n // gap inline do hierárquico não mudam.\r\n comfortable: { groupBody: \"gap-gp-md\", root: \"gap-gp-lg\" },\r\n compact: { groupBody: \"gap-gp-sm\", root: \"gap-gp-md\" },\r\n },\r\n clickable: {\r\n true: {\r\n item: \"cursor-pointer hover:border-border-default hover:shadow-sh-md dark:hover:bg-bg-canvas\",\r\n },\r\n },\r\n selected: {\r\n true: {\r\n item: [\r\n \"bg-bg-brand-subtle border-border-brand-subtle\",\r\n \"before:content-[''] before:absolute before:left-0 before:top-[8px] before:bottom-[8px]\",\r\n \"before:w-[3px] before:bg-bg-brand before:rounded-r-[2px] before:pointer-events-none\",\r\n ].join(\" \"),\r\n },\r\n },\r\n open: {\r\n true: { item: \"!border-border-brand shadow-sh-ring\" },\r\n },\r\n /** Card em arrasto (hello-pangea move o próprio elemento): elevar, não esmaecer. */\r\n dragging: {\r\n true: { item: \"shadow-sh-lg !border-border-brand-subtle\" },\r\n },\r\n },\r\n\r\n defaultVariants: {\r\n density: \"comfortable\",\r\n },\r\n});\r\n\r\nexport type ListStyleVariants = VariantProps<typeof listStyles>;\r\n","import { Fragment, type HTMLAttributes, type MouseEvent, type ReactNode } from \"react\";\r\nimport type {\r\n DraggableProvidedDraggableProps,\r\n DraggableProvidedDragHandleProps,\r\n} from \"@hello-pangea/dnd\";\r\nimport { GripVertical, MoreHorizontal } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Button } from \"@/components/ui/Button\";\r\nimport { Checkbox } from \"@/components/shadcn/checkbox\";\r\nimport {\r\n DropdownMenu,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n DropdownMenuSeparator,\r\n DropdownMenuTrigger,\r\n} from \"@/components/shadcn/dropdown-menu\";\r\nimport { listStyles, type ListStyleVariants } from \"./list.styles\";\r\nimport type {\r\n ListItemData,\r\n ListMenuItem,\r\n ListRenderState,\r\n} from \"./list.types\";\r\n\r\ntype ListItemProps = {\r\n item: ListItemData;\r\n state: ListRenderState;\r\n density: NonNullable<ListStyleVariants[\"density\"]>;\r\n\r\n renderItem?: (item: ListItemData, state: ListRenderState) => ReactNode;\r\n getMenuItems?: (item: ListItemData) => ListMenuItem[];\r\n onClick?: (id: string) => void;\r\n\r\n /* seleção */\r\n selectable?: boolean;\r\n onToggleSelect?: (id: string) => void;\r\n\r\n /* hierarquia — toggle de expandir renderizado à esquerda */\r\n expandToggle?: ReactNode;\r\n\r\n /* dnd (vindo do layout via @hello-pangea Draggable) */\r\n innerRef?: (el: HTMLElement | null) => void;\r\n draggableProps?: DraggableProvidedDraggableProps;\r\n dragHandleProps?: DraggableProvidedDragHandleProps | null;\r\n showHandle?: boolean;\r\n\r\n className?: string;\r\n};\r\n\r\n/**\r\n * <ListItem> — card (row) do List. Wrapper sempre controlado pelo componente\r\n * (estados selected/open/dragging, checkbox, handle, menu). O miolo é o layout\r\n * default por slots OU `renderItem` (override). Não use direto pra montar a\r\n * lista — é renderizado pelos layouts do `<List>`.\r\n */\r\nexport function ListItem({\r\n item,\r\n state,\r\n density,\r\n renderItem,\r\n getMenuItems,\r\n onClick,\r\n selectable,\r\n onToggleSelect,\r\n expandToggle,\r\n innerRef,\r\n draggableProps,\r\n dragHandleProps,\r\n showHandle,\r\n className,\r\n}: ListItemProps) {\r\n const s = listStyles({\r\n density,\r\n selected: state.selected,\r\n open: state.open,\r\n dragging: state.dragging,\r\n clickable: Boolean(onClick),\r\n });\r\n\r\n const menuItems = getMenuItems?.(item) ?? [];\r\n const stop = (e: MouseEvent) => e.stopPropagation();\r\n\r\n const handleClick = (e: MouseEvent<HTMLDivElement>) => {\r\n if (!onClick) return;\r\n if (\r\n (e.target as HTMLElement).closest(\r\n 'button, a, input, label, [role=\"menu\"], [role=\"menuitem\"], [data-slot=\"list-actions\"]',\r\n )\r\n ) {\r\n return;\r\n }\r\n onClick(item.id);\r\n };\r\n\r\n return (\r\n <div\r\n ref={innerRef}\r\n role=\"article\"\r\n aria-selected={state.selected || undefined}\r\n className={cn(s.item(), className)}\r\n onClick={onClick ? handleClick : undefined}\r\n {...(draggableProps as HTMLAttributes<HTMLDivElement>)}\r\n >\r\n {showHandle && (\r\n <span\r\n className={s.handle()}\r\n aria-label=\"Arrastar\"\r\n onClick={stop}\r\n {...dragHandleProps}\r\n >\r\n <GripVertical />\r\n </span>\r\n )}\r\n\r\n {selectable && (\r\n <span className={s.checkbox()} onClick={stop} onPointerDown={stop}>\r\n <Checkbox\r\n checked={state.selected}\r\n onCheckedChange={() => onToggleSelect?.(item.id)}\r\n aria-label=\"Selecionar item\"\r\n />\r\n </span>\r\n )}\r\n\r\n {expandToggle}\r\n\r\n {renderItem ? (\r\n <Fragment>{renderItem(item, state)}</Fragment>\r\n ) : (\r\n <Fragment>\r\n {item.leading && <span className={s.leading()}>{item.leading}</span>}\r\n\r\n <div className={s.content()}>\r\n <div className={s.title()}>{item.title}</div>\r\n {item.subtitle && <div className={s.subtitle()}>{item.subtitle}</div>}\r\n {item.description && (\r\n <div className={s.description()}>{item.description}</div>\r\n )}\r\n </div>\r\n\r\n {item.meta && item.meta.length > 0 && (\r\n <div className={s.metaRow()}>\r\n {item.meta.map((m, i) => (\r\n <div\r\n key={i}\r\n className={cn(s.metaCol(), m.align === \"end\" && \"items-end text-right\")}\r\n >\r\n <span className={s.metaLabel()}>{m.label}</span>\r\n <span className={s.metaValue()}>{m.value}</span>\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {item.trailing && <div className={s.trailing()}>{item.trailing}</div>}\r\n </Fragment>\r\n )}\r\n\r\n {menuItems.length > 0 && (\r\n <div className={s.actions()} data-slot=\"list-actions\" onClick={stop} onPointerDown={stop}>\r\n <ListAutoMenu items={menuItems} />\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\nfunction ListAutoMenu({ items }: { items: ListMenuItem[] }) {\r\n return (\r\n <DropdownMenu>\r\n <DropdownMenuTrigger asChild>\r\n <Button variant=\"ghost\" color=\"secondary\" size=\"icon-2xs\" aria-label=\"Ações\" title=\"Ações\">\r\n <MoreHorizontal />\r\n </Button>\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent align=\"end\" sideOffset={4}>\r\n {items.map((item, idx) =>\r\n item.separator ? (\r\n <DropdownMenuSeparator key={`sep-${idx}`} />\r\n ) : (\r\n <DropdownMenuItem\r\n key={item.label?.toString() ?? idx}\r\n variant={item.destructive ? \"destructive\" : \"default\"}\r\n disabled={item.disabled}\r\n onSelect={() => item.onClick?.()}\r\n >\r\n {item.icon}\r\n {item.label}\r\n </DropdownMenuItem>\r\n ),\r\n )}\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n );\r\n}\r\n","import type { ReactNode } from \"react\";\r\nimport { Draggable } from \"@hello-pangea/dnd\";\r\nimport { type ListStyleVariants } from \"../list.styles\";\r\nimport { ListItem } from \"../list-item\";\r\nimport type {\r\n ListItemData,\r\n ListMenuItem,\r\n ListRenderState,\r\n} from \"../list.types\";\r\n\r\ntype SortableListItemProps = {\r\n item: ListItemData;\r\n index: number;\r\n density: NonNullable<ListStyleVariants[\"density\"]>;\r\n enableDnD: boolean;\r\n open: boolean;\r\n selectable?: boolean;\r\n selected: boolean;\r\n onToggleSelect?: (id: string) => void;\r\n onClick?: (id: string) => void;\r\n renderItem?: (item: ListItemData, state: ListRenderState) => ReactNode;\r\n getMenuItems?: (item: ListItemData) => ListMenuItem[];\r\n};\r\n\r\n/**\r\n * Row da lista. Sem DnD → ListItem direto. Com DnD → envolve num `<Draggable>`\r\n * do @hello-pangea/dnd: o elemento real é movido (física natural de lista) e o\r\n * `snapshot.isDragging` dispara a elevação visual (sombra + border).\r\n */\r\nexport function SortableListItem({\r\n item,\r\n index,\r\n density,\r\n enableDnD,\r\n open,\r\n selectable,\r\n selected,\r\n onToggleSelect,\r\n onClick,\r\n renderItem,\r\n getMenuItems,\r\n}: SortableListItemProps) {\r\n const base = {\r\n item,\r\n density,\r\n renderItem,\r\n getMenuItems,\r\n onClick,\r\n selectable,\r\n onToggleSelect,\r\n };\r\n\r\n if (!enableDnD) {\r\n return (\r\n <ListItem\r\n {...base}\r\n state={{ selected, open, dragging: false, depth: 0 }}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <Draggable draggableId={item.id} index={index} isDragDisabled={item.canDrag === false}>\r\n {(provided, snapshot) => (\r\n <ListItem\r\n {...base}\r\n state={{ selected, open, dragging: snapshot.isDragging, depth: 0 }}\r\n innerRef={provided.innerRef}\r\n draggableProps={provided.draggableProps}\r\n dragHandleProps={provided.dragHandleProps}\r\n showHandle={item.canDrag !== false}\r\n />\r\n )}\r\n </Draggable>\r\n );\r\n}\r\n","import type { ReactNode } from \"react\";\r\nimport { Droppable } from \"@hello-pangea/dnd\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { listStyles, type ListStyleVariants } from \"../list.styles\";\r\nimport { SortableListItem } from \"./_sortable-item\";\r\nimport type {\r\n ListItemData,\r\n ListMenuItem,\r\n ListRenderState,\r\n} from \"../list.types\";\r\n\r\ntype StandardLayoutProps = {\r\n items: ListItemData[];\r\n droppableId: string;\r\n density: NonNullable<ListStyleVariants[\"density\"]>;\r\n enableDnD: boolean;\r\n selectable?: boolean;\r\n selectedIds: Set<string>;\r\n openId?: string;\r\n onToggleSelect?: (id: string) => void;\r\n onItemClick?: (id: string) => void;\r\n renderItem?: (item: ListItemData, state: ListRenderState) => ReactNode;\r\n getMenuItems?: (item: ListItemData) => ListMenuItem[];\r\n};\r\n\r\nexport function StandardLayout({\r\n items,\r\n droppableId,\r\n density,\r\n enableDnD,\r\n selectable,\r\n selectedIds,\r\n openId,\r\n onToggleSelect,\r\n onItemClick,\r\n renderItem,\r\n getMenuItems,\r\n}: StandardLayoutProps) {\r\n const s = listStyles({ density });\r\n\r\n const rows = items.map((item, index) => (\r\n <SortableListItem\r\n key={item.id}\r\n item={item}\r\n index={index}\r\n density={density}\r\n enableDnD={enableDnD}\r\n open={openId === item.id}\r\n selectable={selectable}\r\n selected={selectedIds.has(item.id)}\r\n onToggleSelect={onToggleSelect}\r\n onClick={onItemClick}\r\n renderItem={renderItem}\r\n getMenuItems={getMenuItems}\r\n />\r\n ));\r\n\r\n if (!enableDnD) {\r\n return <div className={s.root({ density })}>{rows}</div>;\r\n }\r\n\r\n return (\r\n <Droppable droppableId={droppableId}>\r\n {(provided, snapshot) => (\r\n <div\r\n ref={provided.innerRef}\r\n {...provided.droppableProps}\r\n className={cn(s.root({ density }), snapshot.isDraggingOver && s.dropZoneActive())}\r\n >\r\n {rows}\r\n {provided.placeholder}\r\n </div>\r\n )}\r\n </Droppable>\r\n );\r\n}\r\n","import type { ReactNode } from \"react\";\r\nimport { Droppable } from \"@hello-pangea/dnd\";\r\nimport { ChevronDown } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { listStyles, type ListStyleVariants } from \"../list.styles\";\r\nimport { SortableListItem } from \"./_sortable-item\";\r\nimport type { GroupedBucket } from \"../utils/group-items\";\r\nimport type {\r\n ListItemData,\r\n ListMenuItem,\r\n ListRenderState,\r\n} from \"../list.types\";\r\n\r\ntype GroupedLayoutProps = {\r\n buckets: GroupedBucket[];\r\n density: NonNullable<ListStyleVariants[\"density\"]>;\r\n enableDnD: boolean;\r\n /** Painel sutil por grupo (\"card fino\" que diferencia da superfície). */\r\n groupSurface?: boolean;\r\n /** Set de grupos ABERTOS (expandido). */\r\n openGroups: Set<string>;\r\n onToggleGroup: (groupId: string) => void;\r\n selectable?: boolean;\r\n selectedIds: Set<string>;\r\n openId?: string;\r\n onToggleSelect?: (id: string) => void;\r\n onItemClick?: (id: string) => void;\r\n renderItem?: (item: ListItemData, state: ListRenderState) => ReactNode;\r\n getMenuItems?: (item: ListItemData) => ListMenuItem[];\r\n};\r\n\r\nexport function GroupedLayout(props: GroupedLayoutProps) {\r\n const { buckets, density } = props;\r\n const s = listStyles({ density });\r\n return (\r\n <div className=\"flex flex-col gap-gp-2xl\">\r\n {buckets.map((bucket) => (\r\n <GroupSection key={bucket.group.id} bucket={bucket} styles={s} {...props} />\r\n ))}\r\n </div>\r\n );\r\n}\r\n\r\nfunction GroupSection({\r\n bucket,\r\n styles: s,\r\n density,\r\n enableDnD,\r\n groupSurface,\r\n openGroups,\r\n onToggleGroup,\r\n selectable,\r\n selectedIds,\r\n openId,\r\n onToggleSelect,\r\n onItemClick,\r\n renderItem,\r\n getMenuItems,\r\n}: GroupedLayoutProps & {\r\n bucket: GroupedBucket;\r\n styles: ReturnType<typeof listStyles>;\r\n}) {\r\n const { group, items, count } = bucket;\r\n const open = openGroups.has(group.id);\r\n\r\n const rows = items.map((item, index) => (\r\n <SortableListItem\r\n key={item.id}\r\n item={item}\r\n index={index}\r\n density={density}\r\n enableDnD={enableDnD && group.canReceiveDrop !== false}\r\n open={openId === item.id}\r\n selectable={selectable}\r\n selected={selectedIds.has(item.id)}\r\n onToggleSelect={onToggleSelect}\r\n onClick={onItemClick}\r\n renderItem={renderItem}\r\n getMenuItems={getMenuItems}\r\n />\r\n ));\r\n\r\n return (\r\n <section className={cn(s.group(), groupSurface && s.groupPanel())}>\r\n <header className={s.groupHeader()}>\r\n <button\r\n type=\"button\"\r\n className={s.groupToggle()}\r\n aria-expanded={open}\r\n aria-label={open ? \"Recolher grupo\" : \"Expandir grupo\"}\r\n onClick={() => onToggleGroup(group.id)}\r\n >\r\n <ChevronDown\r\n className={cn(\"size-[16px] transition-transform\", !open && \"-rotate-90\")}\r\n />\r\n </button>\r\n {group.color && (\r\n <span className={s.groupDot()} style={{ background: group.color }} aria-hidden />\r\n )}\r\n <span className={s.groupTitle()}>{group.label}</span>\r\n <span className={s.groupCount()}>{count}</span>\r\n </header>\r\n\r\n {open &&\r\n (enableDnD ? (\r\n <Droppable droppableId={group.id}>\r\n {(provided, snapshot) => (\r\n <div\r\n ref={provided.innerRef}\r\n {...provided.droppableProps}\r\n className={cn(\r\n s.groupBody({ density }),\r\n \"min-h-[44px]\",\r\n snapshot.isDraggingOver && s.dropZoneActive(),\r\n )}\r\n >\r\n {rows}\r\n {provided.placeholder}\r\n </div>\r\n )}\r\n </Droppable>\r\n ) : (\r\n <div className={s.groupBody({ density })}>{rows}</div>\r\n ))}\r\n </section>\r\n );\r\n}\r\n","import type { ListItemData } from \"../list.types\";\r\n\r\nexport type FlatRow = {\r\n item: ListItemData;\r\n depth: number;\r\n hasChildren: boolean;\r\n expanded: boolean;\r\n /** É o último filho do seu pai (define o \"∟\" do conector). */\r\n isLast: boolean;\r\n /**\r\n * Pra cada nível ancestral (índice = depth do ancestral), indica se aquele\r\n * ancestral ainda tem irmão depois dele — controla se a guia vertical\r\n * continua descendo naquela coluna de indent.\r\n */\r\n ancestorHasNext: boolean[];\r\n};\r\n\r\n/**\r\n * Achata uma árvore (`children`) em linhas, descendo só nos nós expandidos.\r\n * Produz `depth` + flags de conector pra UI de tree-as-list.\r\n */\r\nexport function flattenTree(\r\n roots: ListItemData[],\r\n expanded: Set<string>,\r\n): FlatRow[] {\r\n const rows: FlatRow[] = [];\r\n\r\n const walk = (\r\n nodes: ListItemData[],\r\n depth: number,\r\n ancestorHasNext: boolean[],\r\n ) => {\r\n nodes.forEach((item, idx) => {\r\n const hasChildren = Boolean(item.children && item.children.length > 0);\r\n const isExpanded = hasChildren && expanded.has(item.id);\r\n const isLast = idx === nodes.length - 1;\r\n rows.push({\r\n item,\r\n depth,\r\n hasChildren,\r\n expanded: isExpanded,\r\n isLast,\r\n ancestorHasNext,\r\n });\r\n if (isExpanded) {\r\n walk(item.children!, depth + 1, [...ancestorHasNext, !isLast]);\r\n }\r\n });\r\n };\r\n\r\n walk(roots, 0, []);\r\n return rows;\r\n}\r\n\r\n/** IDs de todos os nós com filhos (pra expandir/colapsar tudo). */\r\nexport function collectExpandableIds(roots: ListItemData[]): string[] {\r\n const ids: string[] = [];\r\n const walk = (nodes: ListItemData[]) => {\r\n for (const n of nodes) {\r\n if (n.children && n.children.length > 0) {\r\n ids.push(n.id);\r\n walk(n.children);\r\n }\r\n }\r\n };\r\n walk(roots);\r\n return ids;\r\n}\r\n","import { useMemo, useState, type ReactNode } from \"react\";\r\nimport { ChevronRight } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { listStyles, type ListStyleVariants } from \"../list.styles\";\r\nimport { ListItem } from \"../list-item\";\r\nimport { flattenTree, type FlatRow } from \"../utils/flatten-tree\";\r\nimport type {\r\n ListItemData,\r\n ListMenuItem,\r\n ListRenderState,\r\n} from \"../list.types\";\r\n\r\ntype BranchHighlight = \"none\" | \"block\" | \"active\";\r\n\r\ntype HierarchicalLayoutProps = {\r\n items: ListItemData[];\r\n density: NonNullable<ListStyleVariants[\"density\"]>;\r\n expanded: Set<string>;\r\n onToggleExpand: (id: string) => void;\r\n showConnectors: boolean;\r\n indentSize: number;\r\n branchHighlight?: BranchHighlight;\r\n selectable?: boolean;\r\n selectedIds: Set<string>;\r\n openId?: string;\r\n onToggleSelect?: (id: string) => void;\r\n onItemClick?: (id: string) => void;\r\n renderItem?: (item: ListItemData, state: ListRenderState) => ReactNode;\r\n getMenuItems?: (item: ListItemData) => ListMenuItem[];\r\n};\r\n\r\n/**\r\n * Layout hierárquico (tree-as-list). Dois modos de visualização:\r\n * - `branchHighlight=\"none\"` (default) → conectores (elbow lines) em linhas planas.\r\n * - `branchHighlight=\"block\"|\"active\"` → painéis aninhados que destacam a \"família\".\r\n */\r\nexport function HierarchicalLayout(props: HierarchicalLayoutProps) {\r\n if (props.branchHighlight && props.branchHighlight !== \"none\") {\r\n return (\r\n <NestedHierarchy {...props} branchHighlight={props.branchHighlight} />\r\n );\r\n }\r\n return <FlatHierarchy {...props} />;\r\n}\r\n\r\n/* ═══════════════════════════════════════════════════════════════════\r\n \"none\" — conectores clássicos (flat rows + elbow lines)\r\n ═══════════════════════════════════════════════════════════════════ */\r\n\r\nfunction FlatHierarchy({\r\n items,\r\n density,\r\n expanded,\r\n onToggleExpand,\r\n showConnectors,\r\n indentSize,\r\n selectable,\r\n selectedIds,\r\n openId,\r\n onToggleSelect,\r\n onItemClick,\r\n renderItem,\r\n getMenuItems,\r\n}: HierarchicalLayoutProps) {\r\n const s = listStyles({ density });\r\n const rows = flattenTree(items, expanded);\r\n // gap entre cards (+4px vs densidade base) — o bridge dos conectores usa o\r\n // MESMO valor pra estender cada guia vertical e manter as linhas contínuas.\r\n const gap = density === \"compact\" ? 10 : 12;\r\n\r\n return (\r\n <div className=\"flex flex-col\" style={{ gap }}>\r\n {rows.map((row) => (\r\n <div key={row.item.id} className=\"flex items-stretch\">\r\n {showConnectors && row.depth > 0 && (\r\n <Connector row={row} indentSize={indentSize} gap={gap} styles={s} />\r\n )}\r\n {!showConnectors && row.depth > 0 && (\r\n <span\r\n style={{ width: row.depth * indentSize }}\r\n className=\"shrink-0\"\r\n aria-hidden\r\n />\r\n )}\r\n <ListItem\r\n item={row.item}\r\n state={{\r\n selected: selectedIds.has(row.item.id),\r\n open: openId === row.item.id,\r\n dragging: false,\r\n depth: row.depth,\r\n }}\r\n density={density}\r\n renderItem={renderItem}\r\n getMenuItems={getMenuItems}\r\n onClick={onItemClick}\r\n selectable={selectable}\r\n onToggleSelect={onToggleSelect}\r\n expandToggle={\r\n row.hasChildren ? (\r\n <ExpandToggle\r\n open={row.expanded}\r\n styles={s}\r\n onClick={() => onToggleExpand(row.item.id)}\r\n />\r\n ) : undefined\r\n }\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n );\r\n}\r\n\r\n/**\r\n * Gutter de conectores à esquerda do card. Uma coluna por nível de indent:\r\n * - colunas dos ancestrais → linha vertical full-height quando o ancestral\r\n * ainda tem irmão depois (a guia \"continua descendo\").\r\n * - última coluna → elbow (∟): vertical até o centro + horizontal até o card;\r\n * continua abaixo do centro só se o nó tiver irmão (não é o último).\r\n */\r\nfunction Connector({\r\n row,\r\n indentSize,\r\n gap,\r\n styles: s,\r\n}: {\r\n row: FlatRow;\r\n indentSize: number;\r\n gap: number;\r\n styles: ReturnType<typeof listStyles>;\r\n}) {\r\n const cols = Array.from({ length: row.depth });\r\n const vLine = {\r\n left: \"50%\",\r\n width: 1,\r\n transform: \"translateX(-50%)\",\r\n } as const;\r\n return (\r\n <div className=\"flex shrink-0\" aria-hidden>\r\n {cols.map((_, i) => {\r\n const isElbow = i === row.depth - 1;\r\n if (isElbow) {\r\n return (\r\n <span key={i} style={{ width: indentSize }} className={s.indent()}>\r\n {/* vertical: (gap acima) → centro do card */}\r\n <span\r\n className={s.connector()}\r\n style={{ ...vLine, top: -gap, height: `calc(50% + ${gap}px)` }}\r\n />\r\n {/* vertical: centro → base (só se tem irmão depois) */}\r\n {!row.isLast && (\r\n <span\r\n className={s.connector()}\r\n style={{ ...vLine, top: \"50%\", bottom: 0 }}\r\n />\r\n )}\r\n {/* horizontal: centro → card */}\r\n <span\r\n className={s.connector()}\r\n style={{\r\n left: \"50%\",\r\n right: 0,\r\n top: \"50%\",\r\n height: 1,\r\n transform: \"translateY(-50%)\",\r\n }}\r\n />\r\n </span>\r\n );\r\n }\r\n // pass-through dos ancestrais — estende pra cima pelo gap (linha contínua).\r\n // Coluna i (x = i*indent) hospeda o elbow de nós em depth i+1, então a\r\n // continuação vertical depende do ancestral em depth i+1 ter irmão —\r\n // ancestorHasNext[i+1], NÃO [i]. Com [i] (off-by-one) a guia sumia no\r\n // último root (ancestorHasNext[0]=false); nos demais o root tinha next\r\n // e mascarava o bug.\r\n const continues = row.ancestorHasNext[i + 1];\r\n return (\r\n <span key={i} style={{ width: indentSize }} className={s.indent()}>\r\n {continues && (\r\n <span\r\n className={s.connector()}\r\n style={{ ...vLine, top: -gap, bottom: 0 }}\r\n />\r\n )}\r\n </span>\r\n );\r\n })}\r\n </div>\r\n );\r\n}\r\n\r\n/* ═══════════════════════════════════════════════════════════════════\r\n \"block\" / \"active\" — painéis aninhados (destaque de família)\r\n ═══════════════════════════════════════════════════════════════════ */\r\n\r\nfunction NestedHierarchy({\r\n items,\r\n density,\r\n expanded,\r\n onToggleExpand,\r\n branchHighlight,\r\n selectable,\r\n selectedIds,\r\n openId,\r\n onToggleSelect,\r\n onItemClick,\r\n renderItem,\r\n getMenuItems,\r\n}: HierarchicalLayoutProps & { branchHighlight: BranchHighlight }) {\r\n // nó \"ativo\" = último expandido (modo \"active\"). Seed = ramo aberto mais profundo.\r\n const [activeId, setActiveId] = useState<string | null>(() =>\r\n branchHighlight === \"active\" ? deepestExpanded(items, expanded) : null,\r\n );\r\n\r\n const { trail, subtree } = useMemo(() => {\r\n if (branchHighlight !== \"active\" || !activeId) {\r\n return { trail: new Set<string>(), subtree: new Set<string>() };\r\n }\r\n const path = findPath(items, activeId) ?? [];\r\n const node = findNode(items, activeId);\r\n return {\r\n trail: new Set(path.slice(0, -1)), // ancestrais (sem o próprio ativo)\r\n subtree: new Set(node ? collectSubtree(node) : []),\r\n };\r\n }, [items, activeId, branchHighlight]);\r\n\r\n const handleToggle = (id: string) => {\r\n if (!expanded.has(id)) setActiveId(id); // ao EXPANDIR, vira o ativo\r\n onToggleExpand(id);\r\n };\r\n\r\n return (\r\n <NestedTree\r\n nodes={items}\r\n density={density}\r\n depth={0}\r\n expanded={expanded}\r\n onToggle={handleToggle}\r\n branchHighlight={branchHighlight}\r\n trail={trail}\r\n subtree={subtree}\r\n activeId={activeId}\r\n selectable={selectable}\r\n selectedIds={selectedIds}\r\n openId={openId}\r\n onToggleSelect={onToggleSelect}\r\n onItemClick={onItemClick}\r\n renderItem={renderItem}\r\n getMenuItems={getMenuItems}\r\n />\r\n );\r\n}\r\n\r\ntype NestedTreeProps = {\r\n nodes: ListItemData[];\r\n density: NonNullable<ListStyleVariants[\"density\"]>;\r\n depth: number;\r\n expanded: Set<string>;\r\n onToggle: (id: string) => void;\r\n branchHighlight: BranchHighlight;\r\n trail: Set<string>;\r\n subtree: Set<string>;\r\n activeId: string | null;\r\n selectable?: boolean;\r\n selectedIds: Set<string>;\r\n openId?: string;\r\n onToggleSelect?: (id: string) => void;\r\n onItemClick?: (id: string) => void;\r\n renderItem?: (item: ListItemData, state: ListRenderState) => ReactNode;\r\n getMenuItems?: (item: ListItemData) => ListMenuItem[];\r\n};\r\n\r\nfunction NestedTree({\r\n nodes,\r\n density,\r\n depth,\r\n expanded,\r\n onToggle,\r\n branchHighlight,\r\n trail,\r\n subtree,\r\n activeId,\r\n selectable,\r\n selectedIds,\r\n openId,\r\n onToggleSelect,\r\n onItemClick,\r\n renderItem,\r\n getMenuItems,\r\n}: NestedTreeProps) {\r\n const s = listStyles({ density });\r\n return (\r\n <div className=\"flex flex-col gap-gp-md\">\r\n {nodes.map((node) => {\r\n const hasChildren = Boolean(node.children?.length);\r\n const isOpen = hasChildren && expanded.has(node.id);\r\n return (\r\n <div key={node.id} className=\"flex flex-col gap-gp-md\">\r\n <ListItem\r\n item={node}\r\n state={{\r\n selected: selectedIds.has(node.id),\r\n open:\r\n openId === node.id ||\r\n (branchHighlight === \"active\" && node.id === activeId),\r\n dragging: false,\r\n depth,\r\n }}\r\n density={density}\r\n renderItem={renderItem}\r\n getMenuItems={getMenuItems}\r\n onClick={onItemClick}\r\n selectable={selectable}\r\n onToggleSelect={onToggleSelect}\r\n expandToggle={\r\n hasChildren ? (\r\n <ExpandToggle\r\n open={isOpen}\r\n styles={s}\r\n onClick={() => onToggle(node.id)}\r\n />\r\n ) : undefined\r\n }\r\n />\r\n {isOpen && (\r\n <div\r\n className={cn(\r\n \"pl-pad-xl\",\r\n branchContainer(branchHighlight, node.id, trail, subtree),\r\n )}\r\n >\r\n <NestedTree\r\n nodes={node.children!}\r\n density={density}\r\n depth={depth + 1}\r\n expanded={expanded}\r\n onToggle={onToggle}\r\n branchHighlight={branchHighlight}\r\n trail={trail}\r\n subtree={subtree}\r\n activeId={activeId}\r\n selectable={selectable}\r\n selectedIds={selectedIds}\r\n openId={openId}\r\n onToggleSelect={onToggleSelect}\r\n onItemClick={onItemClick}\r\n renderItem={renderItem}\r\n getMenuItems={getMenuItems}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n );\r\n}\r\n\r\n/** Painel sutil de \"família\" — mesmo visual no block e no subtree do active. */\r\nconst PANEL =\r\n \"ml-[12px] rounded-radius-lg border border-border-subtle border-l-2 border-l-border-brand-subtle bg-bg-muted/40 dark:bg-bg-surface/40 py-pad-md pr-pad-xs\";\r\nconst TRAIL = \"ml-[12px] border-l-2 border-l-border-brand-subtle py-pad-2xs\";\r\nconst GUIDE = \"ml-[12px] border-l border-border-subtle py-pad-2xs\";\r\n\r\n/** Classe do container de filhos por tratamento. `parentId` = nó dono dos filhos. */\r\nfunction branchContainer(\r\n mode: BranchHighlight,\r\n parentId: string,\r\n trail: Set<string>,\r\n subtree: Set<string>,\r\n): string {\r\n if (mode === \"block\") return PANEL;\r\n if (mode === \"active\") {\r\n if (subtree.has(parentId)) return PANEL; // subtree do ativo = mesmo painel\r\n if (trail.has(parentId)) return TRAIL; // ancestral → só a trilha (spine)\r\n return GUIDE; // fora do ramo ativo → guia neutra\r\n }\r\n return GUIDE;\r\n}\r\n\r\n/* ── shared ────────────────────────────────────────────────────── */\r\n\r\nfunction ExpandToggle({\r\n open,\r\n styles: s,\r\n onClick,\r\n}: {\r\n open: boolean;\r\n styles: ReturnType<typeof listStyles>;\r\n onClick: () => void;\r\n}) {\r\n return (\r\n <button\r\n type=\"button\"\r\n className={s.groupToggle()}\r\n aria-expanded={open}\r\n aria-label={open ? \"Recolher\" : \"Expandir\"}\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onClick();\r\n }}\r\n >\r\n <ChevronRight\r\n className={cn(\"size-[16px] transition-transform\", open && \"rotate-90\")}\r\n />\r\n </button>\r\n );\r\n}\r\n\r\nfunction findNode(nodes: ListItemData[], id: string): ListItemData | null {\r\n for (const n of nodes) {\r\n if (n.id === id) return n;\r\n if (n.children) {\r\n const r = findNode(n.children, id);\r\n if (r) return r;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction findPath(\r\n nodes: ListItemData[],\r\n id: string,\r\n acc: string[] = [],\r\n): string[] | null {\r\n for (const n of nodes) {\r\n const next = [...acc, n.id];\r\n if (n.id === id) return next;\r\n if (n.children) {\r\n const r = findPath(n.children, id, next);\r\n if (r) return r;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction collectSubtree(node: ListItemData): string[] {\r\n const ids = [node.id];\r\n node.children?.forEach((c) => ids.push(...collectSubtree(c)));\r\n return ids;\r\n}\r\n\r\n/** Nó aberto mais profundo seguindo a cadeia de expandidos (seed do \"active\"). */\r\nfunction deepestExpanded(\r\n nodes: ListItemData[],\r\n expanded: Set<string>,\r\n): string | null {\r\n for (const n of nodes) {\r\n if (expanded.has(n.id) && n.children?.length) {\r\n const deeper = deepestExpanded(n.children, expanded);\r\n return deeper ?? n.id;\r\n }\r\n }\r\n return null;\r\n}\r\n","import { useCallback, useState } from \"react\";\r\n\r\ntype Options = {\r\n controlled?: Set<string>;\r\n defaultValue?: Set<string>;\r\n onChange?: (ids: Set<string>) => void;\r\n};\r\n\r\n/**\r\n * Set de IDs selecionados com idioma controlado/não-controlado.\r\n * - `controlled` presente → o consumer dona o estado (List vira burro).\r\n * - senão → estado interno semeado por `defaultValue`.\r\n * `onChange` sempre dispara (mesmo no modo controlado).\r\n */\r\nexport function useSelectionSet({ controlled, defaultValue, onChange }: Options) {\r\n const [internal, setInternal] = useState<Set<string>>(\r\n () => defaultValue ?? new Set(),\r\n );\r\n const isControlled = controlled !== undefined;\r\n const value = isControlled ? controlled : internal;\r\n\r\n const commit = useCallback(\r\n (next: Set<string>) => {\r\n if (!isControlled) setInternal(next);\r\n onChange?.(next);\r\n },\r\n [isControlled, onChange],\r\n );\r\n\r\n const toggle = useCallback(\r\n (id: string) => {\r\n const next = new Set(value);\r\n if (next.has(id)) next.delete(id);\r\n else next.add(id);\r\n commit(next);\r\n },\r\n [value, commit],\r\n );\r\n\r\n return { selected: value, toggle, setSelected: commit };\r\n}\r\n","import { useCallback, useState } from \"react\";\r\n\r\ntype Options = {\r\n controlled?: Set<string>;\r\n defaultValue?: Set<string>;\r\n onChange?: (ids: Set<string>) => void;\r\n};\r\n\r\n/**\r\n * Set de IDs expandidos (colapso de grupos/hierarquia) com idioma\r\n * controlado/não-controlado. Mesma mecânica do useSelectionSet, mantido\r\n * separado por coesão semântica (expansão ≠ seleção).\r\n */\r\nexport function useDisclosureSet({ controlled, defaultValue, onChange }: Options) {\r\n const [internal, setInternal] = useState<Set<string>>(\r\n () => defaultValue ?? new Set(),\r\n );\r\n const isControlled = controlled !== undefined;\r\n const value = isControlled ? controlled : internal;\r\n\r\n const commit = useCallback(\r\n (next: Set<string>) => {\r\n if (!isControlled) setInternal(next);\r\n onChange?.(next);\r\n },\r\n [isControlled, onChange],\r\n );\r\n\r\n const toggle = useCallback(\r\n (id: string) => {\r\n const next = new Set(value);\r\n if (next.has(id)) next.delete(id);\r\n else next.add(id);\r\n commit(next);\r\n },\r\n [value, commit],\r\n );\r\n\r\n return { expanded: value, toggle, setExpanded: commit };\r\n}\r\n","import type { ListGroup, ListItemData } from \"../list.types\";\r\n\r\nexport type GroupedBucket = {\r\n group: ListGroup;\r\n items: ListItemData[];\r\n count: number;\r\n};\r\n\r\n/**\r\n * Particiona itens planos por `groupId`, na ordem definida em `groups`.\r\n * Grupos sem itens são preservados (renderizam vazio / drop target).\r\n * Itens cujo `groupId` não bate com nenhum grupo são ignorados.\r\n */\r\nexport function groupItems(\r\n items: ListItemData[],\r\n groups: ListGroup[],\r\n): GroupedBucket[] {\r\n const byGroup = new Map<string, ListItemData[]>();\r\n for (const g of groups) byGroup.set(g.id, []);\r\n for (const item of items) {\r\n if (item.groupId && byGroup.has(item.groupId)) {\r\n byGroup.get(item.groupId)!.push(item);\r\n }\r\n }\r\n return groups.map((group) => {\r\n const bucket = byGroup.get(group.id) ?? [];\r\n return { group, items: bucket, count: group.count ?? bucket.length };\r\n });\r\n}\r\n","import { useCallback, useMemo } from \"react\";\r\nimport { DragDropContext, type DropResult } from \"@hello-pangea/dnd\";\r\nimport { Inbox } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { listStyles } from \"./list.styles\";\r\nimport { StandardLayout } from \"./layouts/standard-layout\";\r\nimport { GroupedLayout } from \"./layouts/grouped-layout\";\r\nimport { HierarchicalLayout } from \"./layouts/hierarchical-layout\";\r\nimport { useSelectionSet } from \"./hooks/use-selection-set\";\r\nimport { useDisclosureSet } from \"./hooks/use-disclosure-set\";\r\nimport { groupItems } from \"./utils/group-items\";\r\nimport type { ListProps } from \"./list.types\";\r\n\r\nconst STANDARD_DROPPABLE_ID = \"list-standard\";\r\n\r\n/**\r\n * <List> — primitivo de listagem em cards (como `Table` é o primitivo de tabela).\r\n * Burro: recebe dados + estado de UI (controlado/não-controlado) e emite callbacks.\r\n * Sem busca/filtro/sort/server/toolbar — isso é o `DataList` (passo 2).\r\n *\r\n * Layouts: `standard` (lista plana) · `grouped` (seções + DnD) · `hierarchical`\r\n * (árvore-como-lista colapsável com conectores). Card via slots ou `renderItem`.\r\n *\r\n * DnD via @hello-pangea/dnd (física natural de lista: displacement suave dos\r\n * irmãos + placeholder que abre espaço). Burro: emite `onMove`/`onReorder`,\r\n * o consumer commita o estado.\r\n */\r\nexport function List({\r\n layout = \"standard\",\r\n items,\r\n groups,\r\n renderItem,\r\n getMenuItems,\r\n onItemClick,\r\n openId,\r\n selectable,\r\n selectedIds,\r\n defaultSelectedIds,\r\n onSelectionChange,\r\n expandedIds,\r\n defaultExpandedIds,\r\n onExpandedChange,\r\n showConnectors = true,\r\n indentSize = 24,\r\n branchHighlight = \"none\",\r\n enableDnD = false,\r\n groupSurface,\r\n onReorder,\r\n onMove,\r\n loading,\r\n skeletonCount = 4,\r\n emptyState,\r\n density = \"comfortable\",\r\n className,\r\n}: ListProps) {\r\n const s = listStyles({ density });\r\n\r\n const { selected, toggle: toggleSelect } = useSelectionSet({\r\n controlled: selectedIds,\r\n defaultValue: defaultSelectedIds,\r\n onChange: onSelectionChange,\r\n });\r\n\r\n // Grupos abrem por padrão; hierarquia colapsa por padrão (seed via defaults).\r\n const groupedDefaultOpen = useMemo(\r\n () =>\r\n layout === \"grouped\" && groups\r\n ? new Set(groups.map((g) => g.id))\r\n : undefined,\r\n [layout, groups],\r\n );\r\n const { expanded, toggle: toggleExpand } = useDisclosureSet({\r\n controlled: expandedIds,\r\n defaultValue: defaultExpandedIds ?? groupedDefaultOpen,\r\n onChange: onExpandedChange,\r\n });\r\n\r\n const dndEnabled = enableDnD && layout !== \"hierarchical\";\r\n\r\n const handleDragEnd = useCallback(\r\n (result: DropResult) => {\r\n const { source, destination, draggableId } = result;\r\n if (!destination) return;\r\n if (\r\n source.droppableId === destination.droppableId &&\r\n source.index === destination.index\r\n ) {\r\n return;\r\n }\r\n if (layout === \"grouped\") {\r\n onMove?.(\r\n draggableId,\r\n source.droppableId,\r\n destination.droppableId,\r\n destination.index,\r\n );\r\n } else {\r\n onReorder?.(draggableId, destination.index);\r\n }\r\n },\r\n [layout, onMove, onReorder],\r\n );\r\n\r\n /* ── estados ───────────────────────────────────────────────── */\r\n if (loading) {\r\n return (\r\n <div className={cn(s.root({ density }), className)}>\r\n {Array.from({ length: skeletonCount }).map((_, i) => (\r\n <div key={i} className={s.skeleton()}>\r\n <div className={cn(s.skeletonBar(), \"w-1/3 mb-gp-md\")} />\r\n <div className={cn(s.skeletonBar(), \"w-2/3\")} />\r\n </div>\r\n ))}\r\n </div>\r\n );\r\n }\r\n\r\n if (!items.length) {\r\n return (\r\n <div className={cn(s.root({ density }), className)}>\r\n {emptyState ?? (\r\n <div className={s.emptyState()}>\r\n <Inbox className=\"size-icon-md opacity-70\" aria-hidden />\r\n <span>Nada por aqui ainda.</span>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n }\r\n\r\n /* ── layout ────────────────────────────────────────────────── */\r\n const layoutEl =\r\n layout === \"grouped\" ? (\r\n <GroupedLayout\r\n buckets={groupItems(items, groups ?? [])}\r\n density={density}\r\n enableDnD={dndEnabled}\r\n groupSurface={groupSurface}\r\n openGroups={expanded}\r\n onToggleGroup={toggleExpand}\r\n selectable={selectable}\r\n selectedIds={selected}\r\n openId={openId}\r\n onToggleSelect={toggleSelect}\r\n onItemClick={onItemClick}\r\n renderItem={renderItem}\r\n getMenuItems={getMenuItems}\r\n />\r\n ) : layout === \"hierarchical\" ? (\r\n <HierarchicalLayout\r\n items={items}\r\n density={density}\r\n expanded={expanded}\r\n onToggleExpand={toggleExpand}\r\n showConnectors={showConnectors}\r\n indentSize={indentSize}\r\n branchHighlight={branchHighlight}\r\n selectable={selectable}\r\n selectedIds={selected}\r\n openId={openId}\r\n onToggleSelect={toggleSelect}\r\n onItemClick={onItemClick}\r\n renderItem={renderItem}\r\n getMenuItems={getMenuItems}\r\n />\r\n ) : (\r\n <StandardLayout\r\n items={items}\r\n droppableId={STANDARD_DROPPABLE_ID}\r\n density={density}\r\n enableDnD={dndEnabled}\r\n selectable={selectable}\r\n selectedIds={selected}\r\n openId={openId}\r\n onToggleSelect={toggleSelect}\r\n onItemClick={onItemClick}\r\n renderItem={renderItem}\r\n getMenuItems={getMenuItems}\r\n />\r\n );\r\n\r\n if (!dndEnabled) {\r\n return <div className={cn(\"w-full\", className)}>{layoutEl}</div>;\r\n }\r\n\r\n return (\r\n <div className={cn(\"w-full\", className)}>\r\n <DragDropContext onDragEnd={handleDragEnd}>{layoutEl}</DragDropContext>\r\n </div>\r\n );\r\n}\r\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * DataTable wrapper externo — agrupa toolbar + table + footer.\r\n * Visual: card com border + radius. O <Table> interno tem o próprio wrapper\r\n * com bg-bg-table; aqui o <div> raiz só posiciona toolbar e footer.\r\n */\r\nexport const dataTableStyles = tv({\r\n slots: {\r\n root: [\r\n // 16px (gp-2xl) entre toolbar e tabela\r\n \"flex flex-col w-full gap-gp-2xl\",\r\n ],\r\n toolbarWrap: [\r\n // Sem gap: chips ficam justapostos a toolbar header (sem separator)\r\n \"flex flex-col\",\r\n ],\r\n footerWrap: [\r\n \"flex-shrink-0\",\r\n ],\r\n overlay: [\r\n \"absolute inset-0 z-50 flex items-center justify-center\",\r\n \"bg-bg-canvas/80 backdrop-blur-sm\",\r\n ],\r\n emptyWrap: [\r\n \"flex flex-col items-center justify-center gap-gp-md\",\r\n \"min-h-[240px] p-pad-3xl\",\r\n \"text-fg-muted\",\r\n ],\r\n emptyTitle: [\r\n \"text-title-md text-fg-default\",\r\n ],\r\n emptyDescription: [\r\n \"text-body-md text-fg-muted text-center max-w-[360px]\",\r\n ],\r\n bulkBar: [\r\n \"fixed bottom-pad-3xl left-1/2 -translate-x-1/2 z-[var(--z-index-toast,600)]\",\r\n \"flex items-center gap-gp-lg\",\r\n \"py-pad-md px-pad-2xl rounded-radius-xl\",\r\n \"bg-bg-brand-subtle border border-border-brand text-fg-brand\",\r\n \"shadow-sh-lg\",\r\n ],\r\n },\r\n variants: {\r\n /**\r\n * Tela cheia — container raiz vira overlay fixo ocupando a viewport, com\r\n * bg do canvas + padding pra respiro. A tabela interna preenche o resto\r\n * (min-h-0 já no `<Table className>`).\r\n */\r\n fullscreen: {\r\n true: {\r\n root: [\r\n \"fixed inset-0 z-[var(--z-index-modal,500)]\",\r\n \"bg-bg-canvas p-pad-2xl overflow-auto\",\r\n ],\r\n },\r\n },\r\n },\r\n defaultVariants: {\r\n fullscreen: false,\r\n },\r\n});\r\n","import type { TableDensity } from \"../Table\";\r\n\r\n/**\r\n * Constantes default do DataTable — centralizadas pra evitar magic numbers\r\n * repetidos e drift silencioso entre arquivos.\r\n */\r\n\r\n/** Breakpoint (px) abaixo do qual a tabela entra em card mode (quando habilitado). */\r\nexport const DEFAULT_CARD_BREAKPOINT = 768;\r\n\r\n/** Linhas extra renderizadas acima/abaixo do viewport na virtualização. */\r\nexport const DEFAULT_OVERSCAN = 10;\r\n\r\n/** Largura default da coluna `actions` (icon-only kebab + respiro). */\r\nexport const ACTIONS_COLUMN_WIDTH = 120;\r\n\r\n/** Tempo mínimo (ms) que o spinner de refresh fica visível (feedback de UX). */\r\nexport const MIN_REFRESH_SPINNER_MS = 400;\r\n\r\n/**\r\n * Altura estimada da row por densidade (px) — usada pela virtualização\r\n * (`estimateSize`). ⚠️ DEVE casar com as classes de altura em\r\n * `Table/table.styles.ts` (`tableRow` density variants). Se mudar uma altura\r\n * lá, atualizar aqui (e vice-versa) — senão o scroll virtual desalinha.\r\n */\r\nexport const DENSITY_ROW_HEIGHT: Record<TableDensity, number> = {\r\n compact: 40,\r\n standard: 56,\r\n comfortable: 64,\r\n};\r\n","import { createContext, useContext } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type {\n TableDensity,\n ColumnPinned,\n} from \"../../Table\";\nimport type {\n DataTableColumnDef,\n PaginationModel,\n GridSelectionState,\n GridRowId,\n FilterModel,\n SortModel,\n} from \"../data-table.types\";\n\n/* ── Tipo do value do Context — readonly snapshot do estado ─────── */\n\nexport type DataTableContextValue<T = any> = {\n /** Dados originais sem processar (filter/sort/paginate ficam no processor). */\n rows: T[];\n /** Colunas efetivas (já filtradas por visibility e ordenadas por columnOrder). */\n effectiveColumns: DataTableColumnDef<T>[];\n /** Widths em px por field. */\n columnWidths: Record<string, number>;\n /** Sticky offsets por field. */\n stickyOffsets: Record<string, number>;\n /** Order atual dos fields (filtrada por visibilidade). */\n columnOrder: string[];\n /** Set de fields hidden. */\n hiddenColumns: Set<string>;\n /** Map de pinned por field. */\n pinnedColumns: Record<string, ColumnPinned>;\n\n /** Multi-sort: array de criterios (primeiro = prioridade maior). */\n sortModel: SortModel[];\n /** Pagination state. */\n paginationModel: PaginationModel;\n /** Selection state. */\n selection: {\n state: GridSelectionState;\n isRowSelected: (row: T) => boolean;\n selectedCount: number;\n };\n /** Density state. */\n density: TableDensity;\n /** Search state. */\n search: string;\n /** Filter model. */\n filterModel: FilterModel;\n\n /** getRowId utility. */\n getRowId: (row: T) => GridRowId;\n};\n\nconst DataTableContext = createContext<DataTableContextValue | null>(null);\n\nexport function DataTableProvider({\n value,\n children,\n}: {\n value: DataTableContextValue;\n children: ReactNode;\n}) {\n return (\n <DataTableContext.Provider value={value}>\n {children}\n </DataTableContext.Provider>\n );\n}\n\nexport function useDataTableContext<T = any>(): DataTableContextValue<T> {\n const ctx = useContext(DataTableContext);\n if (!ctx) {\n throw new Error(\"useDataTableContext must be used inside <DataTable>\");\n }\n return ctx as DataTableContextValue<T>;\n}\n","import { useCallback, useMemo, useState } from \"react\";\r\nimport { useColumnWidths } from \"../../Table\";\r\nimport type { ColumnPinned } from \"../../Table\";\r\nimport type { DataTableColumnDef } from \"../data-table.types\";\r\nimport { columnTypeRegistry } from \"../column-types\";\r\n\r\nexport type UseDataTableColumnsParams<T> = {\r\n columns: DataTableColumnDef<T>[];\r\n /** Estado inicial hidratado (de localStorage ou prop) — aplicado apenas no mount. */\r\n initialWidthOverrides?: Record<string, number>;\r\n initialPinnedOverrides?: Record<string, ColumnPinned>;\r\n initialHiddenColumns?: string[];\r\n initialColumnOrder?: string[];\r\n /**\r\n * Widths calculados pelo `useColumnAutoWidth` (autoFit). Precedência:\r\n * resize manual (`widthOverrides`) > autoFit (`autoWidths`) > col.width > typeDef.defaultWidth.\r\n * Quando autoFit está desligado, passe `undefined` ou `{}`.\r\n */\r\n autoWidths?: Record<string, number>;\r\n};\r\n\r\nexport type UseDataTableColumnsResult<T> = {\r\n /** Colunas após aplicar hiddenColumns e columnOrder. */\r\n effectiveColumns: DataTableColumnDef<T>[];\r\n /** Widths em px por field (efetivas — incluem autoFit). Use pra RENDER. */\r\n columnWidths: Record<string, number>;\r\n /** Resize manual do usuário (sem autoFit). Use pra PERSISTIR (não as efetivas). */\r\n widthOverrides: Record<string, number>;\r\n /** Sticky offsets por field. */\r\n stickyOffsets: Record<string, number>;\r\n /** Hidden columns state. */\r\n hiddenColumns: Set<string>;\r\n /** Pinned columns state. */\r\n pinnedColumns: Record<string, ColumnPinned>;\r\n /** Column order state. */\r\n columnOrder: string[];\r\n\r\n /** Handlers. */\r\n handleResize: (field: string, widthPx: number) => void;\r\n handlePin: (field: string, side: ColumnPinned) => void;\r\n handleHide: (field: string) => void;\r\n handleShow: (field: string) => void;\r\n handleReorder: (newOrder: string[]) => void;\r\n /** Aplica snapshot completo de columns state (usado por applyView). */\r\n applyColumnState: (state: {\r\n columnWidths?: Record<string, number>;\r\n pinnedColumns?: Record<string, ColumnPinned>;\r\n hiddenColumns?: string[];\r\n columnOrder?: string[];\r\n }) => void;\r\n};\r\n\r\n/**\r\n * Gerencia estado de colunas (widths, pin, hide, order) e calcula offsets sticky.\r\n * Tudo uncontrolled na v1 — controle via props vem em F7 (persistência).\r\n */\r\nexport function useDataTableColumns<T>({\r\n columns,\r\n initialWidthOverrides,\r\n initialPinnedOverrides,\r\n initialHiddenColumns,\r\n initialColumnOrder,\r\n autoWidths,\r\n}: UseDataTableColumnsParams<T>): UseDataTableColumnsResult<T> {\r\n // Width override por field (uncontrolled). Default vem do columnDef.\r\n const [widthOverrides, setWidthOverrides] = useState<Record<string, number>>(\r\n () => initialWidthOverrides ?? {},\r\n );\r\n // Pinned override (default vem do columnDef.pinned).\r\n const [pinnedOverrides, setPinnedOverrides] = useState<\r\n Record<string, ColumnPinned>\r\n >(() => initialPinnedOverrides ?? {});\r\n // Hidden state (uncontrolled).\r\n const [hiddenColumns, setHiddenColumns] = useState<Set<string>>(\r\n () => new Set(initialHiddenColumns ?? []),\r\n );\r\n // Order state (uncontrolled). Default: order do array de columns.\r\n // Hidrata via initialColumnOrder mas descarta entradas que nao existem mais\r\n // nas columns atuais (schema validation — campo pode ter sido removido).\r\n const [columnOrder, setColumnOrder] = useState<string[]>(() => {\r\n const fieldSet = new Set(columns.map((c) => String(c.field)));\r\n if (initialColumnOrder) {\r\n const valid = initialColumnOrder.filter((f) => fieldSet.has(f));\r\n // Anexa campos que existem agora mas nao estavam no persist (colunas novas).\r\n const missing = columns\r\n .map((c) => String(c.field))\r\n .filter((f) => !valid.includes(f));\r\n return [...valid, ...missing];\r\n }\r\n return columns.map((c) => String(c.field));\r\n });\r\n\r\n // Efetivo: filtra hidden, aplica order, mescla overrides + defaults do registry\r\n // por tipo (Fase G.2: width/sortable/align/ellipsis vêm do tipo quando não passados).\r\n //\r\n // Precedência de width (mais alta para mais baixa):\r\n // 1. widthOverrides[field] — resize manual (drag pelo user)\r\n // 2. autoWidths[field] — autoFit calculado via ResizeObserver\r\n // 3. col.width — explícito do consumer\r\n // 4. typeDef.defaultWidth — fallback do tipo registrado\r\n const effectiveColumns = useMemo<DataTableColumnDef<T>[]>(() => {\r\n const byField = new Map(columns.map((c) => [String(c.field), c]));\r\n const ordered: DataTableColumnDef<T>[] = [];\r\n for (const field of columnOrder) {\r\n const col = byField.get(field);\r\n if (!col || hiddenColumns.has(field)) continue;\r\n const typeDef = col.type ? columnTypeRegistry.get(col.type) : undefined;\r\n const isActions = col.type === \"actions\";\r\n ordered.push({\r\n ...col,\r\n width:\r\n widthOverrides[field] ??\r\n autoWidths?.[field] ??\r\n col.width ??\r\n typeDef?.defaultWidth,\r\n sortable: col.sortable ?? typeDef?.defaultSortable,\r\n // align/ellipsis vêm do tipo quando não passados — resolvidos aqui (fonte\r\n // única) pra que HEADER e FOOTER (que leem só `col.align`) fiquem coerentes\r\n // com o BODY. Sem isso, `type: \"currency/number\"` (defaultAlign \"right\")\r\n // alinhava só o body à direita; header/footer caíam à esquerda.\r\n align: col.align ?? typeDef?.defaultAlign,\r\n ellipsis: col.ellipsis ?? typeDef?.defaultEllipsis,\r\n // Pin: override > col.pinned > default. Coluna `actions` ancora à DIREITA\r\n // por padrão (mesmo sem o consumer/gerador passar `pinned`) — robustez:\r\n // independe de onde a coluna foi declarada no array.\r\n pinned:\r\n field in pinnedOverrides\r\n ? pinnedOverrides[field]\r\n : (col.pinned ?? (isActions ? \"right\" : undefined)),\r\n });\r\n }\r\n // `actions` SEMPRE por último na renderização (sort estável preserva o resto),\r\n // mesmo se declarada no meio do array de colunas pelo consumer/gerador.\r\n ordered.sort(\r\n (a, b) => Number(a.type === \"actions\") - Number(b.type === \"actions\"),\r\n );\r\n return ordered;\r\n }, [\r\n columns,\r\n columnOrder,\r\n hiddenColumns,\r\n widthOverrides,\r\n pinnedOverrides,\r\n autoWidths,\r\n ]);\r\n\r\n // Calcula offsets sticky via hook do Table primitivo\r\n const widthsInput = useMemo(\r\n () =>\r\n effectiveColumns.map((c) => ({\r\n field: String(c.field),\r\n width: c.width,\r\n defaultWidth: c.width,\r\n pinned: c.pinned,\r\n })),\r\n [effectiveColumns],\r\n );\r\n const { widths, offsets } = useColumnWidths(widthsInput);\r\n\r\n const handleResize = useCallback((field: string, widthPx: number) => {\r\n setWidthOverrides((prev) => ({ ...prev, [field]: widthPx }));\r\n }, []);\r\n\r\n const handlePin = useCallback((field: string, side: ColumnPinned) => {\r\n setPinnedOverrides((prev) => ({ ...prev, [field]: side }));\r\n }, []);\r\n\r\n const handleHide = useCallback((field: string) => {\r\n setHiddenColumns((prev) => {\r\n const next = new Set(prev);\r\n next.add(field);\r\n return next;\r\n });\r\n }, []);\r\n\r\n const handleShow = useCallback((field: string) => {\r\n setHiddenColumns((prev) => {\r\n const next = new Set(prev);\r\n next.delete(field);\r\n return next;\r\n });\r\n }, []);\r\n\r\n const handleReorder = useCallback((newOrder: string[]) => {\r\n // newOrder pode vir INCOMPLETO — o popover de colunas exclui a coluna\r\n // `actions` (e qualquer não-listada). Mesclar os campos ausentes preserva-os\r\n // (senão somem da tabela, pois effectiveColumns só itera columnOrder).\r\n setColumnOrder((prev) => {\r\n const inNew = new Set(newOrder);\r\n const missing = prev.filter((f) => !inNew.has(f));\r\n return [...newOrder, ...missing];\r\n });\r\n }, []);\r\n\r\n const applyColumnState = useCallback(\r\n (state: {\r\n columnWidths?: Record<string, number>;\r\n pinnedColumns?: Record<string, ColumnPinned>;\r\n hiddenColumns?: string[];\r\n columnOrder?: string[];\r\n }) => {\r\n if (state.columnWidths) setWidthOverrides(state.columnWidths);\r\n if (state.pinnedColumns) setPinnedOverrides(state.pinnedColumns);\r\n if (state.hiddenColumns) setHiddenColumns(new Set(state.hiddenColumns));\r\n if (state.columnOrder) {\r\n // Filtra campos que nao existem mais (schema mudou)\r\n const fieldSet = new Set(columns.map((c) => String(c.field)));\r\n const valid = state.columnOrder.filter((f) => fieldSet.has(f));\r\n const missing = columns\r\n .map((c) => String(c.field))\r\n .filter((f) => !valid.includes(f));\r\n setColumnOrder([...valid, ...missing]);\r\n }\r\n },\r\n [columns],\r\n );\r\n\r\n // pinnedColumns combinado (overrides + defaults)\r\n const pinnedColumns = useMemo<Record<string, ColumnPinned>>(() => {\r\n const result: Record<string, ColumnPinned> = {};\r\n for (const c of columns) {\r\n const field = String(c.field);\r\n result[field] =\r\n field in pinnedOverrides ? pinnedOverrides[field] : c.pinned;\r\n }\r\n return result;\r\n }, [columns, pinnedOverrides]);\r\n\r\n return {\r\n effectiveColumns,\r\n columnWidths: widths,\r\n /** Larguras de resize MANUAL do usuário (sem autoFit). Persistir SÓ isto —\r\n * persistir `columnWidths` (efetivas, c/ autoFit) congela o layout e mata o\r\n * autoFit no reload (vira widthOverrides de precedência máxima). */\r\n widthOverrides,\r\n stickyOffsets: offsets,\r\n hiddenColumns,\r\n pinnedColumns,\r\n columnOrder,\r\n handleResize,\r\n handlePin,\r\n handleHide,\r\n handleShow,\r\n handleReorder,\r\n applyColumnState,\r\n };\r\n}\r\n","/**\r\n * measure-text.ts — Canvas-based text measurement utility.\r\n *\r\n * Singleton canvas reutilizado entre todas as chamadas — evita custo de criar\r\n * canvas a cada medição. SSR-safe (retorna 0 quando `window` não existe).\r\n *\r\n * Usado por `calculateColumnWidths` (Layer 2 — Smart Content Sampling) pra\r\n * descobrir a largura ideal de uma coluna baseada no header + amostra de rows.\r\n */\r\n\r\nlet measureCanvas: HTMLCanvasElement | null = null;\r\nlet measureCtx: CanvasRenderingContext2D | null = null;\r\n\r\n/** Fonte default — alinha com `text-body-sm` do DS (13px / Geist). */\r\nconst DEFAULT_FONT =\r\n \"13px Geist, system-ui, -apple-system, BlinkMacSystemFont, sans-serif\";\r\n\r\nfunction ensureCtx(font: string = DEFAULT_FONT): CanvasRenderingContext2D | null {\r\n if (typeof document === \"undefined\") return null; // SSR safe\r\n if (!measureCanvas) {\r\n measureCanvas = document.createElement(\"canvas\");\r\n measureCtx = measureCanvas.getContext(\"2d\");\r\n }\r\n if (measureCtx) measureCtx.font = font;\r\n return measureCtx;\r\n}\r\n\r\n/**\r\n * Mede a largura em pixels de um texto na fonte default do DS.\r\n * Reutiliza um canvas singleton para evitar overhead de criação.\r\n *\r\n * @param text — texto a medir\r\n * @param font — font shorthand CSS (default: 13px Geist)\r\n * @returns largura em pixels (0 se SSR ou texto vazio)\r\n */\r\nexport function measureTextWidth(text: string, font?: string): number {\r\n if (!text) return 0;\r\n const ctx = ensureCtx(font);\r\n if (!ctx) return 0;\r\n return ctx.measureText(text).width;\r\n}\r\n","import type { DataTableActionItem } from \"../data-table.types\";\r\n\r\n/**\r\n * Regra de distribuição das ações de uma row entre ícones inline e o menu \"…\",\r\n * e a largura que a coluna `type: \"actions\"` precisa pra caber o resultado.\r\n *\r\n * ## Por que isto é um módulo próprio\r\n *\r\n * A célula (`parts/data-table-actions-cell.tsx`) decide o que renderiza; o\r\n * `calculate-column-widths.ts` decide quanto espaço reservar. Se cada um aplicasse a\r\n * regra por conta, os dois divergiriam no primeiro ajuste — foi exatamente o defeito da\r\n * L-038, onde header e footer liam `col.align` cru e discordavam do body. Aqui a regra\r\n * mora num lugar e os dois a chamam.\r\n *\r\n * ## A geometria, MEDIDA NO BROWSER (e a versão errada que ela substituiu)\r\n *\r\n * A célula é `flex items-center gap-gp-2xs justify-end` dentro de uma `TableCell` que, na\r\n * variante `actions`, usa **`px-pad-md`** — a variante sobrescreve o `px-pad-2xl` default\r\n * das outras células (`Table/table.styles.ts`, bloco `variants.actions`). Com os tokens:\r\n *\r\n * padding = `pad-md` × 2 = 16px\r\n * ícone = `icon-2xs` → `size-form-xs` = 28px\r\n * gap = `gp-2xs` = 2px\r\n *\r\n * largura(n) = 16 + 28n + 2(n−1) = **30n + 14**\r\n *\r\n * Donde 1→44, 2→74, 3→104, 4→134.\r\n *\r\n * ⚠️ A primeira versão deste módulo usava `pad-2xl` (32px de padding) e chegava a\r\n * `30n + 30` — 1→60, 3→120 — com a conclusão elegante de que o `ACTIONS_COLUMN_WIDTH`\r\n * legado (120) \"era exatamente 3 slots\". **Falso**: 3 slots são 104, e 120 fica entre 3 e\r\n * 4. O teste concordava porque derivava da mesma fórmula errada; quem pegou foi a medição\r\n * no browser (`width: 64px` inline, `padding: 8px/8px`, botão 28px, folga 8px). É a L-064\r\n * literal — teste escrito do mesmo modelo mental do código concorda por construção.\r\n *\r\n * ## O limite de 3 não é preferência estética\r\n *\r\n * É a capacidade da coluna que o componente já usava: dentro dos 120px legados sobram\r\n * 104 úteis, e 4 ícones pedem 118. Ou a coluna cresce, ou o excedente vai pro menu. O\r\n * default aqui é **mandar tudo pro menu**, porque coluna de ação larga empurra o conteúdo\r\n * de dados e derrota o motivo de ela estar ancorada à direita.\r\n */\r\n\r\n/** Quantos ícones cabem inline nos 120px que a coluna sempre usou. */\r\nexport const ACTIONS_INLINE_MAX = 3;\r\n\r\n/** Largura da coluna pra `n` slots renderizados (ícones + o \"…\" quando existe). */\r\nexport function actionsWidthForSlots(slots: number): number {\r\n return 30 * Math.max(1, slots) + 14;\r\n}\r\n\r\n/** Uma ação está oculta nesta row? `hidden` aceita boolean ou predicado. */\r\nfunction oculta<T>(a: DataTableActionItem<T>, row: T): boolean {\r\n return typeof a.hidden === \"function\" ? a.hidden(row) : !!a.hidden;\r\n}\r\n\r\n/**\r\n * Divide as ações visíveis de uma row entre inline e menu.\r\n *\r\n * Precedência — e a primeira regra existe pra não passar por cima de decisão explícita:\r\n *\r\n * 1. **Algum item marca `showInMenu`** → o consumer já decidiu o split; respeitado\r\n * integralmente, sem limite de quantidade. Quem quer 5 ícones inline consegue.\r\n * 2. Até `ACTIONS_INLINE_MAX` (3) itens → todos inline, sem \"…\". Uma ação só = um ícone\r\n * só, que é o caso comum de \"editar\".\r\n * 3. Mais de 3 → **todos** vão pro menu, e a coluna renderiza só o \"…\".\r\n */\r\nexport function splitActionSlots<T>(\r\n actions: DataTableActionItem<T>[],\r\n row: T,\r\n): { inline: DataTableActionItem<T>[]; menu: DataTableActionItem<T>[] } {\r\n const visiveis = actions.filter((a) => !oculta(a, row));\r\n if (visiveis.length === 0) return { inline: [], menu: [] };\r\n\r\n // (1) split explícito do consumer manda.\r\n if (visiveis.some((a) => a.showInMenu)) {\r\n return {\r\n inline: visiveis.filter((a) => !a.showInMenu),\r\n menu: visiveis.filter((a) => a.showInMenu),\r\n };\r\n }\r\n // (2) cabe inline.\r\n if (visiveis.length <= ACTIONS_INLINE_MAX) return { inline: visiveis, menu: [] };\r\n // (3) não cabe: tudo pro menu.\r\n return { inline: [], menu: visiveis };\r\n}\r\n\r\n/** Slots renderizados: um por ícone inline, mais um pro \"…\" quando há menu. */\r\nexport function countActionSlots<T>(split: {\r\n inline: DataTableActionItem<T>[];\r\n menu: DataTableActionItem<T>[];\r\n}): number {\r\n return split.inline.length + (split.menu.length > 0 ? 1 : 0);\r\n}\r\n\r\n/**\r\n * Largura necessária pra uma coluna de ações, olhando as rows amostradas.\r\n *\r\n * Usa o **máximo** entre as rows: `hidden` pode variar por row (ex.: \"cancelar\" só em\r\n * pedido aberto), e reservar pelo menor cortaria a row mais completa. Sem `getActions`\r\n * ou sem rows, devolve `null` — quem chama decide o fallback.\r\n */\r\nexport function measureActionsWidth<T>(\r\n getActions: ((params: { row: T }) => DataTableActionItem<T>[]) | undefined,\r\n rows: T[],\r\n): number | null {\r\n if (!getActions || rows.length === 0) return null;\r\n let maxSlots = 0;\r\n for (const row of rows) {\r\n const slots = countActionSlots(splitActionSlots(getActions({ row }), row));\r\n if (slots > maxSlots) maxSlots = slots;\r\n }\r\n if (maxSlots === 0) return null;\r\n return actionsWidthForSlots(maxSlots);\r\n}\r\n","import type { DataTableColumnDef } from \"../data-table.types\";\n\n/**\n * Helpers compartilhados de resolução de valor de cell.\n *\n * Antes da consolidação, 3 lugares duplicavam lógica:\n * - data-table.tsx → `resolveCellValue` (cell render)\n * - hooks/use-data-table-processor.ts → `getFieldValue` + `applyValueGetter` + `applyFormatter` (filter/sort/search)\n * - utils/group-rows.ts → `resolveGroupValue` (agrupamento)\n *\n * Agora todos consomem daqui — single source of truth pra dot-path lookup,\n * valueGetter, e valueFormatter.\n */\n\n/** Acessa valor em row via dot-path (`user.name`) ou key simples. */\nexport function getFieldValue<T>(row: T, field: string): unknown {\n if (!field.includes(\".\")) {\n return (row as Record<string, unknown>)[field];\n }\n return field\n .split(\".\")\n .reduce<unknown>(\n (acc, key) => (acc as Record<string, unknown> | null | undefined)?.[key],\n row,\n );\n}\n\n/** Resolve valor da cell: prioriza `column.valueGetter`, senão dot-path do field. */\nexport function applyValueGetter<T>(row: T, column: DataTableColumnDef<T>): unknown {\n if (column.valueGetter) return column.valueGetter(row);\n return getFieldValue(row, String(column.field));\n}\n\n/** Resolve string formatada: pega valor + aplica `column.valueFormatter` se houver. */\nexport function applyFormatter<T>(row: T, column: DataTableColumnDef<T>): string {\n const value = applyValueGetter(row, column);\n if (column.valueFormatter) return column.valueFormatter(value);\n return value == null ? \"\" : String(value);\n}\n","/**\r\n * calculate-column-widths.ts — 3-layer auto-width calculator.\r\n *\r\n * Inspirado no padrão de DataGrids modernos (AG Grid / TanStack / design-tabela\r\n * reference). Calcula widths das colunas em 3 camadas, do menos específico ao mais:\r\n *\r\n * Layer 1 — Type Heuristics\r\n * Cada `type` de coluna tem um `defaultWidth` (registry). Quando `col.width`\r\n * é explícito, ele vence; caso contrário, fallback pro `defaultWidth` do tipo\r\n * (ou DEFAULT_COLUMN_WIDTH se nem o tipo definir).\r\n *\r\n * Layer 2 — Smart Content Sampling (canvas measure)\r\n * Quando `autoFit: true` no DataTable, mede o texto do header + primeiros N\r\n * rows e expande width pra caber o conteúdo. Aplica min/maxWidth do col como\r\n * constraints. Útil pra evitar truncate desnecessário.\r\n *\r\n * Layer 3 — Flex Space Distribution\r\n * Após Layers 1+2, se a soma das widths < containerWidth, distribui o\r\n * espaço sobrando entre colunas SEM `col.width` explícito do consumer.\r\n * Resolve o caso \"tabela com poucas colunas e espaço sobrando à direita\".\r\n *\r\n * Coluna `type: \"actions\"` fica **fora das 3 layers** (não mede texto, não entra no\r\n * flex), mas a largura dela SIM é decidida aqui: `col.width` > `col.minWidth` >\r\n * derivada do nº de ações que a célula vai renderizar (`utils/action-slots.ts`) >\r\n * `ACTIONS_COLUMN_WIDTH`. Até 2026-08-18 este cabeçalho dizia *\"essas mantêm o width\r\n * explícito (consumer sempre passa)\"* — errado nos dois pedaços: o ramo lia só\r\n * `minWidth`, ignorando o `col.width` que o consumer passava, e o builder\r\n * `actionColumn` nem sempre passa width.\r\n */\r\n\r\nimport type { DataTableColumnDef } from \"../data-table.types\";\r\nimport { columnTypeRegistry } from \"../column-types\";\r\nimport { ACTIONS_COLUMN_WIDTH } from \"../data-table.constants\";\r\nimport { measureTextWidth } from \"./measure-text\";\r\nimport { measureActionsWidth } from \"./action-slots\";\r\nimport { applyValueGetter, applyFormatter } from \"./resolve-value\";\r\n\r\n/** Largura default quando nem `col.width` nem `typeDef.defaultWidth` definem. */\r\nexport const DEFAULT_COLUMN_WIDTH = 160;\r\n/** Padding horizontal somado ao texto medido — alinha com `px-pad-2xl` (16px×2). */\r\nexport const CELL_PADDING_PX = 32;\r\n/** Tamanho default da amostra de rows pra Layer 2. */\r\nexport const DEFAULT_SAMPLE_SIZE = 20;\r\n\r\n/**\r\n * Overhead horizontal do ÍCONE DE TIPO no header (`<Icon size=13>` + `gap-gp-md`\r\n * de 8px). Somado SÓ à medição do header (o ícone vive só no head cell, não nas\r\n * células do corpo). Garante que o título não seja truncado quando a coluna tem\r\n * ícone (`col.icon` ou `typeDef.defaultIcon`).\r\n */\r\nexport const HEADER_ICON_PX = 13 + 8;\r\n\r\n/**\r\n * Reserva horizontal pras affordances de sort/menu no header (`headRightStack`\r\n * absolute na borda direita). Quando a coluna é sortável ou tem headMenu, o\r\n * stack pode aparecer (no hover) ou ficar fixo (`pr-[60px]` quando sort ATIVO).\r\n * Reservamos o suficiente pra que o `headerName` continue legível sem \"...\" mesmo\r\n * com a coluna ordenada. Mantido conservador (≈ ícone + respiro) pra não inflar\r\n * demais cada coluna — o objetivo é não-truncar, não reservar os 60px de hover.\r\n */\r\nexport const HEADER_SORT_AFFORDANCE_PX = 24;\r\n\r\n/**\r\n * Largura MÍNIMA que o head cell precisa pra mostrar o `headerName` inteiro, sem\r\n * truncar (\"...\"). Soma ao texto medido: padding horizontal + ícone de tipo (se\r\n * houver) + reserva de sort/menu (se sortável ou com headMenu/filtro). É o piso\r\n * que toda coluna respeita — INCLUSIVE as com `col.width` explícito menor que o\r\n * header (o título é informação importante e tem que caber).\r\n */\r\nfunction measureHeaderMinWidth<T>(\r\n col: DataTableColumnDef<T>,\r\n typeDef: { defaultIcon?: unknown; defaultSortable?: boolean } | undefined,\r\n): number {\r\n const headerText = String(col.headerName ?? String(col.field));\r\n const hasHeaderIcon =\r\n col.icon !== undefined || typeDef?.defaultIcon !== undefined;\r\n const isSortable = col.sortable ?? typeDef?.defaultSortable ?? false;\r\n const hasHeadMenu = col.enableColumnFilter === true;\r\n const overhead =\r\n CELL_PADDING_PX +\r\n (hasHeaderIcon ? HEADER_ICON_PX : 0) +\r\n (isSortable || hasHeadMenu ? HEADER_SORT_AFFORDANCE_PX : 0);\r\n return measureTextWidth(headerText) + overhead;\r\n}\r\n\r\nexport interface CalculateColumnWidthsOptions {\r\n /** Largura interna do container observada via ResizeObserver. */\r\n containerWidth: number;\r\n /** Habilita Layer 2 (canvas measure) globalmente. */\r\n autoFit: boolean;\r\n /** Tamanho da amostra de rows para Layer 2. Default 20. */\r\n sampleSize?: number;\r\n}\r\n\r\n/**\r\n * Calcula widths das colunas em 3 camadas.\r\n *\r\n * Retorna `Record<field, number>` com widths em pixels. Apenas colunas que\r\n * NÃO têm `col.width` explícito do consumer recebem widths calculados.\r\n * Colunas com `col.width` ficam de fora do retorno — `useDataTableColumns`\r\n * usa `col.width` como fallback quando o autoWidth não tem entry.\r\n *\r\n * Quando `containerWidth <= 0` (mount inicial antes do ResizeObserver),\r\n * retorna {} — `useDataTableColumns` cai no fallback de `col.width`/typeDef.\r\n */\r\nexport function calculateColumnWidths<T>(\r\n columns: DataTableColumnDef<T>[],\r\n rows: T[],\r\n options: CalculateColumnWidthsOptions,\r\n): Record<string, number> {\r\n const { containerWidth, autoFit, sampleSize = DEFAULT_SAMPLE_SIZE } = options;\r\n\r\n if (containerWidth <= 0) return {};\r\n\r\n const widths: Record<string, number> = {};\r\n let totalContentWidth = 0;\r\n\r\n // ── Layer 1 + 2 ───────────────────────────────────────────────\r\n for (const col of columns) {\r\n const field = String(col.field);\r\n\r\n // `actions`: largura fixa estreita (ícone/menu). Não mede conteúdo textual nem\r\n // entra no flex (Layer 3) — senão vira 160px e/ou estica.\r\n //\r\n // Precedência, e as duas primeiras são correções de defeito MEDIDO:\r\n //\r\n // 1. `col.width` — antes era IGNORADO aqui: o ramo lia só `col.minWidth`, então\r\n // `actionColumn({ width: 64 })` devolvia 120 em silêncio. As duas skills\r\n // `crud-builder` (repo e payload) instruíam justamente `width: 64` como \"seguro\".\r\n // 2. `col.minWidth` — segue funcionando (era a única saída que funcionava).\r\n // 3. Largura DERIVADA do número de slots que a célula vai renderizar, via o mesmo\r\n // `splitActionSlots` que ela usa. Antes era 120 fixo pra qualquer quantidade:\r\n // 1 ação reservava espaço pra 3, e 4 ícones vazavam a coluna em 30px.\r\n // 4. `ACTIONS_COLUMN_WIDTH` (120 = 3 slots) quando não há `getActions` ou rows\r\n // pra medir.\r\n if (col.type === \"actions\") {\r\n const w =\r\n col.width ??\r\n col.minWidth ??\r\n measureActionsWidth(col.getActions, rows.slice(0, sampleSize)) ??\r\n ACTIONS_COLUMN_WIDTH;\r\n widths[field] = w;\r\n totalContentWidth += w;\r\n continue;\r\n }\r\n\r\n const typeDef = col.type ? columnTypeRegistry.get(col.type) : undefined;\r\n\r\n // Coluna com width explícito do consumer: respeita como BASE (mínimo).\r\n // Registra no output e na base da flex distribution — cresce proporcional\r\n // junto das demais, mas nunca abaixo do width pedido. PISO adicional: o\r\n // header nunca trunca — se o `width` pedido é menor que o que cabe o título,\r\n // sobe pro mínimo do header (a width do consumer não pode esconder o\r\n // headerName). maxWidth ainda limita o topo (header > maxWidth = truncamento\r\n // assumido pelo consumer).\r\n if (col.width !== undefined) {\r\n let w = Math.max(col.width, measureHeaderMinWidth(col, typeDef));\r\n if (col.maxWidth !== undefined && w > col.maxWidth) w = col.maxWidth;\r\n widths[field] = Math.round(w);\r\n totalContentWidth += w;\r\n continue;\r\n }\r\n\r\n // Layer 1 — Type Heuristics\r\n let calculatedWidth = typeDef?.defaultWidth ?? DEFAULT_COLUMN_WIDTH;\r\n\r\n // Layer 2 — Smart Content Sampling (canvas measure)\r\n if (autoFit) {\r\n // Mede header (com affordances — ver measureHeaderMinWidth) pra o título\r\n // nunca truncar, e depois a amostra de células; fica com o maior.\r\n let maxWidth = measureHeaderMinWidth(col, typeDef);\r\n\r\n // Mede sample de rows usando applyFormatter (cobre valueGetter + valueFormatter)\r\n const sample = rows.slice(0, sampleSize);\r\n for (const row of sample) {\r\n const text = applyFormatter(row, col);\r\n if (!text) continue;\r\n const w = measureTextWidth(text) + CELL_PADDING_PX;\r\n if (w > maxWidth) maxWidth = w;\r\n }\r\n\r\n if (maxWidth > calculatedWidth) calculatedWidth = maxWidth;\r\n }\r\n\r\n // Min/max constraints do consumer\r\n if (col.minWidth !== undefined && calculatedWidth < col.minWidth) {\r\n calculatedWidth = col.minWidth;\r\n }\r\n if (col.maxWidth !== undefined && calculatedWidth > col.maxWidth) {\r\n calculatedWidth = col.maxWidth;\r\n }\r\n\r\n widths[field] = Math.round(calculatedWidth);\r\n totalContentWidth += calculatedWidth;\r\n }\r\n\r\n // ── Layer 3 — Flex Space Distribution (proporcional) ──────────\r\n // Quando a soma das larguras é MENOR que o container, distribui o espaço que\r\n // sobra PROPORCIONALMENTE à largura de cada coluna (flex-fill, como uma tabela\r\n // faz naturalmente) — em vez de dividir igualmente OU jogar tudo na única\r\n // coluna sem `width`. O peso de cada coluna é a própria largura-base, então\r\n // colunas pequenas crescem pouco e largas crescem mais, sem \"coluna gigante\".\r\n // Resultado independe da quantidade de colunas (4 grandes OU 6 pequenas).\r\n //\r\n // Colunas com `col.width` ENTRAM no rateio (a width é o piso) — mas só quando\r\n // há ao menos uma coluna SEM width pra \"puxar\" o fill; se TODAS têm width\r\n // explícito, respeitamos o layout fixo do consumer e deixamos o vazio à direita\r\n // (não inflar larguras que o consumer travou de propósito).\r\n if (totalContentWidth < containerWidth) {\r\n // `actions`/`checkbox` NUNCA entram no flex — são colunas de largura fixa\r\n // (ícone), senão \"esticam\" e empurram o conteúdo (bug do auto-width).\r\n const isFixed = (col: DataTableColumnDef<T>) =>\r\n col.type === \"actions\" || col.type === \"checkbox\";\r\n const nonFixed = columns.filter((col) => !isFixed(col));\r\n const hasFlexible = nonFixed.some((col) => col.width === undefined);\r\n // Se existe coluna fluida, TODAS as não-fixas crescem proporcional (a width\r\n // explícita vira piso). Se não há nenhuma fluida, só distribui quando autoFit\r\n // está ligado — senão mantém o layout 100% fixo do consumer.\r\n const targets = hasFlexible || autoFit ? nonFixed : [];\r\n\r\n if (targets.length > 0) {\r\n // Distribuição proporcional com clamp por maxWidth e REDISTRIBUIÇÃO do\r\n // resíduo. Itera enquanto sobra espaço E há colunas que ainda podem crescer:\r\n // - cada coluna recebe espaço ∝ sua largura atual (peso = largura)\r\n // - coluna que bate no maxWidth sai do rateio; o resto é redividido entre\r\n // as restantes (senão o espaço sobraria à direita).\r\n const baseWidth = (col: DataTableColumnDef<T>) =>\r\n widths[String(col.field)] ?? col.width ?? DEFAULT_COLUMN_WIDTH;\r\n\r\n // Colunas ainda \"elásticas\" (não atingiram maxWidth).\r\n let growable = targets.filter((col) => {\r\n const f = String(col.field);\r\n return col.maxWidth === undefined || (widths[f] ?? 0) < col.maxWidth;\r\n });\r\n\r\n let remaining = containerWidth - totalContentWidth;\r\n // Loop de redistribuição — em cada passada, rateia `remaining` por peso.\r\n // Para quando: nada sobra (<1px), ou nenhuma coluna pode mais crescer.\r\n let guard = 0;\r\n while (remaining >= 1 && growable.length > 0 && guard < 16) {\r\n guard += 1;\r\n const totalWeight = growable.reduce((sum, col) => sum + baseWidth(col), 0);\r\n if (totalWeight <= 0) break;\r\n\r\n let consumedThisPass = 0;\r\n const stillGrowable: DataTableColumnDef<T>[] = [];\r\n\r\n for (const col of growable) {\r\n const f = String(col.field);\r\n const current = widths[f] ?? col.width ?? 0;\r\n const share = (baseWidth(col) / totalWeight) * remaining;\r\n const next = current + share;\r\n\r\n if (col.maxWidth !== undefined && next >= col.maxWidth) {\r\n // Bate no teto — consome só até o max e sai do rateio.\r\n consumedThisPass += col.maxWidth - current;\r\n widths[f] = col.maxWidth;\r\n } else {\r\n consumedThisPass += share;\r\n widths[f] = next;\r\n stillGrowable.push(col);\r\n }\r\n }\r\n\r\n remaining -= consumedThisPass;\r\n growable = stillGrowable;\r\n // Se a passada não consumiu nada relevante, evita loop infinito.\r\n if (consumedThisPass < 0.5) break;\r\n }\r\n\r\n // Arredonda no fim (evita acúmulo de erro de fração durante o rateio).\r\n // O resíduo (sub-pixel × nº de colunas) é absorvido pela ÚLTIMA coluna que\r\n // ainda pode crescer (sem maxWidth ou abaixo dele), pra a soma casar com o\r\n // container — preenchimento exato, sem 1-2px de vazio à direita.\r\n //\r\n // ⚠️ O alvo do snap é `containerWidth` MENOS as colunas fixas. `roundedTotal`\r\n // soma apenas os `targets`, e `actions`/`checkbox` foram excluídos deles 60 linhas\r\n // acima — então comparar direto com o container faz os targets preencherem a tela\r\n // inteira e as fixas sobrarem POR CIMA, produzindo scroll horizontal com a largura\r\n // exata delas. Medido em 2026-08-19 no `#/clientes-showcase`: 13 colunas somando\r\n // 1950px num container de 1906 → 44px de scroll, e a coluna de ações mede 44px.\r\n //\r\n // A coluna de SELEÇÃO já era tratada certo, por outro caminho: ela não está em\r\n // `columns` e é descontada antes do cálculo, via `reservedWidth` em\r\n // `use-data-table-controller.ts`. Aqui fazemos o equivalente pras que ESTÃO em\r\n // `columns` mas ficaram fora do rateio.\r\n const larguraFixa = columns\r\n .filter(isFixed)\r\n .reduce((soma, col) => soma + (widths[String(col.field)] ?? 0), 0);\r\n\r\n let lastFlexField: string | undefined;\r\n let roundedTotal = 0;\r\n for (const col of targets) {\r\n const f = String(col.field);\r\n widths[f] = Math.round(widths[f] ?? col.width ?? 0);\r\n roundedTotal += widths[f];\r\n const maxed = col.maxWidth !== undefined && widths[f] >= col.maxWidth;\r\n if (!maxed) lastFlexField = f;\r\n }\r\n if (lastFlexField !== undefined) {\r\n const residue = Math.round(containerWidth) - larguraFixa - roundedTotal;\r\n if (residue !== 0) {\r\n widths[lastFlexField] = Math.max(0, widths[lastFlexField] + residue);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return widths;\r\n}\r\n","/**\r\n * use-column-auto-width.ts — ResizeObserver hook that auto-calculates\r\n * column widths to fill the container.\r\n *\r\n * Quando ativo (`enabled: true`), observa o container via ResizeObserver e\r\n * delega o cálculo de widths para `calculateColumnWidths` (3 layers).\r\n * Retorna `Record<field, number>` com widths em pixels que devem ser\r\n * aplicados na precedência: resize manual > autoFit (este hook) > col.width.\r\n *\r\n * Notas:\r\n * - Quando `enabled: false` (default em consumers que não passam `autoFit`),\r\n * retorna `{}` e não instala o observer — zero overhead.\r\n * - Recalcula apenas no resize do container OU mudanças relevantes\r\n * (columns count/widths estáticos, rows sample). NÃO recalcula a cada render.\r\n * - Usa `requestAnimationFrame` pra coalescer múltiplos resize events.\r\n */\r\n\r\nimport { useEffect, useRef, useState } from \"react\";\r\nimport type { RefObject } from \"react\";\r\nimport type { DataTableColumnDef } from \"../data-table.types\";\r\nimport {\r\n calculateColumnWidths,\r\n type CalculateColumnWidthsOptions,\r\n} from \"../utils/calculate-column-widths\";\r\n\r\nexport interface UseColumnAutoWidthOptions {\r\n /** Liga/desliga o auto-width. Default false. */\r\n enabled: boolean;\r\n /** Tamanho da amostra de rows pra Layer 2. Default 20. */\r\n sampleSize?: number;\r\n /**\r\n * Pixels reservados no container que NÃO contam pro cálculo das colunas\r\n * (ex: largura da coluna `selection` checkbox que é injetada pelo DataTable\r\n * e não vem em `props.columns`). Subtraído do `contentRect.width` antes de\r\n * chamar `calculateColumnWidths`. Default 0.\r\n */\r\n reservedWidth?: number;\r\n /**\r\n * Chave de re-attach. Quando muda, o effect re-instala o ResizeObserver e\r\n * re-mede do zero. Necessário quando o elemento observado DESMONTA e REMONTA\r\n * sem que `containerRef` (objeto estável) mude de identidade — ex: toggle de\r\n * view Tabela↔Lista, em que o corpo da tabela (e o `scrollRef`) é trocado por\r\n * `<List>` e volta. Sem isso, o observer ficaria preso ao node antigo\r\n * (destacado) e o autoFit reaplicaria larguras stale ao voltar pra Tabela.\r\n */\r\n recalcKey?: string | number;\r\n}\r\n\r\nexport interface UseColumnAutoWidthResult {\r\n /** Map de widths calculados, indexado por field. {} quando desligado ou pre-mount. */\r\n autoWidths: Record<string, number>;\r\n}\r\n\r\n/**\r\n * Hook que observa o container e calcula widths via `calculateColumnWidths`.\r\n *\r\n * @param containerRef — ref do elemento que tem o tamanho de referência (geralmente o `scrollContainerRef` do Table)\r\n * @param columns — colunas atuais (effectiveColumns do DataTable)\r\n * @param rows — rows visíveis pra amostragem de Layer 2\r\n * @param options — `{ enabled, sampleSize }`\r\n */\r\nexport function useColumnAutoWidth<T>(\r\n containerRef: RefObject<HTMLDivElement | null>,\r\n columns: DataTableColumnDef<T>[],\r\n rows: T[],\r\n options: UseColumnAutoWidthOptions,\r\n): UseColumnAutoWidthResult {\r\n const { enabled, sampleSize, reservedWidth = 0, recalcKey } = options;\r\n\r\n const [autoWidths, setAutoWidths] = useState<Record<string, number>>({});\r\n const rafIdRef = useRef<number | null>(null);\r\n\r\n // Snapshot estável das colunas/rows pra evitar re-observer churn.\r\n // Quando colunas/rows mudam, o effect re-roda naturalmente.\r\n const columnsRef = useRef(columns);\r\n const rowsRef = useRef(rows);\r\n columnsRef.current = columns;\r\n rowsRef.current = rows;\r\n\r\n useEffect(() => {\r\n if (!enabled) {\r\n setAutoWidths((prev) => (Object.keys(prev).length === 0 ? prev : {}));\r\n return;\r\n }\r\n\r\n const el = containerRef.current;\r\n if (!el) return;\r\n if (typeof ResizeObserver === \"undefined\") return; // SSR / IE safe\r\n\r\n const recalculate = (containerWidth: number) => {\r\n // Desconta colunas externas (ex: selection checkbox de 56px) que ocupam\r\n // espaço no container mas não estão em `props.columns`.\r\n const effectiveWidth = Math.max(0, containerWidth - reservedWidth);\r\n const calcOptions: CalculateColumnWidthsOptions = {\r\n containerWidth: effectiveWidth,\r\n autoFit: enabled,\r\n sampleSize,\r\n };\r\n const next = calculateColumnWidths(\r\n columnsRef.current,\r\n rowsRef.current,\r\n calcOptions,\r\n );\r\n\r\n setAutoWidths((prev) => {\r\n // Skip re-render se nada mudou\r\n const prevKeys = Object.keys(prev);\r\n const nextKeys = Object.keys(next);\r\n if (prevKeys.length === nextKeys.length) {\r\n let same = true;\r\n for (const k of nextKeys) {\r\n if (prev[k] !== next[k]) {\r\n same = false;\r\n break;\r\n }\r\n }\r\n if (same) return prev;\r\n }\r\n return next;\r\n });\r\n };\r\n\r\n // Cálculo inicial — usa `clientWidth` (content-box, EXCLUI scrollbar) pra ficar\r\n // consistente com `entry.contentRect.width` do ResizeObserver. Antes usava\r\n // getBoundingClientRect().width (border-box, INCLUI scrollbar vertical), o que\r\n // sobre-estimava a largura no 1º paint quando já havia scroll-Y (totalizer/altura\r\n // forçada) → colunas largas demais até o 1º resize. clientWidth alinha as duas vias.\r\n recalculate(el.clientWidth);\r\n\r\n const observer = new ResizeObserver((entries) => {\r\n const entry = entries[0];\r\n if (!entry) return;\r\n\r\n // Coalesce múltiplos resize events via rAF\r\n if (rafIdRef.current !== null) cancelAnimationFrame(rafIdRef.current);\r\n rafIdRef.current = requestAnimationFrame(() => {\r\n rafIdRef.current = null;\r\n recalculate(entry.contentRect.width);\r\n });\r\n });\r\n\r\n observer.observe(el);\r\n\r\n return () => {\r\n observer.disconnect();\r\n if (rafIdRef.current !== null) {\r\n cancelAnimationFrame(rafIdRef.current);\r\n rafIdRef.current = null;\r\n }\r\n };\r\n // Recalcula quando:\r\n // - enabled flip\r\n // - número de colunas muda (add/remove)\r\n // - número de rows muda significativamente (sample diferente)\r\n // - sampleSize muda\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [\r\n enabled,\r\n containerRef,\r\n sampleSize,\r\n reservedWidth,\r\n // Re-attach quando o elemento observado desmonta/remonta sem trocar a ref\r\n // (toggle de view Tabela↔Lista). Sem isso o observer fica no node antigo.\r\n recalcKey,\r\n columns.length,\r\n rows.length,\r\n // Inclui campos das columns pra recalcular quando consumer muda a schema\r\n columns.map((c) => String(c.field)).join(\"|\"),\r\n ]);\r\n\r\n return { autoWidths };\r\n}\r\n","import { useCallback, useState } from \"react\";\nimport type { SortModel } from \"../data-table.types\";\n\n/** Normaliza valor controlled/initial pra array (aceita single, array ou null). */\nfunction toArray(v: SortModel | SortModel[] | null | undefined): SortModel[] {\n if (v == null) return [];\n if (Array.isArray(v)) return v;\n return [v];\n}\n\nexport type UseDataTableSortParams = {\n /**\n * Controlled sort. Aceita single (1 criterio) ou array (multi-sort).\n * Array vazio ou null = sem sort.\n */\n sortModel?: SortModel | SortModel[] | null;\n /** Callback quando muda. Sempre recebe array. */\n onSortModelChange?: (model: SortModel[]) => void;\n /** Hidratado de localStorage. Single ou array. */\n initialSortModel?: SortModel | SortModel[] | null;\n};\n\nexport type UseDataTableSortResult = {\n /** Lista de criterios — primeiro = prioridade maior. */\n sortModels: SortModel[];\n /** Backward-compat: primeiro criterio (ou null). */\n sortModel: SortModel | null;\n /** Click no header — ciclo asc → desc → null. Substitui multi por single. */\n handleSort: (field: string) => void;\n /** Setter direto (substitui lista inteira). */\n setSortModels: (models: SortModel[]) => void;\n /**\n * @deprecated — use setSortModels com array.\n * Compat: aceita single objeto/null e wrappea pra array.\n */\n setSortModel: (model: SortModel | null) => void;\n};\n\n/**\n * Sort state — multi-sort com array de criterios.\n *\n * Click no header zera multi e define 1 criterio (ciclo asc/desc/null).\n * Multi-sort eh editado via popover (SortPopover usa setSortModels com array).\n *\n * Controlled quando `sortModel` prop presente (aceita single ou array).\n */\nexport function useDataTableSort({\n sortModel: controlledSort,\n onSortModelChange,\n initialSortModel,\n}: UseDataTableSortParams = {}): UseDataTableSortResult {\n const [uncontrolledSort, setUncontrolledSort] = useState<SortModel[]>(\n () => toArray(initialSortModel),\n );\n const isControlled = controlledSort !== undefined;\n const sortModels = isControlled ? toArray(controlledSort) : uncontrolledSort;\n\n const setSortModels = useCallback(\n (models: SortModel[]) => {\n if (!isControlled) setUncontrolledSort(models);\n onSortModelChange?.(models);\n },\n [isControlled, onSortModelChange],\n );\n\n const setSortModel = useCallback(\n (model: SortModel | null) => {\n setSortModels(model ? [model] : []);\n },\n [setSortModels],\n );\n\n const handleSort = useCallback(\n (field: string) => {\n // Click no header SEMPRE zera multi e define 1 criterio com ciclo.\n // Pra adicionar multi, usar SortPopover.\n const current = sortModels.find((s) => s.field === field);\n if (!current) {\n setSortModels([{ field, direction: \"asc\" }]);\n } else if (current.direction === \"asc\") {\n setSortModels([{ field, direction: \"desc\" }]);\n } else {\n setSortModels([]);\n }\n },\n [sortModels, setSortModels],\n );\n\n return {\n sortModels,\n sortModel: sortModels[0] ?? null,\n handleSort,\n setSortModels,\n setSortModel,\n };\n}\n","import { useCallback, useEffect, useState } from \"react\";\r\nimport type { PaginationModel } from \"../data-table.types\";\r\n\r\nexport type UseDataTablePaginationParams = {\r\n paginationModel?: PaginationModel;\r\n onPaginationModelChange?: (model: PaginationModel) => void;\r\n initialPageSize?: number;\r\n /** Página inicial uncontrolled (hidratada do localStorage). Default 1. */\r\n initialPage?: number;\r\n /** Reset page→1 quando esses valores mudarem (ex: filtro, search). */\r\n resetTriggers?: unknown[];\r\n};\r\n\r\nexport type UseDataTablePaginationResult = {\r\n paginationModel: PaginationModel;\r\n setPage: (page: number) => void;\r\n setPageSize: (pageSize: number) => void;\r\n setPaginationModel: (model: PaginationModel) => void;\r\n};\r\n\r\nconst DEFAULT_PAGE_SIZE = 25;\r\n\r\n/**\r\n * Pagination state. Auto-reseta para page 1 quando triggers mudam (filter/search).\r\n */\r\nexport function useDataTablePagination({\r\n paginationModel: controlledModel,\r\n onPaginationModelChange,\r\n initialPageSize = DEFAULT_PAGE_SIZE,\r\n initialPage = 1,\r\n resetTriggers = [],\r\n}: UseDataTablePaginationParams = {}): UseDataTablePaginationResult {\r\n const [uncontrolled, setUncontrolled] = useState<PaginationModel>({\r\n page: initialPage,\r\n pageSize: initialPageSize,\r\n });\r\n const isControlled = controlledModel !== undefined;\r\n const paginationModel = isControlled ? controlledModel : uncontrolled;\r\n\r\n const setPaginationModel = useCallback(\r\n (model: PaginationModel) => {\r\n if (!isControlled) setUncontrolled(model);\r\n onPaginationModelChange?.(model);\r\n },\r\n [isControlled, onPaginationModelChange],\r\n );\r\n\r\n const setPage = useCallback(\r\n (page: number) => {\r\n // Functional update pra evitar stale closure quando setPage é chamado\r\n // logo após setPageSize no mesmo render tick (ex: FooterTable.onValueChange\r\n // chama setPageSize(N) seguido de setPage(1)).\r\n if (!isControlled) {\r\n setUncontrolled((prev) => ({ ...prev, page }));\r\n }\r\n onPaginationModelChange?.({ ...paginationModel, page });\r\n },\r\n [paginationModel, isControlled, onPaginationModelChange],\r\n );\r\n\r\n const setPageSize = useCallback(\r\n (pageSize: number) => {\r\n if (!isControlled) {\r\n setUncontrolled((prev) => ({ ...prev, pageSize, page: 1 }));\r\n }\r\n onPaginationModelChange?.({ page: 1, pageSize });\r\n },\r\n [isControlled, onPaginationModelChange],\r\n );\r\n\r\n // Reset page→1 quando triggers mudam (ex: filtros aplicados, search digitado)\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n useEffect(() => {\r\n if (paginationModel.page !== 1) {\r\n setPaginationModel({ ...paginationModel, page: 1 });\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, resetTriggers);\r\n\r\n return { paginationModel, setPage, setPageSize, setPaginationModel };\r\n}\r\n","import { useCallback, useMemo, useState } from \"react\";\nimport type { GridRowId, GridSelectionState } from \"../data-table.types\";\n\nexport type UseDataTableSelectionParams<T> = {\n rows: T[];\n getRowId: (row: T) => GridRowId;\n /** Controlled selection. */\n selectionModel?: GridSelectionState;\n onSelectionModelChange?: (model: GridSelectionState) => void;\n};\n\nexport type UseDataTableSelectionResult<T> = {\n /** Estado bruto. */\n state: GridSelectionState;\n /** True se a row está selecionada. */\n isRowSelected: (row: T) => boolean;\n /** Toggle uma row. */\n toggleRow: (row: T) => void;\n /** Seleciona/deseleciona todas as rows da página atual. */\n togglePage: (rowsOnPage: T[]) => void;\n /** Vira \"exclude all\": seleciona TUDO (incluindo dados não carregados). */\n selectAll: () => void;\n /** Limpa. */\n clear: () => void;\n /** Quantidade selecionada (rows visíveis). */\n selectedCount: number;\n /** IDs como array (utility). */\n selectedIds: GridRowId[];\n /** True quando todas as rows visíveis estão selecionadas. */\n isPageSelected: (rowsOnPage: T[]) => boolean;\n /** True quando ALGUMA (mas não todas) estão selecionadas. Pra indeterminate. */\n isPageIndeterminate: (rowsOnPage: T[]) => boolean;\n};\n\nconst EMPTY_STATE: GridSelectionState = { type: \"include\", ids: new Set() };\n\n/**\n * Selection com modelo include/exclude. Permite \"select all global\" sem materializar IDs.\n */\nexport function useDataTableSelection<T>({\n rows,\n getRowId,\n selectionModel: controlledState,\n onSelectionModelChange,\n}: UseDataTableSelectionParams<T>): UseDataTableSelectionResult<T> {\n const [uncontrolled, setUncontrolled] = useState<GridSelectionState>(EMPTY_STATE);\n const isControlled = controlledState !== undefined;\n const state = isControlled ? controlledState : uncontrolled;\n\n const setState = useCallback(\n (next: GridSelectionState) => {\n if (!isControlled) setUncontrolled(next);\n onSelectionModelChange?.(next);\n },\n [isControlled, onSelectionModelChange],\n );\n\n const isRowSelected = useCallback(\n (row: T) => {\n const id = getRowId(row);\n const hasInIds = state.ids.has(id);\n return state.type === \"include\" ? hasInIds : !hasInIds;\n },\n [state, getRowId],\n );\n\n const toggleRow = useCallback(\n (row: T) => {\n const id = getRowId(row);\n const nextIds = new Set(state.ids);\n if (nextIds.has(id)) nextIds.delete(id);\n else nextIds.add(id);\n setState({ type: state.type, ids: nextIds });\n },\n [state, getRowId, setState],\n );\n\n const togglePage = useCallback(\n (rowsOnPage: T[]) => {\n const allSelected = rowsOnPage.every(isRowSelected);\n const nextIds = new Set(state.ids);\n if (allSelected) {\n for (const r of rowsOnPage) {\n const id = getRowId(r);\n if (state.type === \"include\") nextIds.delete(id);\n else nextIds.add(id);\n }\n } else {\n for (const r of rowsOnPage) {\n const id = getRowId(r);\n if (state.type === \"include\") nextIds.add(id);\n else nextIds.delete(id);\n }\n }\n setState({ type: state.type, ids: nextIds });\n },\n [state, isRowSelected, getRowId, setState],\n );\n\n const selectAll = useCallback(() => {\n setState({ type: \"exclude\", ids: new Set() });\n }, [setState]);\n\n const clear = useCallback(() => {\n setState({ type: \"include\", ids: new Set() });\n }, [setState]);\n\n const selectedCount = useMemo(() => {\n if (state.type === \"include\") return state.ids.size;\n return rows.length - state.ids.size;\n }, [state, rows.length]);\n\n const selectedIds = useMemo<GridRowId[]>(() => {\n if (state.type === \"include\") return Array.from(state.ids);\n // exclude: visíveis menos os excluídos\n return rows\n .map(getRowId)\n .filter((id) => !state.ids.has(id));\n }, [state, rows, getRowId]);\n\n const isPageSelected = useCallback(\n (rowsOnPage: T[]) => rowsOnPage.length > 0 && rowsOnPage.every(isRowSelected),\n [isRowSelected],\n );\n\n const isPageIndeterminate = useCallback(\n (rowsOnPage: T[]) => {\n const sel = rowsOnPage.filter(isRowSelected).length;\n return sel > 0 && sel < rowsOnPage.length;\n },\n [isRowSelected],\n );\n\n return {\n state,\n isRowSelected,\n toggleRow,\n togglePage,\n selectAll,\n clear,\n selectedCount,\n selectedIds,\n isPageSelected,\n isPageIndeterminate,\n };\n}\n","import { useCallback, useState } from \"react\";\nimport type { TableDensity } from \"../../Table\";\n\nexport type UseDataTableDensityParams = {\n density?: TableDensity;\n onDensityChange?: (density: TableDensity) => void;\n defaultDensity?: TableDensity;\n /** Hidratado de localStorage. Aplicado apenas no mount. */\n initialDensity?: TableDensity;\n};\n\nexport type UseDataTableDensityResult = {\n density: TableDensity;\n setDensity: (density: TableDensity) => void;\n};\n\nexport function useDataTableDensity({\n density: controlled,\n onDensityChange,\n defaultDensity = \"standard\",\n initialDensity,\n}: UseDataTableDensityParams = {}): UseDataTableDensityResult {\n const [uncontrolled, setUncontrolled] = useState<TableDensity>(\n () => initialDensity ?? defaultDensity,\n );\n const isControlled = controlled !== undefined;\n const density = isControlled ? controlled : uncontrolled;\n\n const setDensity = useCallback(\n (next: TableDensity) => {\n if (!isControlled) setUncontrolled(next);\n onDensityChange?.(next);\n },\n [isControlled, onDensityChange],\n );\n\n return { density, setDensity };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\r\n\r\nexport type UseDataTableSearchParams = {\r\n /** Controlled search. */\r\n search?: string;\r\n onSearchChange?: (value: string) => void;\r\n /** Tempo de debounce em ms. Default 500. */\r\n debounceMs?: number;\r\n /** Estado inicial hidratado (de localStorage) — aplicado apenas no mount uncontrolled. */\r\n initialSearch?: string;\r\n};\r\n\r\nexport type UseDataTableSearchResult = {\r\n /** Valor em tempo real (sem debounce) — pra binding do input. */\r\n inputValue: string;\r\n /** Valor debounced — usado pelo processor/query. */\r\n debouncedValue: string;\r\n /** Update — atualiza input + agenda update do debounced. */\r\n setInputValue: (value: string) => void;\r\n /** Force apply imediato (pra Enter, blur). */\r\n flush: () => void;\r\n};\r\n\r\nconst DEFAULT_DEBOUNCE = 500;\r\n\r\n/**\r\n * Search com debounce — separa o input (rápido) do valor \"comprometido\" (lento).\r\n * Em client mode: debouncedValue alimenta o processor. Server mode (futuro):\r\n * mesma assinatura, mas aciona refetch.\r\n */\r\nexport function useDataTableSearch({\r\n search: controlledSearch,\r\n onSearchChange,\r\n debounceMs = DEFAULT_DEBOUNCE,\r\n initialSearch,\r\n}: UseDataTableSearchParams = {}): UseDataTableSearchResult {\r\n const [uncontrolled, setUncontrolled] = useState<string>(initialSearch ?? \"\");\r\n const isControlled = controlledSearch !== undefined;\r\n const inputValue = isControlled ? controlledSearch : uncontrolled;\r\n\r\n // Quando hidrata do localStorage, debouncedValue já inicia no valor final\r\n // pra processor aplicar filtro no primeiro render (sem aguardar debounce).\r\n const [debouncedValue, setDebouncedValue] = useState<string>(inputValue);\r\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n\r\n // Quando inputValue muda, agenda update do debounced\r\n useEffect(() => {\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n timeoutRef.current = setTimeout(() => {\r\n setDebouncedValue(inputValue);\r\n }, debounceMs);\r\n return () => {\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n };\r\n }, [inputValue, debounceMs]);\r\n\r\n const setInputValue = useCallback(\r\n (value: string) => {\r\n if (!isControlled) setUncontrolled(value);\r\n onSearchChange?.(value);\r\n },\r\n [isControlled, onSearchChange],\r\n );\r\n\r\n const flush = useCallback(() => {\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n setDebouncedValue(inputValue);\r\n }, [inputValue]);\r\n\r\n return { inputValue, debouncedValue, setInputValue, flush };\r\n}\r\n","import { useCallback, useState } from \"react\";\nimport type { FilterModel } from \"../data-table.types\";\n\nexport type UseDataTableFiltersParams = {\n filterModel?: FilterModel;\n onFilterModelChange?: (model: FilterModel) => void;\n initialFilterModel?: FilterModel;\n};\n\nexport type UseDataTableFiltersResult = {\n filterModel: FilterModel;\n setFilterModel: (model: FilterModel) => void;\n clearFilters: () => void;\n};\n\nconst EMPTY_MODEL: FilterModel = { items: [], logicOperator: \"AND\" };\n\nexport function useDataTableFilters({\n filterModel: controlled,\n onFilterModelChange,\n initialFilterModel,\n}: UseDataTableFiltersParams = {}): UseDataTableFiltersResult {\n const [uncontrolled, setUncontrolled] = useState<FilterModel>(\n initialFilterModel ?? EMPTY_MODEL,\n );\n const isControlled = controlled !== undefined;\n const filterModel = isControlled ? controlled : uncontrolled;\n\n const setFilterModel = useCallback(\n (model: FilterModel) => {\n if (!isControlled) setUncontrolled(model);\n onFilterModelChange?.(model);\n },\n [isControlled, onFilterModelChange],\n );\n\n const clearFilters = useCallback(() => {\n setFilterModel(EMPTY_MODEL);\n }, [setFilterModel]);\n\n return { filterModel, setFilterModel, clearFilters };\n}\n","import { useMemo } from \"react\";\nimport type {\n DataTableColumnDef,\n FilterItem,\n FilterModel,\n PaginationModel,\n SortModel,\n} from \"../data-table.types\";\nimport { columnTypeRegistry } from \"../column-types\";\nimport {\n getFieldValue,\n applyValueGetter,\n applyFormatter,\n} from \"../utils/resolve-value\";\n\nexport type UseDataTableProcessorParams<T> = {\n rows: T[];\n columns: DataTableColumnDef<T>[];\n filterModel: FilterModel;\n search: string;\n searchField?: string; // 'all' (default) ou field específico\n /** Multi-sort: array de criterios (primeiro = prioridade maior). */\n sortModel: SortModel[];\n paginationModel: PaginationModel;\n /** Quando false, skip do slice de paginação — `rowsToRender` retorna todas as\n * rows filtradas/buscadas/ordenadas. Use quando paginationConfig.enabled=false\n * ou quando virtualize=true (virtualizer cuida do \"render só visível\"). Default true. */\n paginate?: boolean;\n};\n\nexport type UseDataTableProcessorResult<T> = {\n /** Rows visíveis depois de filter+search+sort+paginate. */\n rowsToRender: T[];\n /** Rows depois de filter+search+sort (sem paginate) — pra \"togglePage\" considerar página atual completa. */\n rowsAllPagesProcessed: T[];\n /** Total após filter+search (sem paginate) — pra footer mostrar \"1-10 de N\". */\n totalAfterFilter: number;\n};\n\n// Helpers de resolução consolidados em utils/resolve-value.ts.\n\n/* ── Filter ──────────────────────────────────────────────────────── */\n\n/**\n * Match generico — delega pro ColumnTypeRegistry quando coluna tem filterType,\n * senao usa fallback string-based.\n */\nfunction matchesFilter<T>(value: any, item: FilterItem, col: DataTableColumnDef<T> | undefined): boolean {\n const { operator } = item;\n const target = item.value;\n\n // Operadores neutros (sem valor)\n if (operator === \"isEmpty\") return value == null || value === \"\";\n if (operator === \"isNotEmpty\") return value != null && value !== \"\";\n\n // Delega pro registry quando coluna tem tipo\n if (col?.filterType) {\n const def = columnTypeRegistry.get(col.filterType);\n const result = def.matchesFilter(value, target as any, operator);\n if (result !== null) return result;\n }\n\n // Fallback string-based\n const str = value == null ? \"\" : String(value).toLowerCase();\n const targetStr = target == null ? \"\" : String(target).toLowerCase();\n switch (operator) {\n case \"contains\": return str.includes(targetStr);\n case \"equals\": return str === targetStr;\n case \"neq\": return str !== targetStr;\n case \"startsWith\": return str.startsWith(targetStr);\n case \"endsWith\": return str.endsWith(targetStr);\n case \"isAnyOf\": return Array.isArray(target) && (target as any[]).some((t) => String(t).toLowerCase() === str);\n case \"isNoneOf\": return !Array.isArray(target) || !(target as any[]).some((t) => String(t).toLowerCase() === str);\n case \"gt\": return Number(value) > Number(target);\n case \"lt\": return Number(value) < Number(target);\n case \"gte\": return Number(value) >= Number(target);\n case \"lte\": return Number(value) <= Number(target);\n default: return true;\n }\n}\n\n/**\n * Agrupa filtros por (field + operator) — items do mesmo grupo combinam por OR\n * (ex: status=A + status=B vira \"status ∈ {A,B}\"). Grupos diferentes combinam\n * por AND (ex: status ∈ {...} AND city = X).\n *\n * Pra operadores agregados (isAnyOf, isNoneOf) com array, o grupo eh trivial.\n * Pra operadores escalares (equals, contains), reagrupa items repetidos.\n */\n/** Item está \"ativo\" (deve filtrar) quando tem valor real OU operator nao\n * precisa de valor (isEmpty/isNotEmpty). Filtros com value vazio/null/array\n * vazio são ignorados — usuario abriu modal e adicionou linha mas ainda nao\n * preencheu, não deve impactar a tabela. */\nfunction isFilterItemActive(item: FilterItem): boolean {\n if (item.operator === \"isEmpty\" || item.operator === \"isNotEmpty\") return true;\n const v = item.value;\n if (v == null) return false;\n if (typeof v === \"string\") return v.length > 0;\n if (Array.isArray(v)) {\n return v.some((x) => x != null && (typeof x === \"string\" ? x.length > 0 : true));\n }\n return true;\n}\n\nfunction applyFilters<T>(rows: T[], filterModel: FilterModel, columns: DataTableColumnDef<T>[]): T[] {\n // Pula items \"em construção\" (sem valor preenchido) — eles entram no estado\n // quando user clica \"+ Adicionar\" no modal mas não devem afetar resultado.\n const activeItems = filterModel.items.filter(isFilterItemActive);\n if (activeItems.length === 0) return rows;\n const colsByField = new Map(columns.map((c) => [String(c.field), c]));\n\n // Agrupa itens por (field|operator)\n const groups = new Map<string, FilterItem[]>();\n for (const item of activeItems) {\n const key = `${item.field}|${item.operator}`;\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(item);\n }\n\n return rows.filter((row) => {\n // AND entre grupos\n for (const items of groups.values()) {\n const col = colsByField.get(items[0].field);\n const value = col ? applyValueGetter(row, col) : getFieldValue(row, items[0].field);\n // OR dentro do grupo: row passa se QUALQUER item do grupo bate\n const passes = items.some((it) => matchesFilter(value, it, col));\n if (!passes) return false;\n }\n return true;\n });\n}\n\n/* ── Search ──────────────────────────────────────────────────────── */\n\nfunction applySearch<T>(rows: T[], search: string, columns: DataTableColumnDef<T>[], searchField: string): T[] {\n if (!search.trim()) return rows;\n const needle = search.trim().toLowerCase();\n const searchableCols =\n searchField === \"all\" || !searchField\n ? columns.filter((c) => c.type !== \"actions\")\n : columns.filter((c) => String(c.field) === searchField);\n\n return rows.filter((row) =>\n searchableCols.some((col) => applyFormatter(row, col).toLowerCase().includes(needle)),\n );\n}\n\n/* ── Sort ────────────────────────────────────────────────────────── */\n\n/** Compara 2 rows num criterio especifico. */\nfunction compareByField<T>(\n a: T,\n b: T,\n field: string,\n direction: \"asc\" | \"desc\",\n columns: DataTableColumnDef<T>[],\n): number {\n const col = columns.find((c) => String(c.field) === field);\n if (!col) return 0;\n const sign = direction === \"asc\" ? 1 : -1;\n const va = applyValueGetter(a, col);\n const vb = applyValueGetter(b, col);\n if (va == null && vb == null) return 0;\n if (va == null) return 1 * sign;\n if (vb == null) return -1 * sign;\n if (typeof va === \"number\" && typeof vb === \"number\") return (va - vb) * sign;\n return String(va).localeCompare(String(vb)) * sign;\n}\n\n/** Multi-sort: aplica criterios em cascata — quebra de empate via proximo criterio. */\nfunction applySort<T>(rows: T[], sortModel: SortModel[], columns: DataTableColumnDef<T>[]): T[] {\n if (!sortModel || sortModel.length === 0) return rows;\n return [...rows].sort((a, b) => {\n for (const s of sortModel) {\n const cmp = compareByField(a, b, s.field, s.direction, columns);\n if (cmp !== 0) return cmp;\n }\n return 0;\n });\n}\n\n/* ── Pipeline cascateado ─────────────────────────────────────────── */\n\nexport function useDataTableProcessor<T>({\n rows,\n columns,\n filterModel,\n search,\n searchField = \"all\",\n sortModel,\n paginationModel,\n paginate = true,\n}: UseDataTableProcessorParams<T>): UseDataTableProcessorResult<T> {\n // 1. Filter\n const filtered = useMemo(\n () => applyFilters(rows, filterModel, columns),\n [rows, filterModel, columns],\n );\n\n // 2. Search\n const searched = useMemo(\n () => applySearch(filtered, search, columns, searchField),\n [filtered, search, columns, searchField],\n );\n\n // 3. Sort\n const sorted = useMemo(\n () => applySort(searched, sortModel, columns),\n [searched, sortModel, columns],\n );\n\n // 4. Paginate (skip quando paginate=false → retorna todas as rows filtradas)\n const paginated = useMemo(() => {\n if (!paginate) return sorted;\n const { page, pageSize } = paginationModel;\n const start = (page - 1) * pageSize;\n return sorted.slice(start, start + pageSize);\n }, [sorted, paginationModel, paginate]);\n\n return {\n rowsToRender: paginated,\n rowsAllPagesProcessed: sorted,\n totalAfterFilter: sorted.length,\n };\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\r\nimport type {\r\n GridFetchParams,\r\n GridFetchResult,\r\n PaginationModel,\r\n SortModel,\r\n FilterModel,\r\n FilterItem,\r\n} from \"../data-table.types\";\r\nimport { filterValueIsEmpty } from \"../utils/filter-ops\";\r\n\r\nexport type UseDataTableQueryParams<T> = {\r\n fetchData: (params: GridFetchParams) => Promise<GridFetchResult<T>>;\r\n filterModel: FilterModel;\r\n search: string;\r\n searchField?: string;\r\n sortModel: SortModel[];\r\n paginationModel: PaginationModel;\r\n /** Loading externo (forçado pelo consumer via prop). */\r\n externalLoading?: boolean;\r\n /** Debounce (ms) das mudanças de FILTRO. Default 350. Pagination/sort/search\r\n * não passam por aqui (search já vem debounced do useDataTableSearch). */\r\n filterDebounceMs?: number;\r\n};\r\n\r\nexport type UseDataTableQueryResult<T> = {\r\n /** Linhas retornadas pelo servidor pra página atual. */\r\n rowsToRender: T[];\r\n /** Total global do servidor (pra footer \"1-10 de N\"). */\r\n totalAfterFilter: number;\r\n /** True enquanto a request está em andamento. */\r\n isLoading: boolean;\r\n /** Última error string (ou null). */\r\n error: string | null;\r\n /** Dispara refetch imediato (usado por DataTableRef.refresh). */\r\n refresh: () => void;\r\n};\r\n\r\n/** Operadores que dispensam valor — a condição já está completa sem ele. */\r\nconst NULLARY_OPERATORS = new Set([\"isEmpty\", \"isNotEmpty\"]);\r\n\r\n/**\r\n * Um FilterItem está ATIVO (vale buscar) quando tem o que comparar: operadores\r\n * nulários (isEmpty/isNotEmpty) sempre; os demais só com valor real. Espelha o\r\n * gate de payload (ui/lib/datatable.ts `isActiveFilterItem`) e o guard do motor\r\n * da API — fonte única de \"filtro incompleto não dispara nada\".\r\n */\r\nfunction isActiveFilterItem(item: FilterItem): boolean {\r\n if (NULLARY_OPERATORS.has(item.operator)) return true;\r\n return !filterValueIsEmpty(item.value);\r\n}\r\n\r\nconst DEFAULT_FILTER_DEBOUNCE = 350;\r\n\r\n/**\r\n * Server mode fetcher. Chama `fetchData(params)` quando filter/sort/pagination/search mudam.\r\n *\r\n * - Em-vôo: `isLoading=true`. Resultado anterior continua visível.\r\n * - Race condition guard: requests fora de ordem são descartadas via `requestIdRef`.\r\n * - Refresh imperativo: bump em `refreshKey` força refetch sem mudar params.\r\n *\r\n * \"Fino\" (evita request boba):\r\n * - Só os filtros ATIVOS contam — escolher campo/operador (valor ainda vazio) NÃO\r\n * muda o conjunto, então não refaz fetch nem manda filtro incompleto ao backend.\r\n * - Mudança de filtro é DEBOUNCED (digitar o valor = 1 request, não 1 por tecla).\r\n * Pagination/sort/search continuam imediatos (search já vem debounced).\r\n */\r\nexport function useDataTableQuery<T>({\r\n fetchData,\r\n filterModel,\r\n search,\r\n searchField,\r\n sortModel,\r\n paginationModel,\r\n externalLoading,\r\n filterDebounceMs = DEFAULT_FILTER_DEBOUNCE,\r\n}: UseDataTableQueryParams<T>): UseDataTableQueryResult<T> {\r\n const [data, setData] = useState<T[]>([]);\r\n const [total, setTotal] = useState(0);\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [refreshKey, setRefreshKey] = useState(0);\r\n\r\n // Guard contra race condition — só aplica o resultado se for da request mais recente\r\n const requestIdRef = useRef(0);\r\n\r\n const refresh = useCallback(() => {\r\n setRefreshKey((k) => k + 1);\r\n }, []);\r\n\r\n // Conjunto de filtros ATIVOS — o que de fato vai ao servidor. Itens incompletos\r\n // (campo/operador escolhidos, valor vazio) ficam de fora.\r\n const activeFilterModel = useMemo<FilterModel>(\r\n () => ({\r\n ...filterModel,\r\n items: filterModel.items.filter(isActiveFilterItem),\r\n }),\r\n [filterModel],\r\n );\r\n\r\n // Assinatura estável do conjunto ATIVO — é o gatilho de refetch (debounced).\r\n // Como ignora itens inativos, escolher campo/operador não muda a chave.\r\n const activeFilterKey = useMemo(\r\n () => JSON.stringify(activeFilterModel),\r\n [activeFilterModel],\r\n );\r\n\r\n // Debounce só do filtro: digitar o valor não dispara 1 request por tecla.\r\n const [debouncedFilterKey, setDebouncedFilterKey] = useState(activeFilterKey);\r\n useEffect(() => {\r\n const t = setTimeout(\r\n () => setDebouncedFilterKey(activeFilterKey),\r\n filterDebounceMs,\r\n );\r\n return () => clearTimeout(t);\r\n }, [activeFilterKey, filterDebounceMs]);\r\n\r\n // Ref pro modelo ativo mais recente — o efeito lê no momento do fetch (evita\r\n // stale e dispensa o objeto nas deps; quem dispara o filtro é a key debounced).\r\n const activeFilterRef = useRef(activeFilterModel);\r\n activeFilterRef.current = activeFilterModel;\r\n\r\n useEffect(() => {\r\n const currentId = ++requestIdRef.current;\r\n setIsLoading(true);\r\n setError(null);\r\n\r\n fetchData({\r\n pagination: paginationModel,\r\n sort: sortModel,\r\n filters: activeFilterRef.current,\r\n search,\r\n searchField,\r\n })\r\n .then((result) => {\r\n // Ignora se outra request mais recente foi disparada\r\n if (currentId !== requestIdRef.current) return;\r\n setData(result.data);\r\n setTotal(result.total);\r\n setIsLoading(false);\r\n })\r\n .catch((err: unknown) => {\r\n if (currentId !== requestIdRef.current) return;\r\n setError(err instanceof Error ? err.message : String(err));\r\n setIsLoading(false);\r\n });\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [\r\n fetchData,\r\n debouncedFilterKey,\r\n search,\r\n searchField,\r\n sortModel,\r\n paginationModel,\r\n refreshKey,\r\n ]);\r\n\r\n return {\r\n rowsToRender: data,\r\n totalAfterFilter: total,\r\n isLoading: isLoading || !!externalLoading,\r\n error,\r\n refresh,\r\n };\r\n}\r\n","import { useCallback } from \"react\";\r\nimport type { DataTableColumnDef, GridRowId } from \"../data-table.types\";\r\nimport { applyFormatter } from \"../utils/resolve-value\";\r\n\r\nexport type ExportScope = \"all\" | \"filtered\" | \"selected\";\r\n\r\nexport type UseDataTableExportParams<T> = {\r\n columns: DataTableColumnDef<T>[];\r\n /** Rows visiveis na pagina atual (server) ou apos filter+sort+paginate (client). */\r\n rowsCurrentPage: T[];\r\n /** Rows apos filter+search+sort, sem paginate. Client mode tem; server tem apenas pagina atual. */\r\n rowsAfterFilter: T[];\r\n /** Rows brutas (todas, sem filter). Server mode = vazio. */\r\n rowsAll: T[];\r\n /** IDs selecionados (resolvidos do selection state). */\r\n selectedIds: GridRowId[];\r\n /** Funcao pra extrair id de uma row. */\r\n getRowId: (row: T) => GridRowId;\r\n /** Nome do arquivo (sem extensao). Default \"export\". */\r\n filename?: string;\r\n};\r\n\r\nexport type UseDataTableExportResult = {\r\n exportCsv: (scope: ExportScope) => void;\r\n};\r\n\r\n/**\r\n * Gera CSV no client a partir das rows do escopo escolhido.\r\n * Aplica `valueFormatter` da coluna quando presente, senao usa o valor cru convertido pra string.\r\n * Trigger de download via Blob URL + <a download>.\r\n */\r\nexport function useDataTableExport<T>({\r\n columns,\r\n rowsCurrentPage,\r\n rowsAfterFilter,\r\n rowsAll,\r\n selectedIds,\r\n getRowId,\r\n filename = \"export\",\r\n}: UseDataTableExportParams<T>): UseDataTableExportResult {\r\n const exportCsv = useCallback(\r\n (scope: ExportScope) => {\r\n // Seleciona rows do escopo\r\n let rows: T[];\r\n if (scope === \"all\") {\r\n // Client tem rowsAll; server so temos a pagina atual\r\n rows = rowsAll.length > 0 ? rowsAll : rowsCurrentPage;\r\n } else if (scope === \"filtered\") {\r\n rows = rowsAfterFilter;\r\n } else {\r\n // selected: filtra rowsAfterFilter por IDs selecionados\r\n const idSet = new Set(selectedIds);\r\n rows = rowsAfterFilter.filter((r) => idSet.has(getRowId(r)));\r\n }\r\n\r\n // Colunas exportaveis (exclui type=actions)\r\n const exportCols = columns.filter((c) => c.type !== \"actions\");\r\n\r\n const csv = generateCsv(rows, exportCols);\r\n downloadCsv(csv, `${filename}-${scope}.csv`);\r\n },\r\n [columns, rowsCurrentPage, rowsAfterFilter, rowsAll, selectedIds, getRowId, filename],\r\n );\r\n\r\n return { exportCsv };\r\n}\r\n\r\n/* -- CSV utils ----------------------------------------------------------- */\r\n\r\nfunction escapeCsvCell(value: string): string {\r\n // Wrap em aspas se conter virgula, aspas ou nova linha\r\n if (/[\",\\n\\r]/.test(value)) {\r\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\r\n }\r\n return value;\r\n}\r\n\r\nfunction generateCsv<T>(rows: T[], columns: DataTableColumnDef<T>[]): string {\r\n const header = columns.map((c) => escapeCsvCell(c.headerName)).join(\",\");\r\n const lines = rows.map((row) =>\r\n columns.map((col) => escapeCsvCell(applyFormatter(row, col))).join(\",\"),\r\n );\r\n return [header, ...lines].join(\"\\n\");\r\n}\r\n\r\nfunction downloadCsv(csv: string, filename: string): void {\r\n // BOM pra Excel reconhecer UTF-8\r\n const blob = new Blob([\"\" + csv], { type: \"text/csv;charset=utf-8\" });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement(\"a\");\r\n a.href = url;\r\n a.download = filename;\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n URL.revokeObjectURL(url);\r\n}\r\n","import type {\r\n DataTableViewMode,\r\n FilterModel,\r\n GridRowId,\r\n SortModel,\r\n} from \"../data-table.types\";\r\nimport type { ColumnPinned, TableDensity } from \"../../Table\";\r\n\r\nconst STORAGE_PREFIX = \"igreen-datatable:\";\r\n// v4: filterModel/search/currentPage persistem como parte do workspace \"Default\".\r\n// Quando uma view custom está ativa, esses campos refletem o snapshot Default\r\n// (não o state da view), pra preservar o workspace pessoal entre sessões.\r\n// v5: `columnWidths` passa a guardar SÓ resize manual (widthOverrides), não as\r\n// larguras efetivas (que incluíam autoFit). Persistir efetivas congelava o\r\n// layout e matava o autoFit no reload. Bump invalida o persist antigo (com\r\n// widths congelados) → autoFit recalcula limpo na próxima carga.\r\nconst SCHEMA_VERSION = 5;\r\n\r\n/**\r\n * Subset persistido — workspace \"Default\" completo.\r\n *\r\n * Quando o user tem uma view custom ativa, esses campos representam o snapshot\r\n * do workspace Default (congelado antes da view ser aplicada). Quando o user\r\n * volta para Default via `applyDefault`, esse snapshot é restaurado por inteiro.\r\n */\r\nexport type PersistedDataTableState = {\r\n version: number;\r\n density?: TableDensity;\r\n /** Multi-sort: array. Migrado de single object pra array em v2. */\r\n sortModel?: SortModel[] | null;\r\n pageSize?: number;\r\n /** Página atual (1-indexed). Persistido em v4 como parte do workspace Default. */\r\n currentPage?: number;\r\n columnWidths?: Record<string, number>;\r\n pinnedColumns?: Record<string, ColumnPinned>;\r\n hiddenColumns?: string[];\r\n columnOrder?: string[];\r\n /** Filtros aplicados. Persistido em v4 como parte do workspace Default. */\r\n filterModel?: FilterModel;\r\n /** Texto de busca (debounced). Persistido em v4 como parte do workspace Default. */\r\n search?: string;\r\n /** Modo de visualização (table OR kanban). Persistido em v3. */\r\n viewMode?: DataTableViewMode;\r\n /** Field de agrupamento (Fase F.4). Persistido em v3. */\r\n groupBy?: string;\r\n /** Rows expandidas (Fase F.4b). Persistido em v3. */\r\n expandedRowIds?: GridRowId[];\r\n /** Ultima view ativa (preset id, saved view id, ou null pra Default). */\r\n lastActiveViewId?: string | null;\r\n};\r\n\r\nexport type LoadedPersistedState = Omit<PersistedDataTableState, \"version\">;\r\n\r\nfunction storageKey(persistId: string): string {\r\n return `${STORAGE_PREFIX}${persistId}`;\r\n}\r\n\r\n/** Le do localStorage. Retorna null se vazio, schema antigo, ou parse falhou. */\r\nexport function loadPersistedState(\r\n persistId: string | undefined,\r\n): LoadedPersistedState | null {\r\n if (!persistId || typeof window === \"undefined\") return null;\r\n try {\r\n const raw = window.localStorage.getItem(storageKey(persistId));\r\n if (!raw) return null;\r\n const parsed = JSON.parse(raw) as PersistedDataTableState;\r\n if (parsed.version !== SCHEMA_VERSION) return null;\r\n const { version: _v, ...state } = parsed;\r\n return state;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/** Salva no localStorage. Inclui version pro schema. */\r\nexport function savePersistedState(\r\n persistId: string | undefined,\r\n state: LoadedPersistedState,\r\n): void {\r\n if (!persistId || typeof window === \"undefined\") return;\r\n try {\r\n const payload: PersistedDataTableState = { version: SCHEMA_VERSION, ...state };\r\n window.localStorage.setItem(storageKey(persistId), JSON.stringify(payload));\r\n } catch {\r\n // localStorage cheio / disabled / quota — silencioso, persist é best-effort.\r\n }\r\n}\r\n\r\n/** Remove entry do localStorage (usado pelo reset). */\r\nexport function clearPersistedState(persistId: string | undefined): void {\r\n if (!persistId || typeof window === \"undefined\") return;\r\n try {\r\n window.localStorage.removeItem(storageKey(persistId));\r\n } catch {\r\n // ignore\r\n }\r\n}\r\n","import { useEffect, useRef } from \"react\";\nimport { savePersistedState, type LoadedPersistedState } from \"./state-persistence-utils\";\n\nexport type UseDataTableStatePersistenceParams = {\n persistId: string | undefined;\n /** Snapshot completo a ser salvo. O hook detecta mudanças via deep-compare leve. */\n state: LoadedPersistedState;\n /** Delay antes de salvar (debounce). Default 400ms. */\n debounceMs?: number;\n};\n\n/**\n * Persiste estado da tabela no localStorage com debounce.\n * Hidratacao acontece no controller (loadPersistedState passado como initial state pros hooks).\n * Este hook so cuida do save.\n */\nexport function useDataTableStatePersistence({\n persistId,\n state,\n debounceMs = 400,\n}: UseDataTableStatePersistenceParams): void {\n const isMountedRef = useRef(false);\n\n useEffect(() => {\n // Evita salvar no primeiro render (re-salvar o que acabou de hidratar)\n if (!isMountedRef.current) {\n isMountedRef.current = true;\n return;\n }\n if (!persistId) return;\n\n const timer = setTimeout(() => {\n savePersistedState(persistId, state);\n }, debounceMs);\n\n return () => clearTimeout(timer);\n }, [persistId, state, debounceMs]);\n}\n","import type { SavedView, SavedViewsService } from \"./saved-views.types\";\n\nconst STORAGE_PREFIX = \"igreen-datatable-views:\";\n\nfunction storageKey(persistId: string): string {\n return `${STORAGE_PREFIX}${persistId}`;\n}\n\nfunction readAll(persistId: string): SavedView[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(storageKey(persistId));\n if (!raw) return [];\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nfunction writeAll(persistId: string, views: SavedView[]): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(storageKey(persistId), JSON.stringify(views));\n } catch {\n // localStorage cheio / disabled — silencioso\n }\n}\n\n/**\n * Service mock — persiste em localStorage via key separada de state-persistence.\n * Para producao: substituir por adapter que chama API. Mesma interface, comportamento assincrono.\n */\nexport const savedViewsMockService: SavedViewsService = {\n list: async (persistId) => {\n return readAll(persistId);\n },\n save: async (persistId, view) => {\n const all = readAll(persistId);\n const idx = all.findIndex((v) => v.id === view.id);\n if (idx >= 0) {\n all[idx] = view;\n } else {\n all.push(view);\n }\n writeAll(persistId, all);\n return view;\n },\n delete: async (persistId, id) => {\n const all = readAll(persistId);\n writeAll(persistId, all.filter((v) => v.id !== id));\n },\n};\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { SavedView, SavedViewsService } from \"../services/saved-views.types\";\nimport { savedViewsMockService } from \"../services/saved-views-mock-service\";\n\nexport type UseDataTableSavedViewsParams = {\n persistId: string | undefined;\n service?: SavedViewsService;\n};\n\nexport type SaveViewOptions = {\n /** Default false (privada). Quando true, view eh marcada como publica. */\n isPublic?: boolean;\n};\n\nexport type UseDataTableSavedViewsResult = {\n views: SavedView[];\n isLoading: boolean;\n currentViewId: string | null;\n /** Salva o snapshot atual com o nome dado. Gera id novo. */\n saveView: (\n name: string,\n snapshot: SavedView[\"state\"],\n opts?: SaveViewOptions,\n ) => Promise<SavedView | null>;\n /** Remove view do servico. */\n deleteView: (id: string) => Promise<void>;\n /** Marca uma view como atualmente aplicada (logica de aplicacao fica fora do hook). */\n setCurrentViewId: (id: string | null) => void;\n};\n\nfunction generateId(): string {\n return `view-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/**\n * Gerencia views salvas via service (default: localStorage mock).\n * O hook lista no mount, expoe save/delete, e mantem qual view esta \"ativa\" (apenas marker).\n * Aplicacao do estado de uma view eh feita pelo controller (chama setters dos hooks SRP).\n */\nexport function useDataTableSavedViews({\n persistId,\n service = savedViewsMockService,\n}: UseDataTableSavedViewsParams): UseDataTableSavedViewsResult {\n const [views, setViews] = useState<SavedView[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [currentViewId, setCurrentViewId] = useState<string | null>(null);\n const warnedRef = useRef(false);\n\n // Warning em prod quando service nao foi customizado (spec §risks)\n useEffect(() => {\n if (warnedRef.current || !persistId) return;\n const isProd = import.meta.env?.MODE === \"production\";\n const isMock = service === savedViewsMockService;\n if (isProd && isMock) {\n // eslint-disable-next-line no-console\n console.warn(\n \"[DataTable] Saved Views mock service em production. Substitua via prop `savedViewsService` por adapter de backend persistente.\",\n );\n warnedRef.current = true;\n }\n }, [persistId, service]);\n\n // Carrega lista no mount (quando persistId esta presente)\n useEffect(() => {\n if (!persistId) return;\n let cancelled = false;\n setIsLoading(true);\n service.list(persistId)\n .then((list) => {\n if (cancelled) return;\n setViews(list);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setIsLoading(false);\n });\n return () => { cancelled = true; };\n }, [persistId, service]);\n\n const saveView = useCallback(\n async (\n name: string,\n snapshot: SavedView[\"state\"],\n opts?: SaveViewOptions,\n ): Promise<SavedView | null> => {\n if (!persistId) return null;\n const view: SavedView = {\n id: generateId(),\n name: name.trim(),\n isPublic: opts?.isPublic ?? false,\n state: snapshot,\n createdAt: new Date().toISOString(),\n };\n const saved = await service.save(persistId, view);\n setViews((prev) => [...prev, saved]);\n setCurrentViewId(saved.id);\n return saved;\n },\n [persistId, service],\n );\n\n const deleteView = useCallback(\n async (id: string): Promise<void> => {\n if (!persistId) return;\n await service.delete(persistId, id);\n setViews((prev) => prev.filter((v) => v.id !== id));\n setCurrentViewId((curr) => (curr === id ? null : curr));\n },\n [persistId, service],\n );\n\n return { views, isLoading, currentViewId, saveView, deleteView, setCurrentViewId };\n}\n","import type { GridRowId } from \"../data-table.types\";\n\n/** Marker symbol pra distinguir TreeRow (data row enriquecida com metadados de\n * hierarquia) de uma data row T crua. Symbol-as-discriminator no padrão de\n * group-rows.ts / expand-rows.ts — evita colisão com props do T. */\nexport const TREE_ROW_TYPE = Symbol(\"dt-tree-row\");\n\n/**\n * Wrapper de uma data row no modo tree-data. Carrega a row original (`row`)\n * intacta — pra render de cells, edit, selection etc — + metadados de\n * hierarquia computados a partir do `getTreeDataPath`.\n *\n * Pattern: NÃO substitui a row; envelopa. O render branch desembrulha via\n * `isTreeRow` e usa `node.row` como a row real. Assim filter/sort/selection/\n * edit continuam operando em `T` sem saber de árvore.\n */\nexport type DataTableTreeRow<T = unknown> = {\n __type: typeof TREE_ROW_TYPE;\n /** Row original — usada em todo render/edit/selection. */\n row: T;\n /** Id estável da row (== getRowId(row)). */\n id: GridRowId;\n /** Profundidade na árvore (0 = raiz). Indentação = level * unidade. */\n level: number;\n /** Tem ao menos 1 descendente direto? Define se renderiza chevron. */\n hasChildren: boolean;\n /** Está expandido? (só relevante quando hasChildren). */\n isExpanded: boolean;\n /** Quantidade total de descendentes (todos os níveis abaixo). */\n descendantCount: number;\n /** Quantidade de filhos diretos. */\n childCount: number;\n /** Caminho completo até esta row (output do getTreeDataPath). */\n path: Array<string | number>;\n};\n\n/** Type guard pra TreeRow. União ampla pra coexistir com outras transformações. */\nexport function isTreeRow<T>(item: unknown): item is DataTableTreeRow<T> {\n return (\n item != null &&\n typeof item === \"object\" &&\n \"__type\" in item &&\n (item as { __type: symbol }).__type === TREE_ROW_TYPE\n );\n}\n\n/** Nó interno da árvore durante a construção. */\ntype TreeBuildNode<T> = {\n /** Row original — undefined pra nós \"filler\" (path intermediário sem row própria). */\n row: T | undefined;\n id: GridRowId | undefined;\n path: Array<string | number>;\n children: TreeBuildNode<T>[];\n /** Index de ordem de chegada — pra estabilidade de ordenação default. */\n order: number;\n};\n\n/**\n * Reshape de um array FLAT de rows em uma sequência ordenada de TreeRows,\n * respeitando a hierarquia derivada de `getTreeDataPath` e o estado de expansão.\n *\n * ## Como funciona\n * 1. Cada row produz um path (ex: `[\"A\"]`, `[\"A\",\"B\"]`, `[\"A\",\"B\",\"C\"]`).\n * 2. Construímos uma árvore por prefixo de path (trie). Rows cujo path tem\n * comprimento N viram nós em profundidade N-1.\n * 3. Se um path intermediário não tiver row própria (ex: existe `[\"A\",\"B\"]`\n * mas não `[\"A\"]`), criamos um nó \"filler\" sintético sem `row` — necessário\n * pra manter a indentação correta. Filler nodes NÃO entram no render (não\n * têm row pra pintar); seus filhos sobem um nível visualmente? Não — pra\n * simplicidade e previsibilidade, filler nodes SÃO renderizados como uma\n * TreeRow \"stub\" carregando a primeira row-filho como representante NÃO —\n * decisão: filler nodes são pulados no flatten mas seus filhos preservam o\n * nível real (mantém alinhamento com o path). Ver `flatten`.\n * 4. Flatten em pré-ordem (pai antes dos filhos). Filhos só entram se TODOS os\n * ancestrais estão expandidos.\n *\n * ## Expansão\n * `expandedIds` guarda os ids de nós EXPANDIDOS (semântica explícita, igual a\n * row-expansion). Quando `defaultExpanded=true`, um id AUSENTE de `expandedIds`\n * conta como expandido e um id PRESENTE conta como colapsado (toggle inverte o\n * default) — mesma convenção de group-rows. Quando `defaultExpanded=false`,\n * vice-versa.\n *\n * @param rows Rows já filtradas/buscadas/ordenadas (output do processor).\n * @param getTreeDataPath Deriva o caminho hierárquico de cada row.\n * @param getRowId Extrai id estável da row.\n * @param expandedIds Set de ids que DIFEREM do estado default de expansão.\n * @param defaultExpanded Estado de expansão default dos nós com filhos.\n */\nexport function buildTreeRows<T>(\n rows: T[],\n getTreeDataPath: (row: T) => Array<string | number>,\n getRowId: (row: T) => GridRowId,\n expandedIds: Set<GridRowId>,\n defaultExpanded: boolean,\n): Array<DataTableTreeRow<T>> {\n if (rows.length === 0) return [];\n\n // ── 1. Trie por path ────────────────────────────────────────────\n const rootChildren: TreeBuildNode<T>[] = [];\n // Map de pathKey → node pra reaproveitar nós intermediários.\n const nodeByPathKey = new Map<string, TreeBuildNode<T>>();\n let orderCounter = 0;\n\n const pathKey = (path: Array<string | number>) => path.join(\"\u0000\");\n\n const ensureNode = (path: Array<string | number>): TreeBuildNode<T> => {\n const key = pathKey(path);\n const existing = nodeByPathKey.get(key);\n if (existing) return existing;\n\n const node: TreeBuildNode<T> = {\n row: undefined,\n id: undefined,\n path,\n children: [],\n order: orderCounter++,\n };\n nodeByPathKey.set(key, node);\n\n if (path.length === 1) {\n rootChildren.push(node);\n } else {\n const parentPath = path.slice(0, -1);\n const parent = ensureNode(parentPath);\n parent.children.push(node);\n }\n return node;\n };\n\n for (const row of rows) {\n const path = getTreeDataPath(row);\n if (!path || path.length === 0) continue; // row sem path → ignorada da árvore\n const node = ensureNode(path);\n // Se 2 rows compartilham o mesmo path, a primeira vence (determinístico).\n if (node.row === undefined) {\n node.row = row;\n node.id = getRowId(row);\n }\n }\n\n // ── 2. descendantCount (pós-ordem) ──────────────────────────────\n const countDescendants = (node: TreeBuildNode<T>): number => {\n let total = 0;\n for (const child of node.children) {\n total += 1 + countDescendants(child);\n }\n return total;\n };\n\n // ── 3. Flatten pré-ordem, respeitando expansão ──────────────────\n const result: Array<DataTableTreeRow<T>> = [];\n\n const isNodeExpanded = (id: GridRowId | undefined): boolean => {\n if (id === undefined) return true; // filler nodes sempre \"abertos\"\n return expandedIds.has(id) ? !defaultExpanded : defaultExpanded;\n };\n\n const walk = (node: TreeBuildNode<T>, level: number) => {\n const hasChildren = node.children.length > 0;\n\n // Nó filler (sem row própria): não renderiza, mas seus filhos mantêm o\n // nível do path (level+1) pra alinhar à hierarquia real. Tratado como\n // sempre expandido.\n if (node.row === undefined || node.id === undefined) {\n for (const child of node.children) walk(child, level + 1);\n return;\n }\n\n const expanded = isNodeExpanded(node.id);\n const descendantCount = countDescendants(node);\n\n result.push({\n __type: TREE_ROW_TYPE,\n row: node.row,\n id: node.id,\n level,\n hasChildren,\n isExpanded: expanded,\n descendantCount,\n childCount: node.children.length,\n path: node.path,\n });\n\n if (hasChildren && expanded) {\n for (const child of node.children) walk(child, level + 1);\n }\n };\n\n for (const node of rootChildren) walk(node, 0);\n\n return result;\n}\n\n/**\n * Coleta todos os ids de nós que TÊM filhos (expansíveis) — usado por\n * expand-all / collapse-all pra montar o Set de toggles. Independe do estado\n * de expansão atual: retorna todo nó ramo da árvore.\n */\nexport function collectExpandableTreeIds<T>(\n rows: T[],\n getTreeDataPath: (row: T) => Array<string | number>,\n getRowId: (row: T) => GridRowId,\n): GridRowId[] {\n // Conta filhos por pathKey de pai.\n const childCountByParentKey = new Map<string, number>();\n const idByPathKey = new Map<string, GridRowId>();\n const pathKey = (path: Array<string | number>) => path.join(\"\u0000\");\n\n for (const row of rows) {\n const path = getTreeDataPath(row);\n if (!path || path.length === 0) continue;\n idByPathKey.set(pathKey(path), getRowId(row));\n if (path.length > 1) {\n const parentKey = pathKey(path.slice(0, -1));\n childCountByParentKey.set(parentKey, (childCountByParentKey.get(parentKey) ?? 0) + 1);\n }\n }\n\n const ids: GridRowId[] = [];\n for (const [key, count] of childCountByParentKey.entries()) {\n if (count > 0) {\n const id = idByPathKey.get(key);\n if (id !== undefined) ids.push(id);\n }\n }\n return ids;\n}\n","import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from \"react\";\r\nimport type { Ref } from \"react\";\r\nimport type {\r\n DataTableProps,\r\n DataTablePresetView,\r\n DataTableRef,\r\n DataTableState,\r\n DataTableViewMode,\r\n GridFetchParams,\r\n GridFetchResult,\r\n GridRowId,\r\n} from \"../data-table.types\";\r\nimport type { DataTableContextValue } from \"../context/data-table-context\";\r\nimport { useDataTableColumns } from \"./use-data-table-columns\";\r\nimport { useColumnAutoWidth } from \"./use-column-auto-width\";\r\nimport { SELECTION_COLUMN_WIDTH } from \"../../Table\";\r\nimport { useDataTableSort } from \"./use-data-table-sort\";\r\nimport { useDataTablePagination } from \"./use-data-table-pagination\";\r\nimport { useDataTableSelection } from \"./use-data-table-selection\";\r\nimport { useDataTableDensity } from \"./use-data-table-density\";\r\nimport { useDataTableSearch } from \"./use-data-table-search\";\r\nimport { useDataTableFilters } from \"./use-data-table-filters\";\r\nimport { useDataTableProcessor } from \"./use-data-table-processor\";\r\nimport { useDataTableQuery } from \"./use-data-table-query\";\r\nimport { useDataTableExport } from \"./use-data-table-export\";\r\nimport { useDataTableStatePersistence } from \"./use-data-table-state-persistence\";\r\nimport { loadPersistedState, clearPersistedState } from \"./state-persistence-utils\";\r\nimport { useDataTableSavedViews } from \"./use-data-table-saved-views\";\r\nimport type { SavedView, SavedViewsService } from \"../services/saved-views.types\";\r\nimport { promoteOperatorForColumn } from \"../utils/filter-ops\";\r\nimport { collectExpandableTreeIds } from \"../utils/tree-rows\";\r\n// Side-effect: registra os tipos default no ColumnTypeRegistry\r\nimport \"../column-types\";\r\n\r\n/** No-op fetch usado quando estamos em client mode — referência estável evita re-renders. */\r\nconst NOOP_FETCH = async (_params: GridFetchParams): Promise<GridFetchResult<never>> => ({ data: [], total: 0 });\r\n\r\nconst DEFAULT_GET_ROW_ID = (row: any): GridRowId => row.id;\r\n\r\n/**\r\n * Normaliza filterModel ao hidratar de presetView/savedView — promove operator\r\n * escalar (`equals`/`neq`) pra multi (`isAnyOf`/`isNoneOf`) quando a column\r\n * declarada tem `filterType: \"multiSelect\"`. Sem isso, presets declarados via\r\n * `presetView({ filters: [{ field, value }] })` ficam com operator default\r\n * \"equals\" e quebram o widget MultiSelectFieldDropdown (que sempre toggla com\r\n * array, gerando inconsistência entre operator e shape do value).\r\n */\r\nfunction normalizeFilterModelForColumns<T>(\r\n filterModel: import(\"../data-table.types\").FilterModel,\r\n columns: readonly import(\"../data-table.types\").DataTableColumnDef<T>[],\r\n): import(\"../data-table.types\").FilterModel {\r\n const colByField = new Map(columns.map((c) => [String(c.field), c]));\r\n let touched = false;\r\n const items = filterModel.items.map((item) => {\r\n const col = colByField.get(item.field);\r\n const operator = promoteOperatorForColumn(item.operator, col);\r\n if (operator === item.operator) return item;\r\n touched = true;\r\n return { ...item, operator };\r\n });\r\n return touched ? { ...filterModel, items } : filterModel;\r\n}\r\n\r\nexport function useDataTableController<T>(\r\n props: DataTableProps<T>,\r\n ref: Ref<DataTableRef>,\r\n) {\r\n const getRowId = props.getRowId ?? (DEFAULT_GET_ROW_ID as (row: T) => GridRowId);\r\n\r\n /* ── Hidrata estado persistido (localStorage) ─────────────────── */\r\n\r\n // Lazy: roda uma vez via useMemo. persistId estavel entre renders.\r\n const persistedInitial = useMemo(\r\n () => loadPersistedState(props.persistId),\r\n [props.persistId],\r\n );\r\n\r\n /* ── Hooks SRP ────────────────────────────────────────────────── */\r\n\r\n // Ref ao container que será observado pelo ResizeObserver do auto-fit.\r\n // Compartilhado entre `Table.scrollRef` (scroll y/x) e `useColumnAutoWidth`\r\n // (medição do contentRect.width). data-table.tsx consome via controller.\r\n const scrollContainerRef = useRef<HTMLDivElement | null>(null);\r\n\r\n // viewMode (estado interno read-only) elevado pra ANTES do autoFit — o hook\r\n // precisa dele como `recalcKey`: ao alternar Tabela↔Lista o corpo da tabela\r\n // (que carrega o `scrollRef`) desmonta e remonta sem trocar a ref, então o\r\n // ResizeObserver precisa ser re-instalado e o autoFit re-medido. O setter e os\r\n // callbacks completos ficam mais abaixo (precisam de `props.onViewModeChange`).\r\n const [internalViewMode, setInternalViewMode] = useState<DataTableViewMode>(\r\n // Hidrata do localStorage (v3+) com fallback pra prop `defaultViewMode`\r\n persistedInitial?.viewMode ?? props.defaultViewMode ?? \"table\",\r\n );\r\n const viewMode: DataTableViewMode = props.viewMode ?? internalViewMode;\r\n\r\n // AutoFit: calcula widths fluidas em 3 layers (type heuristic / canvas measure / flex distribution).\r\n // Default true — opt-out via `autoFit: false` em DataTableProps.\r\n const autoFitEnabled = props.autoFit !== false;\r\n // Selection column (checkbox) é injetada pelo DataTable e não está em props.columns,\r\n // mas ocupa 56px no container — desconta do auto-fit pra evitar overflow.\r\n const selectionReservedWidth = props.selectionConfig?.enabled\r\n ? SELECTION_COLUMN_WIDTH\r\n : 0;\r\n const { autoWidths } = useColumnAutoWidth(\r\n scrollContainerRef,\r\n props.columns,\r\n props.rows ?? [],\r\n {\r\n enabled: autoFitEnabled,\r\n reservedWidth: selectionReservedWidth,\r\n // Re-attach/re-medir quando o corpo da tabela remonta (toggle de view).\r\n // Só \"table\" carrega o scrollRef observado; usar viewMode garante que ao\r\n // voltar pra Tabela o observer reata no node novo e re-mede do zero.\r\n recalcKey: viewMode,\r\n },\r\n );\r\n\r\n const cols = useDataTableColumns({\r\n columns: props.columns,\r\n initialWidthOverrides: persistedInitial?.columnWidths,\r\n initialPinnedOverrides: persistedInitial?.pinnedColumns,\r\n initialHiddenColumns: persistedInitial?.hiddenColumns,\r\n initialColumnOrder: persistedInitial?.columnOrder,\r\n autoWidths,\r\n });\r\n\r\n const sort = useDataTableSort({\r\n sortModel: props.sortModel,\r\n onSortModelChange: props.onSortModelChange,\r\n initialSortModel: persistedInitial?.sortModel,\r\n });\r\n\r\n const filters = useDataTableFilters({\r\n filterModel: props.filterModel,\r\n onFilterModelChange: props.onFilterModelChange,\r\n // Hidrata filtros do workspace Default (v4+). Quando uma view custom estava\r\n // ativa no último mount, o effect de restore (linha ~410) aplica a view depois.\r\n //\r\n // Normaliza ANTES de hidratar — filterModels persistidos antes do fix #10\r\n // (preset hydration) podem ter operator=\"equals\" pra colunas multiSelect.\r\n // Sem normalizar aqui, o operator dropdown do popover ficava vazio (porque\r\n // \"equals\" não está em MultiSelectColumnType.operators).\r\n initialFilterModel: persistedInitial?.filterModel\r\n ? normalizeFilterModelForColumns(persistedInitial.filterModel, props.columns)\r\n : undefined,\r\n });\r\n\r\n const search = useDataTableSearch({\r\n search: props.search,\r\n onSearchChange: props.onSearchChange,\r\n // Hidrata texto de busca do workspace Default (v4+).\r\n initialSearch: persistedInitial?.search,\r\n });\r\n\r\n // Pagination com auto-reset quando filtros/search mudam\r\n const pagination = useDataTablePagination({\r\n paginationModel: props.paginationModel,\r\n onPaginationModelChange: props.onPaginationModelChange,\r\n initialPageSize:\r\n persistedInitial?.pageSize ?? props.paginationConfig?.initialPageSize,\r\n // Hidrata página atual do workspace Default (v4+).\r\n initialPage: persistedInitial?.currentPage,\r\n resetTriggers: [filters.filterModel.items.length, search.debouncedValue],\r\n });\r\n\r\n const density = useDataTableDensity({\r\n density: props.density,\r\n onDensityChange: props.onDensityChange,\r\n initialDensity: persistedInitial?.density,\r\n });\r\n\r\n /* ── viewMode + groupBy + expandedRowIds — controlled/uncontrolled hybrid\r\n *\r\n * Centralizados aqui (em vez de em `data-table.tsx`) pra que `applyView`\r\n * possa restaurá-los junto com filter/sort/density/layout. Padrão:\r\n * - Se prop controlled passada → usa prop (read-only); setter dispara callback\r\n * - Senão → usa state interno + chama callback se fornecido\r\n *\r\n * Saved views podem alternar esses 3 fields via `applyView` (sempre dispara\r\n * o callback). Builder `presetView()` pode declarar `viewMode/groupBy/\r\n * expandedRowIds` em presets read-only. */\r\n // (internalViewMode/viewMode declarados acima — antes do autoFit, que os usa\r\n // como recalcKey). Aqui só o setter + os demais states de view.\r\n const setViewMode = useCallback((mode: DataTableViewMode) => {\r\n if (props.viewMode === undefined) setInternalViewMode(mode);\r\n props.onViewModeChange?.(mode);\r\n }, [props.viewMode, props.onViewModeChange]);\r\n\r\n const [internalGroupBy, setInternalGroupBy] = useState<string | undefined>(\r\n persistedInitial?.groupBy ?? props.defaultGroupBy,\r\n );\r\n const groupBy: string | undefined = props.groupBy ?? internalGroupBy;\r\n const setGroupBy = useCallback((next: string | undefined) => {\r\n if (props.groupBy === undefined) setInternalGroupBy(next);\r\n props.onGroupByChange?.(next);\r\n }, [props.groupBy, props.onGroupByChange]);\r\n\r\n const [internalExpandedRowIds, setInternalExpandedRowIdsRaw] = useState<GridRowId[]>(\r\n () => persistedInitial?.expandedRowIds ?? props.defaultExpandedRowIds ?? [],\r\n );\r\n const expandedRowIds: GridRowId[] = props.expandedRowIds ?? internalExpandedRowIds;\r\n const setExpandedRowIds = useCallback((next: GridRowId[]) => {\r\n if (props.expandedRowIds === undefined) setInternalExpandedRowIdsRaw(next);\r\n props.onExpandedRowIdsChange?.(next);\r\n }, [props.expandedRowIds, props.onExpandedRowIdsChange]);\r\n\r\n /** Toggle de uma row específica. Respeita `singleExpand` (default false). */\r\n const toggleRowExpansion = useCallback((id: GridRowId) => {\r\n const current = props.expandedRowIds ?? internalExpandedRowIds;\r\n const has = current.includes(id);\r\n let next: GridRowId[];\r\n if (has) {\r\n next = current.filter((x) => x !== id);\r\n } else if (props.singleExpand) {\r\n next = [id];\r\n } else {\r\n next = [...current, id];\r\n }\r\n setExpandedRowIds(next);\r\n }, [props.expandedRowIds, internalExpandedRowIds, props.singleExpand, setExpandedRowIds]);\r\n\r\n /* ── Modo: client (rows) vs server (fetchData) ───────────────── */\r\n\r\n const isServerMode = !!props.fetchData;\r\n const clientRows = props.rows ?? [];\r\n\r\n /* ── Processor (client mode pipeline) ────────────────────────── */\r\n\r\n // Skip paginate quando:\r\n // - paginationConfig.enabled === false (consumer não quer paginação)\r\n // - props.virtualize (virtualizer cuida do \"render só visível\", precisa de\r\n // todas as rows pra calcular scroll height total)\r\n // - groupBy state (Fase F.4: agrupamento precisa de todas as rows pra montar\r\n // grupos completos; paginar quebraria o conceito)\r\n // - getTreeDataPath (Fase F.4c: tree-data precisa de todas as rows pra\r\n // reconstruir a hierarquia completa; paginar cortaria ramos)\r\n const shouldPaginate =\r\n props.paginationConfig?.enabled !== false &&\r\n !props.virtualize &&\r\n !groupBy &&\r\n !props.getTreeDataPath;\r\n\r\n const processed = useDataTableProcessor({\r\n rows: isServerMode ? [] : clientRows,\r\n columns: props.columns,\r\n filterModel: filters.filterModel,\r\n search: search.debouncedValue,\r\n sortModel: sort.sortModels,\r\n paginationModel: pagination.paginationModel,\r\n paginate: shouldPaginate,\r\n });\r\n\r\n /* ── Query (server mode) — só executa quando fetchData presente ── */\r\n\r\n const query = useDataTableQuery({\r\n // Quando fetchData é undefined, passamos uma função no-op estável\r\n // pra não quebrar a regra de hooks. A useEffect interna roda em ambos\r\n // os modos, mas em client mode o NOOP_FETCH não causa fetch real.\r\n fetchData: props.fetchData ?? NOOP_FETCH,\r\n filterModel: filters.filterModel,\r\n search: search.debouncedValue,\r\n searchField: undefined,\r\n sortModel: sort.sortModels,\r\n paginationModel: pagination.paginationModel,\r\n externalLoading: props.loading,\r\n });\r\n\r\n // Seleciona output baseado no modo\r\n const effectiveRows = isServerMode ? query.rowsToRender : processed.rowsToRender;\r\n const effectiveTotal = isServerMode\r\n ? (props.rowCount ?? query.totalAfterFilter)\r\n : processed.totalAfterFilter;\r\n const allPagesProcessed = isServerMode ? query.rowsToRender : processed.rowsAllPagesProcessed;\r\n\r\n // Clamp de página fora de range: quando o total encolhe (ex: filtro reduz\r\n // resultados em server/controlled mode) e a página atual passou a ser maior\r\n // que a última válida, corrige o STATE — não só o render do footer. Sem isso,\r\n // em server/controlled o fetch podia rodar com page inválida até o user clicar.\r\n useEffect(() => {\r\n if (props.paginationConfig?.enabled === false) return;\r\n const { page, pageSize } = pagination.paginationModel;\r\n if (pageSize <= 0) return;\r\n const lastPage = Math.max(1, Math.ceil(effectiveTotal / pageSize));\r\n if (page > lastPage) pagination.setPage(lastPage);\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [effectiveTotal, pagination.paginationModel.page, pagination.paginationModel.pageSize]);\r\n\r\n const selection = useDataTableSelection({\r\n rows: allPagesProcessed,\r\n getRowId,\r\n selectionModel: props.selectionModel,\r\n onSelectionModelChange: props.onSelectionModelChange,\r\n });\r\n\r\n /* ── Export (CSV) ─────────────────────────────────────────────── */\r\n\r\n const exporter = useDataTableExport({\r\n columns: props.columns,\r\n rowsCurrentPage: effectiveRows,\r\n rowsAfterFilter: allPagesProcessed,\r\n rowsAll: clientRows, // server mode = [] (usa pagina atual via scope fallback)\r\n selectedIds: selection.selectedIds,\r\n getRowId,\r\n filename: props.toolbar?.title?.toLowerCase().replace(/\\s+/g, \"-\") ?? \"export\",\r\n });\r\n\r\n /* ── Estados de feedback ──────────────────────────────────────── */\r\n\r\n const isLoading = isServerMode ? query.isLoading : !!props.loading;\r\n const totalRowsForEmpty = isServerMode\r\n ? effectiveTotal\r\n : clientRows.length;\r\n const isDataEmpty = !isLoading && totalRowsForEmpty === 0 && effectiveRows.length === 0;\r\n const isNoResults =\r\n !isLoading &&\r\n !isDataEmpty &&\r\n effectiveTotal === 0 &&\r\n (filters.filterModel.items.length > 0 || search.debouncedValue.length > 0);\r\n\r\n /* ── Snapshot do estado pra getState() ───────────────────────── */\r\n\r\n const getState = useCallback((): DataTableState => ({\r\n density: density.density,\r\n sortModel: sort.sortModels,\r\n paginationModel: pagination.paginationModel,\r\n selectionModel: selection.state,\r\n filterModel: filters.filterModel,\r\n search: search.debouncedValue,\r\n columnWidths: cols.columnWidths,\r\n pinnedColumns: cols.pinnedColumns,\r\n hiddenColumns: cols.hiddenColumns,\r\n columnOrder: cols.columnOrder,\r\n }), [\r\n density.density,\r\n sort.sortModels,\r\n pagination.paginationModel,\r\n selection.state,\r\n filters.filterModel,\r\n search.debouncedValue,\r\n cols.columnWidths,\r\n cols.pinnedColumns,\r\n cols.hiddenColumns,\r\n cols.columnOrder,\r\n ]);\r\n\r\n /* ── Saved Views ──────────────────────────────────────────────── */\r\n\r\n const savedViews = useDataTableSavedViews({\r\n persistId: props.persistId,\r\n service: props.savedViewsService,\r\n });\r\n\r\n /* ── Persist (localStorage) — salva debounced quando state muda ──\r\n *\r\n * Estratégia \"Default workspace\":\r\n * - O `defaultSnapshotRef` rastreia o estado APENAS quando `currentViewId === null`\r\n * (usuário está na tab Default). Quando uma view específica (preset/saved)\r\n * está aplicada, o defaultSnapshot fica congelado.\r\n * - O `applyDefault` lê do defaultSnapshotRef → restaura o \"workspace pessoal\"\r\n * do usuário, NÃO zera tudo.\r\n * - O persistedSnapshot completo continua sendo salvo (pra hidratação no\r\n * próximo mount) — inclusive quando uma view está aplicada. O\r\n * `lastActiveViewId` re-aplica a view, e o defaultSnapshot fica disponível\r\n * pra quando o usuário clicar Default. */\r\n\r\n const persistedSnapshot = useMemo(() => ({\r\n density: density.density,\r\n sortModel: sort.sortModels,\r\n pageSize: pagination.paginationModel.pageSize,\r\n // v4 — currentPage/filterModel/search persistem como parte do workspace Default.\r\n // O defaultSnapshotRef abaixo só atualiza quando currentViewId === null, ou seja\r\n // só \"captura\" esses valores quando a Default está ativa. Aplicar uma view custom\r\n // não polui o Default (o save sempre usa defaultSnapshotRef, não persistedSnapshot).\r\n currentPage: pagination.paginationModel.page,\r\n // Persistir SÓ resize manual (widthOverrides) — NUNCA as larguras efetivas\r\n // (cols.columnWidths inclui autoFit). Persistir efetivas congelava o layout\r\n // e matava o autoFit no reload (vira override de precedência máxima).\r\n columnWidths: cols.widthOverrides,\r\n pinnedColumns: cols.pinnedColumns,\r\n hiddenColumns: Array.from(cols.hiddenColumns),\r\n columnOrder: cols.columnOrder,\r\n filterModel: filters.filterModel,\r\n search: search.debouncedValue,\r\n // Fase v3 — features novas também persistem (workspace completo da Default)\r\n viewMode,\r\n groupBy,\r\n expandedRowIds,\r\n // Persistir ultima view ativa (preset id, saved view id, ou null pra Default)\r\n lastActiveViewId: savedViews.currentViewId,\r\n }), [\r\n density.density,\r\n sort.sortModels,\r\n pagination.paginationModel.pageSize,\r\n pagination.paginationModel.page,\r\n cols.widthOverrides,\r\n cols.pinnedColumns,\r\n cols.hiddenColumns,\r\n cols.columnOrder,\r\n filters.filterModel,\r\n search.debouncedValue,\r\n viewMode,\r\n groupBy,\r\n expandedRowIds,\r\n savedViews.currentViewId,\r\n ]);\r\n\r\n /**\r\n * Snapshot do workspace \"Default\" do usuário — atualizado APENAS quando\r\n * nenhuma view específica está aplicada. Usado pelo `applyDefault` pra\r\n * restaurar o estado que o usuário tinha antes de clicar numa view.\r\n *\r\n * Inicializado com persistedInitial (hidratação do mount). Atualizado em\r\n * useEffect sempre que persistedSnapshot muda E currentViewId === null.\r\n */\r\n const defaultSnapshotRef = useRef(persistedInitial);\r\n useEffect(() => {\r\n if (savedViews.currentViewId === null) {\r\n // Salva snapshot sem o lastActiveViewId (sempre null pra defaults)\r\n const { lastActiveViewId: _ignore, ...rest } = persistedSnapshot;\r\n defaultSnapshotRef.current = rest;\r\n }\r\n }, [persistedSnapshot, savedViews.currentViewId]);\r\n\r\n // v4 — o que vai pro localStorage é o snapshot Default (sempre intacto, mesmo\r\n // quando view custom está ativa) + lastActiveViewId atual. Assim:\r\n // - User filtra → Default snapshot atualiza → save reflete filtros aplicados\r\n // - User aplica view custom → lastActiveViewId muda, mas Default fica congelado\r\n // - User volta pra Default → applyDefault restaura tudo do snapshot\r\n // Triggers do useMemo abaixo cobrem o que dispara save: defaultSnapshotRef\r\n // atualiza via effect acima, então usamos persistedSnapshot como trigger via\r\n // currentViewId (quando muda, queremos salvar imediatamente o novo state).\r\n const persistedSnapshotForSave = useMemo(() => {\r\n const base = savedViews.currentViewId === null\r\n ? persistedSnapshot\r\n : { ...defaultSnapshotRef.current, lastActiveViewId: savedViews.currentViewId };\r\n return base;\r\n // persistedSnapshot já contém todos os campos relevantes; quando view custom\r\n // está ativa, usamos o defaultSnapshotRef preservado + view id atual.\r\n }, [persistedSnapshot, savedViews.currentViewId]);\r\n\r\n useDataTableStatePersistence({\r\n persistId: props.persistId,\r\n state: persistedSnapshotForSave,\r\n });\r\n\r\n /**\r\n * Aplica TODOS os campos capturáveis de uma view (saved OR preset).\r\n * Campos ausentes na view → aplica defaults razoáveis:\r\n * - layout (columnWidths/pinned/hidden/order) → `{}`/`[]`\r\n * - viewMode → \"table\" (default histórico)\r\n * - groupBy → undefined (sem agrupamento)\r\n * - expandedRowIds → [] (todas colapsadas)\r\n *\r\n * Comportamento idêntico pra saved view e preset view (mesmo shape de state).\r\n */\r\n const applyViewState = useCallback(\r\n (id: string, state: import(\"../services/saved-views.types\").DataTableSavedViewState) => {\r\n density.setDensity(state.density);\r\n sort.setSortModels(state.sortModel);\r\n // Normaliza filterModel ANTES de aplicar — promove operator escalar pra\r\n // multi quando coluna é multiSelect (ver helper acima). Fix raiz pro\r\n // problema do preset com `{field, value}` sem operator.\r\n filters.setFilterModel(\r\n normalizeFilterModelForColumns(state.filterModel, props.columns),\r\n );\r\n cols.applyColumnState({\r\n columnWidths: state.columnWidths,\r\n pinnedColumns: state.pinnedColumns,\r\n hiddenColumns: state.hiddenColumns,\r\n columnOrder: state.columnOrder,\r\n });\r\n // viewMode é \"sticky\": só troca se a visão definir um explicitamente\r\n // (ex.: preset de kanban). Presets sem viewMode mantêm o que o usuário\r\n // está vendo (table/list/kanban) — trocar de view não deve flipar a view.\r\n if (state.viewMode !== undefined) setViewMode(state.viewMode);\r\n setGroupBy(state.groupBy);\r\n setExpandedRowIds(state.expandedRowIds ?? []);\r\n savedViews.setCurrentViewId(id);\r\n },\r\n [density, sort, filters, cols, setViewMode, setGroupBy, setExpandedRowIds, savedViews],\r\n );\r\n\r\n const applyView = useCallback(\r\n (view: SavedView) => applyViewState(view.id, view.state),\r\n [applyViewState],\r\n );\r\n\r\n /** Aplica preset view (read-only) — mesma lógica do applyView (state unificado). */\r\n const applyPresetView = useCallback(\r\n (preset: DataTablePresetView) => applyViewState(preset.id, preset.state),\r\n [applyViewState],\r\n );\r\n\r\n /**\r\n * Apply unificado por id — procura primeiro em defaultViews (presets), depois\r\n * em savedViews. Usado pelo TableToolbarViews via onApply(id).\r\n */\r\n const applyViewById = useCallback(\r\n (id: string) => {\r\n const preset = props.defaultViews?.find((v) => v.id === id);\r\n if (preset) {\r\n applyPresetView(preset);\r\n return;\r\n }\r\n const saved = savedViews.views.find((v) => v.id === id);\r\n if (saved) applyView(saved);\r\n },\r\n [props.defaultViews, savedViews.views, applyPresetView, applyView],\r\n );\r\n\r\n /* ── Restore lastActiveViewId no mount (depois de savedViews carregar) ── */\r\n\r\n const restoredRef = useRef(false);\r\n useEffect(() => {\r\n if (restoredRef.current) return;\r\n if (!props.persistId) return;\r\n // Espera savedViews terminar de carregar pra ter a lista completa pra lookup\r\n if (savedViews.isLoading) return;\r\n restoredRef.current = true;\r\n\r\n const lastId = persistedInitial?.lastActiveViewId;\r\n if (!lastId) return;\r\n\r\n // Tenta preset primeiro, depois saved\r\n const preset = props.defaultViews?.find((v) => v.id === lastId);\r\n if (preset) {\r\n applyPresetView(preset);\r\n return;\r\n }\r\n const saved = savedViews.views.find((v) => v.id === lastId);\r\n if (saved) applyView(saved);\r\n }, [\r\n props.persistId,\r\n persistedInitial,\r\n savedViews.isLoading,\r\n savedViews.views,\r\n props.defaultViews,\r\n applyPresetView,\r\n applyView,\r\n ]);\r\n\r\n const saveCurrentAsView = useCallback(\r\n (name: string, opts?: { isPublic?: boolean }) => {\r\n return savedViews.saveView(\r\n name,\r\n {\r\n filterModel: filters.filterModel,\r\n sortModel: sort.sortModels,\r\n density: density.density,\r\n // Só resize manual (não as efetivas c/ autoFit) — senão a view congela\r\n // o layout e mata o autoFit ao ser aplicada.\r\n columnWidths: cols.widthOverrides,\r\n pinnedColumns: cols.pinnedColumns,\r\n hiddenColumns: Array.from(cols.hiddenColumns),\r\n columnOrder: cols.columnOrder,\r\n // Features novas — capturadas no snapshot\r\n viewMode,\r\n groupBy,\r\n expandedRowIds,\r\n },\r\n opts,\r\n );\r\n },\r\n [\r\n savedViews,\r\n filters.filterModel,\r\n sort.sortModels,\r\n density.density,\r\n cols.widthOverrides,\r\n cols.pinnedColumns,\r\n cols.hiddenColumns,\r\n cols.columnOrder,\r\n viewMode,\r\n groupBy,\r\n expandedRowIds,\r\n ],\r\n );\r\n\r\n /**\r\n * Tab \"Default\" — restaura o \"workspace pessoal\" do usuário (estado salvo\r\n * no localStorage), NÃO zera tudo.\r\n *\r\n * Quando `persistId` está presente:\r\n * - Lê do `defaultSnapshotRef.current` (mantido em sincronia conforme o\r\n * usuário mexia na Default antes de aplicar uma view).\r\n * - **v4**: filters/search/currentPage também são restaurados (parte do workspace).\r\n * Pra limpar manualmente, user clica \"Limpar filtros\" / \"Limpar busca\" / etc.\r\n *\r\n * Quando `persistId` ausente (sem persistence):\r\n * - Comportamento legado: zera tudo (Default = empty state).\r\n */\r\n const applyDefault = useCallback(() => {\r\n const snapshot = props.persistId ? defaultSnapshotRef.current : null;\r\n\r\n if (snapshot) {\r\n density.setDensity(snapshot.density ?? \"standard\");\r\n sort.setSortModels(snapshot.sortModel ?? []);\r\n cols.applyColumnState({\r\n columnWidths: snapshot.columnWidths ?? {},\r\n pinnedColumns: snapshot.pinnedColumns ?? {},\r\n hiddenColumns: snapshot.hiddenColumns ?? [],\r\n columnOrder: snapshot.columnOrder ?? props.columns.map((c) => String(c.field)),\r\n });\r\n // viewMode sticky: clicar \"Default\" não flipa a view atual (table/list/kanban).\r\n setGroupBy(snapshot.groupBy);\r\n setExpandedRowIds(snapshot.expandedRowIds ?? []);\r\n // v4 — restaura filters/search/page do workspace Default\r\n filters.setFilterModel(snapshot.filterModel ?? { items: [], logicOperator: \"AND\" });\r\n search.setInputValue(snapshot.search ?? \"\");\r\n pagination.setPaginationModel({\r\n page: snapshot.currentPage ?? 1,\r\n pageSize: snapshot.pageSize ?? pagination.paginationModel.pageSize,\r\n });\r\n } else {\r\n // Sem persistId: comportamento legado (empty state)\r\n density.setDensity(\"standard\");\r\n sort.setSortModels([]);\r\n cols.applyColumnState({\r\n columnWidths: {},\r\n pinnedColumns: {},\r\n hiddenColumns: [],\r\n columnOrder: props.columns.map((c) => String(c.field)),\r\n });\r\n setViewMode(\"table\");\r\n setGroupBy(undefined);\r\n setExpandedRowIds([]);\r\n filters.setFilterModel({ items: [], logicOperator: \"AND\" });\r\n search.setInputValue(\"\");\r\n }\r\n\r\n savedViews.setCurrentViewId(null);\r\n }, [props.persistId, props.columns, density, sort, filters, search, pagination, cols, setViewMode, setGroupBy, setExpandedRowIds, savedViews]);\r\n\r\n /* ── Tree-data: expand-all / collapse-all programático ───────────\r\n *\r\n * `expandedRowIds` guarda os ids que DIVERGEM do estado default de expansão\r\n * (mesma semântica de buildTreeRows/group-rows): com `defaultExpanded=true`\r\n * um id presente conta como COLAPSADO; com `defaultExpanded=false` conta como\r\n * EXPANDIDO. Logo, \"expandir/recolher tudo\" é só escolher entre `[]` (todos no\r\n * default) e \"todos os ids expansíveis\" (todos divergindo):\r\n *\r\n * defaultExpanded=true → expandAll = [] | collapseAll = todos os ids\r\n * defaultExpanded=false → expandAll = todos os ids | collapseAll = []\r\n *\r\n * `collectExpandableTreeIds` varre TODAS as rows pós-filtro/sort (não só a\r\n * página atual — tree-data desliga paginação) e retorna os ids dos nós que têm\r\n * filhos. No-op fora do modo tree-data (sem `getTreeDataPath`). */\r\n const treeDefaultExpanded = props.treeData?.defaultExpanded !== false; // default true\r\n\r\n const expandAllTree = useCallback(() => {\r\n if (!props.getTreeDataPath) return;\r\n if (treeDefaultExpanded) {\r\n // Tudo já expandido por default → zera a divergência.\r\n setExpandedRowIds([]);\r\n } else {\r\n // Cada nó com filhos precisa divergir do default colapsado.\r\n setExpandedRowIds(\r\n collectExpandableTreeIds(allPagesProcessed, props.getTreeDataPath, getRowId),\r\n );\r\n }\r\n }, [props.getTreeDataPath, treeDefaultExpanded, allPagesProcessed, getRowId, setExpandedRowIds]);\r\n\r\n const collapseAllTree = useCallback(() => {\r\n if (!props.getTreeDataPath) return;\r\n if (treeDefaultExpanded) {\r\n // Cada nó com filhos precisa divergir do default expandido.\r\n setExpandedRowIds(\r\n collectExpandableTreeIds(allPagesProcessed, props.getTreeDataPath, getRowId),\r\n );\r\n } else {\r\n // Tudo já colapsado por default → zera a divergência.\r\n setExpandedRowIds([]);\r\n }\r\n }, [props.getTreeDataPath, treeDefaultExpanded, allPagesProcessed, getRowId, setExpandedRowIds]);\r\n\r\n /* ── Imperative ref ──────────────────────────────────────────── */\r\n\r\n useImperativeHandle(ref, () => ({\r\n refresh: () => {\r\n if (isServerMode) query.refresh();\r\n // Client mode: refresh é no-op (rows já estão em memória).\r\n },\r\n getState,\r\n getSelectedIds: () => selection.selectedIds,\r\n getSelectedCount: () => selection.selectedCount,\r\n clearSelection: selection.clear,\r\n exportCsv: exporter.exportCsv,\r\n resetPersistedState: () => {\r\n clearPersistedState(props.persistId);\r\n },\r\n expandAllTree,\r\n collapseAllTree,\r\n }), [getState, selection, isServerMode, query, exporter, props.persistId, expandAllTree, collapseAllTree]);\r\n\r\n /* ── Context value memoizado ─────────────────────────────────── */\r\n\r\n const contextValue = useMemo<DataTableContextValue<T>>(() => ({\r\n rows: clientRows,\r\n effectiveColumns: cols.effectiveColumns,\r\n columnWidths: cols.columnWidths,\r\n stickyOffsets: cols.stickyOffsets,\r\n columnOrder: cols.columnOrder,\r\n hiddenColumns: cols.hiddenColumns,\r\n pinnedColumns: cols.pinnedColumns,\r\n sortModel: sort.sortModels,\r\n paginationModel: pagination.paginationModel,\r\n selection: {\r\n state: selection.state,\r\n isRowSelected: selection.isRowSelected,\r\n selectedCount: selection.selectedCount,\r\n },\r\n density: density.density,\r\n search: search.inputValue,\r\n filterModel: filters.filterModel,\r\n getRowId,\r\n }), [\r\n clientRows,\r\n cols.effectiveColumns,\r\n cols.columnWidths,\r\n cols.stickyOffsets,\r\n cols.columnOrder,\r\n cols.hiddenColumns,\r\n cols.pinnedColumns,\r\n sort.sortModels,\r\n pagination.paginationModel,\r\n selection.state,\r\n selection.isRowSelected,\r\n selection.selectedCount,\r\n density.density,\r\n search.inputValue,\r\n filters.filterModel,\r\n getRowId,\r\n ]);\r\n\r\n return {\r\n contextValue,\r\n isLoading,\r\n isDataEmpty,\r\n isNoResults,\r\n /** Ref ao scroll container (compartilhado entre Table.scrollRef + useColumnAutoWidth). */\r\n scrollContainerRef,\r\n rowsToRender: effectiveRows,\r\n /** Todas as rows após filter/search/sort (sem paginate) — usado por totalizers\r\n * pra agregar sobre tudo, nao só pagina atual. Em server mode = current page. */\r\n rowsAllPagesProcessed: allPagesProcessed,\r\n totalAfterFilter: effectiveTotal,\r\n cols,\r\n sort,\r\n pagination,\r\n selection,\r\n density,\r\n search,\r\n filters,\r\n exporter,\r\n isServerMode,\r\n savedViews,\r\n applyView,\r\n applyViewById,\r\n applyDefault,\r\n saveCurrentAsView,\r\n query,\r\n // States novos centralizados (controlled/uncontrolled)\r\n viewMode,\r\n setViewMode,\r\n groupBy,\r\n setGroupBy,\r\n expandedRowIds,\r\n setExpandedRowIds,\r\n toggleRowExpansion,\r\n /** Tree-data: expande/recolhe TODOS os nós de uma vez (programático).\r\n * Também expostos no imperative handle (`DataTableRef`). */\r\n expandAllTree,\r\n collapseAllTree,\r\n /** Modo tree-data ativo? (há `getTreeDataPath` e não há groupBy). */\r\n useTreeData: !!props.getTreeDataPath && !groupBy,\r\n };\r\n}\r\n","import { useEffect, useRef, type RefObject } from \"react\";\r\n\r\n/**\r\n * `useGrabToScroll` — arrastar o corpo da tabela (\"grab\") pra rolar\r\n * horizontalmente, equivalente ao hook legado do DataGrid MUI.\r\n *\r\n * Anexa pointer listeners ao elemento de scroll (`scrollContainerRef`). Um\r\n * arrasto só começa após o ponteiro passar de `thresholdPx` (default 6px) —\r\n * abaixo disso o gesto é tratado como clique normal (seleção/click de célula\r\n * preservados). Quando um arrasto de fato acontece, o `click` subsequente é\r\n * suprimido (capture-phase) pra não disparar `onRowClick` ou seleção acidental.\r\n *\r\n * Não interfere no scroll por roda (wheel) — apenas posiciona `scrollLeft` via\r\n * pointermove. Pula:\r\n * - dispositivos touch (`pointer: coarse`) — lá o scroll nativo já funciona;\r\n * - alvos interativos (button/input/a/checkbox/[role=button]/etc) e células\r\n * editáveis/expansíveis/de seleção, pra não roubar o gesto deles.\r\n *\r\n * @param scrollContainerRef ref ao elemento com `overflow-x` (o mesmo\r\n * `scrollRef` passado ao `<Table>`).\r\n * @param enabled liga/desliga o comportamento sem desmontar o hook.\r\n * @param thresholdPx distância mínima (px) pra um movimento virar arrasto.\r\n */\r\nexport function useGrabToScroll(\r\n scrollContainerRef: RefObject<HTMLElement | null>,\r\n enabled: boolean,\r\n thresholdPx = 6,\r\n): void {\r\n // Persiste entre renders: sinaliza ao click-capture que o último gesto foi\r\n // um arrasto e o clique deve ser engolido.\r\n const suppressClickRef = useRef(false);\r\n\r\n useEffect(() => {\r\n if (!enabled) return;\r\n const scroller = scrollContainerRef.current;\r\n if (!scroller) return;\r\n\r\n // Touch já rola nativamente — grab-to-scroll é só desktop (mouse/pen).\r\n if (\r\n typeof window !== \"undefined\" &&\r\n typeof window.matchMedia === \"function\" &&\r\n window.matchMedia(\"(pointer: coarse)\").matches\r\n ) {\r\n return;\r\n }\r\n\r\n // Alvos que NÃO devem iniciar um arrasto (têm gesto próprio).\r\n const INTERACTIVE_SELECTOR = [\r\n \"a\",\r\n \"button\",\r\n \"input\",\r\n \"textarea\",\r\n \"select\",\r\n '[role=\"button\"]',\r\n '[role=\"menuitem\"]',\r\n '[role=\"checkbox\"]',\r\n '[role=\"switch\"]',\r\n '[contenteditable=\"true\"]',\r\n \"[data-editable]\",\r\n \"[data-expandable]\",\r\n '[data-purpose=\"selection\"]',\r\n '[data-purpose=\"actions\"]',\r\n ].join(\",\");\r\n\r\n const prevCursor = scroller.style.cursor;\r\n const prevUserSelect = scroller.style.userSelect;\r\n\r\n /**\r\n * `cursor: grab` SÓ quando há o que arrastar.\r\n *\r\n * Até 2026-08-21 a mãozinha era aplicada sem condição, e o `pointerdown` recusava o\r\n * arrasto depois (`scrollWidth <= clientWidth`, abaixo). Resultado: em toda tabela que\r\n * cabia na tela — a maioria — o cursor prometia um gesto que não existia, e o usuário\r\n * clicava e arrastava sem nada acontecer. Affordance mentindo é pior que affordance\r\n * ausente: ela ensina um gesto errado.\r\n */\r\n const syncCursor = () => {\r\n const rolavel = scroller.scrollWidth > scroller.clientWidth;\r\n scroller.style.cursor = rolavel ? \"grab\" : prevCursor;\r\n };\r\n syncCursor();\r\n\r\n /*\r\n * `window.resize` não basta: largura de coluna (autoFit, resize manual), troca de view\r\n * (tabela ↔ lista ↔ kanban) e chegada de dados mudam o `scrollWidth` sem a janela mudar\r\n * de tamanho. O observer vai no scroller E no conteúdo dele — o 1º pega o container\r\n * encolhendo, o 2º pega a tabela crescendo por dentro.\r\n */\r\n const ro =\r\n typeof ResizeObserver === \"function\" ? new ResizeObserver(syncCursor) : null;\r\n if (ro) {\r\n ro.observe(scroller);\r\n if (scroller.firstElementChild) ro.observe(scroller.firstElementChild);\r\n }\r\n\r\n let isPointerDown = false;\r\n let isDragging = false;\r\n let activePointerId: number | null = null;\r\n let startClientX = 0;\r\n let startScrollLeft = 0;\r\n\r\n const shouldIgnoreTarget = (target: EventTarget | null): boolean => {\r\n const el = target instanceof Element ? target : null;\r\n if (!el) return true;\r\n return el.closest(INTERACTIVE_SELECTOR) != null;\r\n };\r\n\r\n const onClickCapture = (event: MouseEvent) => {\r\n if (!suppressClickRef.current) return;\r\n suppressClickRef.current = false;\r\n event.preventDefault();\r\n event.stopPropagation();\r\n };\r\n\r\n const onPointerDown = (event: PointerEvent) => {\r\n // Só botão primário do mouse; ignora touch (já tratado pelo skip acima,\r\n // mas defensivo) — pen é permitido.\r\n if (event.pointerType === \"mouse\" && event.button !== 0) return;\r\n if (event.pointerType === \"touch\") return;\r\n if (shouldIgnoreTarget(event.target)) return;\r\n // Nada a rolar — não inicia.\r\n if (scroller.scrollWidth <= scroller.clientWidth) return;\r\n\r\n isPointerDown = true;\r\n isDragging = false;\r\n activePointerId = event.pointerId;\r\n startClientX = event.clientX;\r\n startScrollLeft = scroller.scrollLeft;\r\n };\r\n\r\n const onPointerMove = (event: PointerEvent) => {\r\n if (!isPointerDown || activePointerId !== event.pointerId) return;\r\n const deltaX = event.clientX - startClientX;\r\n if (!isDragging) {\r\n if (Math.abs(deltaX) < thresholdPx) return;\r\n // Cruzou o threshold → vira arrasto de verdade.\r\n isDragging = true;\r\n scroller.style.cursor = \"grabbing\";\r\n scroller.style.userSelect = \"none\";\r\n try {\r\n scroller.setPointerCapture(event.pointerId);\r\n } catch {\r\n /* setPointerCapture pode falhar em alguns browsers — no-op */\r\n }\r\n }\r\n scroller.scrollLeft = startScrollLeft - deltaX;\r\n event.preventDefault();\r\n };\r\n\r\n const finish = (event: PointerEvent) => {\r\n if (activePointerId !== event.pointerId) return;\r\n if (isDragging) {\r\n // Suprime o `click` que o browser dispara após o pointerup do arrasto.\r\n suppressClickRef.current = true;\r\n }\r\n isPointerDown = false;\r\n isDragging = false;\r\n activePointerId = null;\r\n // Re-sincroniza em vez de fixar \"grab\": o conteúdo pode ter mudado durante o arrasto\r\n // (troca de view, coluna redimensionada) e aí a tabela já não rola mais.\r\n syncCursor();\r\n scroller.style.userSelect = prevUserSelect;\r\n try {\r\n scroller.releasePointerCapture(event.pointerId);\r\n } catch {\r\n /* releasePointerCapture pode falhar se já liberado — no-op */\r\n }\r\n };\r\n\r\n scroller.addEventListener(\"click\", onClickCapture, true);\r\n scroller.addEventListener(\"pointerdown\", onPointerDown);\r\n scroller.addEventListener(\"pointermove\", onPointerMove, { passive: false });\r\n scroller.addEventListener(\"pointerup\", finish);\r\n scroller.addEventListener(\"pointercancel\", finish);\r\n\r\n return () => {\r\n scroller.removeEventListener(\"click\", onClickCapture, true);\r\n scroller.removeEventListener(\"pointerdown\", onPointerDown);\r\n scroller.removeEventListener(\"pointermove\", onPointerMove);\r\n scroller.removeEventListener(\"pointerup\", finish);\r\n scroller.removeEventListener(\"pointercancel\", finish);\r\n ro?.disconnect();\r\n scroller.style.cursor = prevCursor;\r\n scroller.style.userSelect = prevUserSelect;\r\n };\r\n }, [scrollContainerRef, enabled, thresholdPx]);\r\n}\r\n","import type { ReactNode } from \"react\";\r\nimport { Inbox } from \"lucide-react\";\r\n\r\nexport type DataTableEmptyProps = {\r\n /** Icone na ilustração. Default: Inbox. Renderizado dentro de circulo com bg-bg-muted. */\r\n icon?: ReactNode;\r\n /** Titulo principal. Default: \"Nenhum dado cadastrado\". */\r\n title?: string;\r\n /** Descricao secundaria. Default: orientacao de proximos passos. */\r\n description?: string;\r\n /** Acao primaria — ex: <Button>Adicionar</Button>. Renderizada abaixo da descricao. */\r\n action?: ReactNode;\r\n};\r\n\r\n/**\r\n * Estado vazio (dataset sem nenhum registro). Usado quando a tabela nao tem\r\n * dados em absoluto — diferente de NoResults (que aplica quando filtros zeraram).\r\n *\r\n * Estrutura: ilustracao circular > titulo > descricao > acao opcional.\r\n * Consumer pode customizar via props ou substituir 100% via `props.renderEmpty`.\r\n */\r\nexport function DataTableEmpty({\r\n icon = <Inbox aria-hidden />,\r\n title = \"Nenhum dado cadastrado\",\r\n description = \"Comece adicionando novos itens para visualizar aqui.\",\r\n action,\r\n}: DataTableEmptyProps = {}) {\r\n return (\r\n <div className=\"flex-1 min-h-0 flex flex-col items-center justify-center gap-gp-lg p-pad-4xl text-center\">\r\n <div\r\n className=\"flex items-center justify-center size-[80px] rounded-full bg-bg-muted [&_svg]:size-icon-2xl [&_svg]:text-fg-muted\"\r\n aria-hidden\r\n >\r\n {icon}\r\n </div>\r\n <div className=\"flex flex-col gap-gp-2xs items-center\">\r\n <p className=\"text-title-md text-fg-strong\">{title}</p>\r\n <p className=\"text-body-md text-fg-muted max-w-[360px]\">\r\n {description}\r\n </p>\r\n </div>\r\n {action && <div className=\"mt-pad-md\">{action}</div>}\r\n </div>\r\n );\r\n}\r\n","/**\n * DataTableLoading — esqueleto de loading que simula a estrutura da tabela.\n *\n * Renderiza header bar + N rows com células fluidas que se distribuem em todas\n * as colunas — visualmente próximo da tabela final pra evitar layout shift quando\n * dados chegam. Cada cell tem placeholder bg-bg-muted animate-pulse com largura\n * relativa (50-90% da cell) pra parecer texto real.\n */\nexport type DataTableLoadingProps = {\n /** Quantas linhas fake renderizar. Default 10. */\n rows?: number;\n /** Quantas colunas fake renderizar. Default 6. */\n columns?: number;\n};\n\nexport function DataTableLoading({\n rows = 10,\n columns = 6,\n}: DataTableLoadingProps = {}) {\n // Pesos pra distribuir colunas (1 = base; 2 = duas vezes maior).\n // Primeira coluna mais estreita (ID/checkbox), segunda mais larga (nome),\n // demais variando. Repete o padrão se columns > 6.\n const widthPattern = [0.5, 1.5, 1.4, 1.2, 1, 0.9];\n // Larguras INTERNAS da placeholder dentro da cell (% — varia pra parecer texto)\n const innerPattern = [70, 85, 75, 60, 80, 65];\n\n return (\n <div\n role=\"status\"\n aria-label=\"Carregando dados\"\n aria-busy=\"true\"\n // Mesmo container do Table primitivo (table.styles.ts → root) — garante\n // que skeleton tenha bordas, radius e shadow idênticos ao estado loaded,\n // evitando o \"salto visual\" quando dados chegam (quadrado → arredondado).\n className=\"flex flex-col w-full bg-bg-table border border-border-table rounded-radius-xl shadow-sh-sm overflow-hidden\"\n >\n {/* Header fake — barra mais escura simulando o head da tabela */}\n <div className=\"flex w-full h-[42px] items-center px-pad-2xl gap-gp-2xl border-b border-border-table bg-bg-table-head\">\n {Array.from({ length: columns }).map((_, colIdx) => (\n <div\n key={colIdx}\n className=\"flex-1 min-w-0\"\n style={{ flex: widthPattern[colIdx % widthPattern.length] }}\n >\n <div\n className=\"h-3 rounded-radius-sm bg-bg-muted animate-pulse\"\n style={{ width: `${innerPattern[colIdx % innerPattern.length]}%` }}\n />\n </div>\n ))}\n </div>\n\n {/* Body rows fake */}\n {Array.from({ length: rows }).map((_, rowIdx) => (\n <div\n key={rowIdx}\n className=\"flex w-full h-[56px] items-center px-pad-2xl gap-gp-2xl border-b border-border-table last:border-b-0\"\n >\n {Array.from({ length: columns }).map((_, colIdx) => {\n // Variacao pseudo-random estavel pra evitar todas linhas identicas\n const seed = (rowIdx * 31 + colIdx * 17) % 100;\n const width = 40 + ((seed * 1.5) % 50); // 40-90%\n return (\n <div\n key={colIdx}\n className=\"flex-1 min-w-0\"\n style={{ flex: widthPattern[colIdx % widthPattern.length] }}\n >\n <div\n className=\"h-form-sm rounded-radius-md bg-bg-muted animate-pulse\"\n style={{\n width: `${width}%`,\n animationDelay: `${(rowIdx * 60 + colIdx * 30) % 600}ms`,\n }}\n />\n </div>\n );\n })}\n </div>\n ))}\n </div>\n );\n}\n","import type { ReactNode } from \"react\";\r\nimport { SearchX, FilterX } from \"lucide-react\";\r\nimport { Button } from \"../../Button/button\";\r\n\r\nexport type DataTableNoResultsProps = {\r\n /** Icone na ilustracao. Default: SearchX. */\r\n icon?: ReactNode;\r\n /** Titulo principal. Default: \"Nenhum dado encontrado\". */\r\n title?: string;\r\n /** Descricao secundaria. */\r\n description?: string;\r\n /** Acao primaria customizada — substitui o botao \"Limpar filtros\" default. */\r\n action?: ReactNode;\r\n /** Callback que limpa filtros — quando definido SEM `action`, renderiza\r\n * botao default \"Limpar filtros\". DataTable auto-wira isso pra\r\n * filters.clearFilters / search.flush. */\r\n onClearFilters?: () => void;\r\n};\r\n\r\n/**\r\n * Estado \"nada encontrado com filtros aplicados\". Diferente de Empty\r\n * (dataset vazio em absoluto). Sugere ajustar/limpar filtros.\r\n *\r\n * Auto-wire: DataTable passa `onClearFilters` que limpa filterModel + search.\r\n * Consumer pode customizar via props ou substituir 100% via `props.renderNoResults`.\r\n */\r\nexport function DataTableNoResults({\r\n icon = <SearchX aria-hidden />,\r\n title = \"Nenhum dado encontrado\",\r\n description = \"Não encontramos nada com os critérios pesquisados. Tente ajustar os filtros.\",\r\n action,\r\n onClearFilters,\r\n}: DataTableNoResultsProps = {}) {\r\n // Render default action quando onClearFilters definido E action nao customizado\r\n const resolvedAction =\r\n action ??\r\n (onClearFilters ? (\r\n <Button\r\n size=\"sm\"\r\n variant=\"outline\"\r\n color=\"secondary\"\r\n iconLeft={<FilterX />}\r\n onClick={onClearFilters}\r\n >\r\n Limpar filtros\r\n </Button>\r\n ) : null);\r\n\r\n return (\r\n <div className=\"flex-1 min-h-0 flex flex-col items-center justify-center gap-gp-lg p-pad-4xl text-center\">\r\n <div\r\n className=\"flex items-center justify-center size-[80px] rounded-full bg-bg-muted [&_svg]:size-icon-2xl [&_svg]:text-fg-muted\"\r\n aria-hidden\r\n >\r\n {icon}\r\n </div>\r\n <div className=\"flex flex-col gap-gp-2xs items-center\">\r\n <p className=\"text-title-md text-fg-strong\">{title}</p>\r\n <p className=\"text-body-md text-fg-muted max-w-[360px]\">\r\n {description}\r\n </p>\r\n </div>\r\n {resolvedAction && <div className=\"mt-pad-md\">{resolvedAction}</div>}\r\n </div>\r\n );\r\n}\r\n","import { useEffect, useState, type ReactNode } from \"react\";\r\nimport {\r\n ArrowUp,\r\n ArrowDown,\r\n PinIcon,\r\n PinOff,\r\n EyeOff,\r\n MoreHorizontal,\r\n X as XIcon,\r\n} from \"lucide-react\";\r\nimport { Button } from \"../../Button/button\";\r\nimport {\r\n DropdownMenu,\r\n DropdownMenuTrigger,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n DropdownMenuSeparator,\r\n} from \"@/components/shadcn/dropdown-menu\";\r\n\r\nexport type DataTableColumnMenuItem = {\r\n id: string;\r\n label: ReactNode;\r\n icon?: ReactNode;\r\n onSelect?: () => void;\r\n destructive?: boolean;\r\n disabled?: boolean;\r\n};\r\n\r\nexport type DataTableColumnMenuProps = {\r\n /** Nome da coluna (usado no aria-label). */\r\n columnName: string;\r\n /** Direção atual do sort (null = sem sort). */\r\n sortDirection: \"asc\" | \"desc\" | null;\r\n /** Pin atual (null = sem pin). */\r\n pinned: \"left\" | \"right\" | null;\r\n /** Pode esconder essa coluna? Default true. */\r\n canHide?: boolean;\r\n /** Handlers — null disabled */\r\n onSortAsc?: () => void;\r\n onSortDesc?: () => void;\r\n onSortClear?: () => void;\r\n onPinLeft?: () => void;\r\n onPinRight?: () => void;\r\n onUnpin?: () => void;\r\n onHide?: () => void;\r\n /** Items extras (slot pro consumer adicionar). */\r\n extraItems?: DataTableColumnMenuItem[];\r\n};\r\n\r\n/**\r\n * Menu 3-pontos no header de cada coluna do DataTable.\r\n * Acoes: Sort asc/desc/clear, Pin left/right/unpin, Hide column, extras.\r\n */\r\nexport function DataTableColumnMenu({\r\n columnName,\r\n sortDirection,\r\n pinned,\r\n canHide = true,\r\n onSortAsc,\r\n onSortDesc,\r\n onSortClear,\r\n onPinLeft,\r\n onPinRight,\r\n onUnpin,\r\n onHide,\r\n extraItems,\r\n}: DataTableColumnMenuProps) {\r\n // Controlled open + keepMounted: mantem o botão visível durante a animação\r\n // de fechamento do portal (~200ms). Sem isso, o seletor :has([data-state=open])\r\n // do wrapper headMenuItem perde o match assim que Radix muda pra \"closed\", o\r\n // botao some e o portal animando pisca em (0,0) por ter perdido a âncora.\r\n const [open, setOpen] = useState(false);\r\n const [keepMounted, setKeepMounted] = useState(false);\r\n\r\n useEffect(() => {\r\n if (open) {\r\n setKeepMounted(true);\r\n return;\r\n }\r\n if (!keepMounted) return;\r\n const t = setTimeout(() => setKeepMounted(false), 200);\r\n return () => clearTimeout(t);\r\n }, [open, keepMounted]);\r\n\r\n return (\r\n <DropdownMenu open={open} onOpenChange={setOpen}>\r\n <DropdownMenuTrigger asChild>\r\n <Button\r\n size=\"icon-2xs\"\r\n variant=\"ghost\"\r\n color=\"secondary\"\r\n aria-label={`Menu da coluna ${columnName}`}\r\n // data-menu-active fica true durante toda a vida do menu (abrindo,\r\n // aberto e janela de close animation). Wrapper headMenuItem usa\r\n // :has([data-menu-active=true]) pra continuar visivel.\r\n data-menu-active={keepMounted || undefined}\r\n // Interrompe propagacao em TODOS os eventos relevantes pra evitar\r\n // que o header sortable dispare handleSort enquanto o menu abre\r\n // (re-render durante anchor calculation faz o portal teleportar).\r\n onClick={(e) => e.stopPropagation()}\r\n onPointerDown={(e) => e.stopPropagation()}\r\n onMouseDown={(e) => e.stopPropagation()}\r\n >\r\n <MoreHorizontal />\r\n </Button>\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent align=\"end\" onClick={(e) => e.stopPropagation()}>\r\n {/* Sort */}\r\n <DropdownMenuItem\r\n onClick={onSortAsc}\r\n disabled={sortDirection === \"asc\"}\r\n >\r\n <ArrowUp className=\"size-icon-xs\" />\r\n Ordenar crescente\r\n </DropdownMenuItem>\r\n <DropdownMenuItem\r\n onClick={onSortDesc}\r\n disabled={sortDirection === \"desc\"}\r\n >\r\n <ArrowDown className=\"size-icon-xs\" />\r\n Ordenar decrescente\r\n </DropdownMenuItem>\r\n {sortDirection !== null && (\r\n <DropdownMenuItem onClick={onSortClear}>\r\n <XIcon className=\"size-icon-xs\" />\r\n Limpar ordenação\r\n </DropdownMenuItem>\r\n )}\r\n\r\n <DropdownMenuSeparator />\r\n\r\n {/* Pin */}\r\n {pinned !== \"left\" && (\r\n <DropdownMenuItem onClick={onPinLeft}>\r\n <PinIcon className=\"size-icon-xs\" />\r\n Fixar à esquerda\r\n </DropdownMenuItem>\r\n )}\r\n {pinned !== \"right\" && (\r\n <DropdownMenuItem onClick={onPinRight}>\r\n <PinIcon className=\"size-icon-xs\" />\r\n Fixar à direita\r\n </DropdownMenuItem>\r\n )}\r\n {pinned !== null && (\r\n <DropdownMenuItem onClick={onUnpin}>\r\n <PinOff className=\"size-icon-xs\" />\r\n Remover fixação\r\n </DropdownMenuItem>\r\n )}\r\n\r\n {canHide && (\r\n <>\r\n <DropdownMenuSeparator />\r\n <DropdownMenuItem onClick={onHide}>\r\n <EyeOff className=\"size-icon-xs\" />\r\n Ocultar coluna\r\n </DropdownMenuItem>\r\n </>\r\n )}\r\n\r\n {extraItems && extraItems.length > 0 && (\r\n <>\r\n <DropdownMenuSeparator />\r\n {extraItems.map((item) => (\r\n <DropdownMenuItem\r\n key={item.id}\r\n onClick={item.onSelect}\r\n disabled={item.disabled}\r\n variant={item.destructive ? \"destructive\" : \"default\"}\r\n >\r\n {item.icon}\r\n {item.label}\r\n </DropdownMenuItem>\r\n ))}\r\n </>\r\n )}\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n );\r\n}\r\n","import { MoreHorizontal } from \"lucide-react\";\r\nimport { Button } from \"../../Button/button\";\r\nimport {\r\n DropdownMenu,\r\n DropdownMenuTrigger,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n} from \"@/components/shadcn/dropdown-menu\";\r\nimport type { DataTableActionItem } from \"../data-table.types\";\r\nimport { splitActionSlots } from \"../utils/action-slots\";\r\n\r\nexport type DataTableActionsCellProps<T> = {\r\n /** Row da linha — passado pra disabled/hidden/onClick. */\r\n row: T;\r\n /** Lista de actions resolvida pra esta row. */\r\n actions: DataTableActionItem<T>[];\r\n};\r\n\r\n/**\r\n * Celula da coluna `type: \"actions\"` — renderiza icone-buttons inline e/ou o\r\n * dropdown \"…\". Quem decide o split é `splitActionSlots` (ver `utils/action-slots.ts`\r\n * pra a regra e a geometria que a justifica):\r\n *\r\n * - algum item com `showInMenu` → o split do consumer manda, sem limite;\r\n * - até 3 itens, nenhum marcado → todos inline, sem \"…\";\r\n * - mais de 3, nenhum marcado → todos no \"…\" (4 ícones não cabem na coluna).\r\n *\r\n * Items com `hidden(row) === true` somem completamente. Items com\r\n * `disabled(row) === true` ficam atenuados e sem click.\r\n *\r\n * Stopa propagacao no click do botao/menu pra nao disparar `onRowClick`\r\n * do TableRow ancestral.\r\n */\r\nexport function DataTableActionsCell<T>({\r\n row,\r\n actions,\r\n}: DataTableActionsCellProps<T>) {\r\n // Split vem do módulo compartilhado — o `calculate-column-widths` chama o MESMO\r\n // para dimensionar a coluna. Duas cópias da regra divergiriam no primeiro ajuste\r\n // e a coluna passaria a reservar espaço pra um layout diferente do renderizado.\r\n const { inline: inlineActions, menu: menuActions } = splitActionSlots(actions, row);\r\n\r\n if (inlineActions.length === 0 && menuActions.length === 0) return null;\r\n\r\n const resolveDisabled = (a: DataTableActionItem<T>): boolean => {\r\n if (typeof a.disabled === \"function\") return a.disabled(row);\r\n return !!a.disabled;\r\n };\r\n\r\n return (\r\n <div className=\"flex items-center gap-gp-2xs justify-end w-full\">\r\n {/* Icones inline */}\r\n {inlineActions.map((a) => (\r\n <Button\r\n key={a.id}\r\n size=\"icon-2xs\"\r\n variant=\"ghost\"\r\n color={a.destructive ? \"critical\" : \"secondary\"}\r\n aria-label={a.label}\r\n title={a.label}\r\n disabled={resolveDisabled(a)}\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n a.onClick(row);\r\n }}\r\n >\r\n {a.icon}\r\n </Button>\r\n ))}\r\n\r\n {/* Dropdown 3-pontos com items showInMenu */}\r\n {menuActions.length > 0 && (\r\n <DropdownMenu>\r\n <DropdownMenuTrigger asChild>\r\n <Button\r\n size=\"icon-2xs\"\r\n variant=\"ghost\"\r\n color=\"secondary\"\r\n aria-label=\"Mais acoes\"\r\n onClick={(e) => e.stopPropagation()}\r\n onPointerDown={(e) => e.stopPropagation()}\r\n onMouseDown={(e) => e.stopPropagation()}\r\n >\r\n <MoreHorizontal />\r\n </Button>\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent\r\n align=\"end\"\r\n onClick={(e) => e.stopPropagation()}\r\n >\r\n {menuActions.map((a) => (\r\n <DropdownMenuItem\r\n key={a.id}\r\n onClick={() => a.onClick(row)}\r\n disabled={resolveDisabled(a)}\r\n variant={a.destructive ? \"destructive\" : \"default\"}\r\n >\r\n {a.icon}\r\n {a.label}\r\n </DropdownMenuItem>\r\n ))}\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import type { ReactNode } from \"react\";\nimport { useSortable } from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { TableHeadCell } from \"../../Table\";\nimport type { TableHeadCellProps } from \"../../Table\";\n\nexport type DataTableSortableHeadCellProps = TableHeadCellProps & {\n /** ID unico do item no SortableContext (== field). Obrigatorio pra dnd. */\n sortableId: string;\n /** Quando true, desabilita drag (usado pra coluna actions). */\n disableDrag?: boolean;\n children?: ReactNode;\n};\n\n/**\n * Wrapper do TableHeadCell que adiciona drag-and-drop via @dnd-kit/sortable.\n *\n * - Activation constraint de 5px no PointerSensor (DndContext) preserva click-to-sort.\n * - Aplica `transform` + `transition` durante drag (CSS smooth movement).\n * - Reduz opacidade do item em drag pra dar feedback visual.\n * - Spread `attributes` + `listeners` via `rootProps` — listeners ficam na cell\n * inteira (drag activator) mas mousedown/click do resize handle + column menu\n * button já tem stopPropagation, então não conflitam.\n *\n * Quando `disableDrag=true`, o item participa do SortableContext (mantem layout)\n * mas não pode ser arrastado nem ser drop target.\n */\nexport function DataTableSortableHeadCell({\n sortableId,\n disableDrag = false,\n children,\n ...headCellProps\n}: DataTableSortableHeadCellProps) {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({\n id: sortableId,\n disabled: disableDrag,\n });\n\n // Cursor strategy:\n // - drag desabilitado → cursor default do TableHeadCell (pointer se sortable, default se não)\n // - durante drag ativo → grabbing (feedback visual de \"está sendo movido\")\n // - sortable + draggable → pointer (sort = ação primária ao click; drag é secundário)\n // - apenas draggable (não sortable) → grab (drag é a única ação interativa)\n const cursor: React.CSSProperties[\"cursor\"] = disableDrag\n ? undefined\n : isDragging\n ? \"grabbing\"\n : headCellProps.sortable\n ? \"pointer\"\n : \"grab\";\n\n const dragStyle: React.CSSProperties = {\n transform: CSS.Translate.toString(transform),\n transition,\n opacity: isDragging ? 0.4 : undefined,\n cursor,\n zIndex: isDragging ? 30 : undefined,\n // Override do sticky positioning durante drag pra cell flutuar acompanhando o cursor\n position: isDragging ? \"relative\" : undefined,\n };\n\n return (\n <TableHeadCell\n {...headCellProps}\n ref={setNodeRef}\n style={dragStyle}\n rootProps={{\n ...attributes,\n ...listeners,\n }}\n >\n {children}\n </TableHeadCell>\n );\n}\n","import type { ReactNode } from \"react\";\r\nimport type { DataTableColumnDef } from \"../data-table.types\";\r\nimport { applyValueGetter } from \"./resolve-value\";\r\n\r\n/**\r\n * Agregação de coluna — fonte ÚNICA. Antes a mesma lógica (switch\r\n * sum/avg/count/min/max + filtro de números + formatter) estava duplicada em\r\n * `data-table-group-header-row` e `data-table-totalizer-row`, com uma\r\n * divergência sutil: o totalizer NÃO respeitava `col.valueGetter` (lia só o\r\n * dot-path), o group-header sim. Agora ambos usam `applyValueGetter` → consistente.\r\n */\r\n\r\n/**\r\n * Computa o valor agregado built-in (sum/avg/count/min/max) de uma coluna sobre\r\n * `rows`. Retorna `null` quando `aggregate` não é um keyword built-in numérico.\r\n */\r\nexport function computeAggregate<T>(\r\n col: DataTableColumnDef<T>,\r\n rows: T[],\r\n): number | null {\r\n if (typeof col.aggregate !== \"string\") return null;\r\n const values = rows\r\n .map((r) => applyValueGetter(r, col))\r\n .filter((v): v is number => typeof v === \"number\" && !isNaN(v));\r\n\r\n switch (col.aggregate) {\r\n case \"sum\":\r\n return values.reduce((acc, v) => acc + v, 0);\r\n case \"avg\":\r\n return values.length === 0\r\n ? 0\r\n : values.reduce((acc, v) => acc + v, 0) / values.length;\r\n case \"count\":\r\n return rows.length;\r\n case \"min\":\r\n return values.length === 0 ? 0 : Math.min(...values);\r\n case \"max\":\r\n return values.length === 0 ? 0 : Math.max(...values);\r\n default:\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Resolve o conteúdo renderizável do aggregate de uma coluna:\r\n * 1. `override` explícito (quando passado, ex: aggregateRow do server mode)\r\n * 2. `col.aggregate` função custom → ReactNode livre\r\n * 3. keyword built-in → número computado + `aggregateFormatter ?? valueFormatter`\r\n * 4. senão → null\r\n */\r\nexport function renderAggregate<T>(\r\n col: DataTableColumnDef<T>,\r\n rows: T[],\r\n override?: ReactNode,\r\n): ReactNode {\r\n if (override !== undefined) return override;\r\n if (col.aggregate === undefined) return null;\r\n if (typeof col.aggregate === \"function\") return col.aggregate(rows);\r\n\r\n const result = computeAggregate(col, rows);\r\n if (result === null) return null;\r\n const formatter = col.aggregateFormatter ?? col.valueFormatter;\r\n return formatter ? formatter(result) : String(result);\r\n}\r\n","import type { ReactNode } from \"react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { TableCell } from \"../../Table\";\r\nimport type { DataTableColumnDef } from \"../data-table.types\";\r\nimport { renderAggregate } from \"../utils/aggregate\";\r\n\r\nexport type DataTableTotalizerRowProps<T> = {\r\n /** Colunas efetivas (apos hidden/order) — mesma fonte do header. */\r\n columns: DataTableColumnDef<T>[];\r\n /** Rows pra agregar. Em client mode: allPagesProcessed (todas filtradas).\r\n * Em server mode: current page rows (ou empty se consumer só usar aggregateRow). */\r\n rows: T[];\r\n /** Override pre-computado por field — vence aggregate built-in/custom. */\r\n overrides?: Record<string, ReactNode>;\r\n /** Widths efetivos por field (mesma fonte do header pra alinhar). */\r\n columnWidths: Record<string, number>;\r\n /** Sticky offsets pra colunas pinned. */\r\n stickyOffsets: Record<string, number>;\r\n /** Tem coluna de selection enabled? Renderiza cell vazia na esquerda. */\r\n hasSelection?: boolean;\r\n};\r\n\r\n/**\r\n * Footer row sticky no bottom do body — mostra agregacoes por coluna.\r\n *\r\n * Para cada coluna:\r\n * - Se `overrides[field]` definido → renderiza esse valor (server mode).\r\n * - Senao, se `column.aggregate` definido → computa local.\r\n * - Senao, cell vazia (apenas mantem largura/alinhamento).\r\n *\r\n * `column.aggregate` aceita:\r\n * - 'sum' | 'avg' | 'count' | 'min' | 'max' — built-ins (so funcionam em valores numericos).\r\n * - (rows: T[]) => ReactNode — funcao custom, recebe rows pra computar livremente.\r\n *\r\n * Formatacao do resultado built-in: `column.aggregateFormatter(value)` >\r\n * `column.valueFormatter(value)` > toString.\r\n */\r\nexport function DataTableTotalizerRow<T>({\r\n columns,\r\n rows,\r\n overrides,\r\n columnWidths,\r\n stickyOffsets,\r\n hasSelection = false,\r\n}: DataTableTotalizerRowProps<T>) {\r\n return (\r\n <div\r\n role=\"row\"\r\n className={cn(\r\n \"flex w-max min-w-full\",\r\n \"sticky bottom-0 z-[8]\",\r\n \"bg-bg-table-head border-t border-border-table\",\r\n \"h-[42px]\",\r\n )}\r\n >\r\n {hasSelection && (\r\n <TableCell width={56} align=\"center\" className=\"!px-0\">\r\n {/* Empty cell pra alinhar com checkbox column. */}\r\n </TableCell>\r\n )}\r\n {columns.map((col) => {\r\n const field = String(col.field);\r\n const content = renderAggregate(col, rows, overrides?.[field]);\r\n return (\r\n <TableCell\r\n key={field}\r\n field={field}\r\n width={columnWidths[field]}\r\n pinned={col.pinned}\r\n pinOffset={stickyOffsets[field]}\r\n align={col.align}\r\n ellipsis={col.ellipsis}\r\n className=\"text-body-xs font-semibold text-fg-strong bg-bg-table-head\"\r\n >\r\n {content}\r\n </TableCell>\r\n );\r\n })}\r\n </div>\r\n );\r\n}\r\n\r\n","import { useEffect, useRef, useState } from \"react\";\r\nimport { Loader2, AlertCircle } from \"lucide-react\";\r\nimport { Input } from \"@/components/shadcn/input\";\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from \"@/components/shadcn/select\";\r\nimport type { DataTableColumnDef } from \"../data-table.types\";\r\nimport { columnTypeRegistry } from \"../column-types\";\r\n\r\nexport type DataTableEditCellProps<T> = {\r\n column: DataTableColumnDef<T>;\r\n row: T;\r\n initialValue: any;\r\n /** Fase F.1 — quando true, mostra spinner overlay e bloqueia input (commit em andamento). */\r\n isLoading?: boolean;\r\n /** Fase F.1 — quando definido, mostra ícone de erro com tooltip e mantem edit aberto. */\r\n error?: string | null;\r\n onCommit: (newValue: any) => void;\r\n onCancel: () => void;\r\n};\r\n\r\n/**\r\n * Editor inline para celulas com `editable: true`.\r\n *\r\n * - Se `column.renderEdit` definido, delega 100% pro consumer (escape hatch).\r\n * - Caso contrario, renderiza editor default baseado em `column.editType`\r\n * (ou derivado de `column.type` / `column.filterOptions`).\r\n *\r\n * Eventos do editor default:\r\n * - Enter → commit\r\n * - Esc → cancel\r\n * - Blur → commit (delay 1 tick pra permitir Radix internal events terminarem)\r\n *\r\n * Editor SE auto-foca no mount. Input ganha selection.all pra usuario\r\n * sobrescrever rapidamente.\r\n */\r\nexport function DataTableEditCell<T>({\r\n column,\r\n row,\r\n initialValue,\r\n isLoading = false,\r\n error = null,\r\n onCommit,\r\n onCancel,\r\n}: DataTableEditCellProps<T>) {\r\n const [value, setValue] = useState(initialValue);\r\n\r\n // Wrapper com overlay de loading/error. Inputs internos ficam por baixo\r\n // com pointer-events bloqueado quando loading.\r\n const wrap = (children: React.ReactNode) => (\r\n <div className=\"relative w-full\">\r\n <div\r\n className={\r\n isLoading\r\n ? \"pointer-events-none opacity-60 transition-opacity\"\r\n : \"transition-opacity\"\r\n }\r\n >\r\n {children}\r\n </div>\r\n {isLoading && (\r\n <div\r\n className=\"absolute inset-0 flex items-center justify-end pr-pad-md pointer-events-none\"\r\n aria-live=\"polite\"\r\n >\r\n <Loader2\r\n className=\"size-icon-sm text-fg-brand animate-spin\"\r\n aria-label=\"Salvando...\"\r\n />\r\n </div>\r\n )}\r\n {error && !isLoading && (\r\n <div\r\n className=\"absolute inset-y-0 right-pad-md flex items-center pointer-events-none\"\r\n aria-live=\"assertive\"\r\n title={error}\r\n >\r\n <AlertCircle\r\n className=\"size-icon-sm text-fg-danger\"\r\n aria-label={error}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n );\r\n\r\n // Custom editor — consumer controla 100%\r\n if (column.renderEdit) {\r\n return wrap(\r\n column.renderEdit({\r\n row,\r\n value,\r\n onChange: setValue,\r\n onCommit: () => onCommit(value),\r\n onCancel,\r\n }),\r\n );\r\n }\r\n\r\n // Fase G.2 — registry-aware: se o tipo da coluna definir renderEdit, usa ele\r\n const typeDef = column.type ? columnTypeRegistry.get(column.type) : undefined;\r\n if (typeDef?.renderEdit) {\r\n return wrap(\r\n typeDef.renderEdit({\r\n row,\r\n value,\r\n onChange: (v) => setValue(v),\r\n onCommit: () => onCommit(value),\r\n onCancel,\r\n options: column.filterOptions,\r\n }),\r\n );\r\n }\r\n\r\n // Default editor — deriva editType\r\n const editType = resolveEditType(column);\r\n\r\n if (editType === \"select\") {\r\n return wrap(\r\n <SelectEditor\r\n value={value == null ? \"\" : String(value)}\r\n options={column.filterOptions ?? []}\r\n onChange={(v) => {\r\n // Select dispara onValueChange uma vez no commit (nao tem onChange + Enter).\r\n // Commit imediato no select pra UX direta.\r\n setValue(v);\r\n onCommit(v);\r\n }}\r\n onCancel={onCancel}\r\n disabled={isLoading}\r\n />,\r\n );\r\n }\r\n\r\n return wrap(\r\n <InputEditor\r\n type={editType === \"number\" ? \"number\" : \"text\"}\r\n value={value == null ? \"\" : String(value)}\r\n onChange={(v) => setValue(editType === \"number\" ? (v === \"\" ? null : Number(v)) : v)}\r\n onCommit={() => onCommit(value)}\r\n onCancel={onCancel}\r\n disabled={isLoading}\r\n hasError={!!error}\r\n />,\r\n );\r\n}\r\n\r\n/* ── Editor: Input (text/number) ─────────────────────────────────── */\r\n\r\nfunction InputEditor({\r\n type,\r\n value,\r\n onChange,\r\n onCommit,\r\n onCancel,\r\n disabled = false,\r\n hasError = false,\r\n}: {\r\n type: \"text\" | \"number\";\r\n value: string;\r\n onChange: (next: string) => void;\r\n onCommit: () => void;\r\n onCancel: () => void;\r\n disabled?: boolean;\r\n hasError?: boolean;\r\n}) {\r\n const ref = useRef<HTMLInputElement>(null);\r\n\r\n // Auto-focus + select-all no mount\r\n useEffect(() => {\r\n const el = ref.current;\r\n if (!el || disabled) return;\r\n el.focus();\r\n el.select();\r\n }, [disabled]);\r\n\r\n return (\r\n <Input\r\n ref={ref}\r\n type={type}\r\n size=\"xs\"\r\n state={hasError ? \"error\" : \"default\"}\r\n value={value}\r\n disabled={disabled}\r\n onChange={(e) => onChange(e.target.value)}\r\n onKeyDown={(e) => {\r\n if (e.key === \"Enter\") {\r\n e.preventDefault();\r\n onCommit();\r\n } else if (e.key === \"Escape\") {\r\n e.preventDefault();\r\n onCancel();\r\n }\r\n }}\r\n onBlur={() => {\r\n // Durante loading, NAO commitar via blur — usuario pode estar so movendo\r\n // foco temporariamente enquanto a request voa. Commit explicito via Enter\r\n // ja foi disparado e a Promise esta em curso.\r\n if (disabled) return;\r\n // Delay 1 tick pra permitir cliques internos no row (caso usuario\r\n // clique em outra celula durante edicao) terminarem antes do commit.\r\n setTimeout(onCommit, 0);\r\n }}\r\n // Bloqueia bubbling pra TableRow.onClick / dnd / sort\r\n onClick={(e) => e.stopPropagation()}\r\n onPointerDown={(e) => e.stopPropagation()}\r\n onMouseDown={(e) => e.stopPropagation()}\r\n onDoubleClick={(e) => e.stopPropagation()}\r\n className=\"border-0 rounded-radius-sm shadow-none focus-visible:shadow-sh-ring pr-pad-2xl\"\r\n />\r\n );\r\n}\r\n\r\n/* ── Editor: Select ──────────────────────────────────────────────── */\r\n\r\nfunction SelectEditor({\r\n value,\r\n options,\r\n onChange,\r\n onCancel,\r\n disabled = false,\r\n}: {\r\n value: string;\r\n options: Array<{ value: any; label: string }>;\r\n onChange: (next: string) => void;\r\n onCancel: () => void;\r\n disabled?: boolean;\r\n}) {\r\n return (\r\n <div\r\n onClick={(e) => e.stopPropagation()}\r\n onPointerDown={(e) => e.stopPropagation()}\r\n onMouseDown={(e) => e.stopPropagation()}\r\n onDoubleClick={(e) => e.stopPropagation()}\r\n onKeyDown={(e) => {\r\n if (e.key === \"Escape\") {\r\n e.preventDefault();\r\n onCancel();\r\n }\r\n }}\r\n className=\"w-full\"\r\n >\r\n <Select defaultOpen={!disabled} value={value} onValueChange={onChange} disabled={disabled}>\r\n <SelectTrigger className=\"h-form-sm min-h-form-sm rounded-radius-sm\">\r\n <SelectValue placeholder=\"Selecionar...\" />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {options.map((o) => (\r\n <SelectItem key={String(o.value)} value={String(o.value)}>\r\n {o.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n </div>\r\n );\r\n}\r\n\r\n/* ── Helpers ─────────────────────────────────────────────────────── */\r\n\r\nfunction resolveEditType<T>(col: DataTableColumnDef<T>): \"text\" | \"number\" | \"select\" {\r\n if (col.editType) return col.editType;\r\n // Deriva de filterType primeiro (mais especifico que `type`)\r\n if (col.filterType === \"select\" || col.filterType === \"multiSelect\") return \"select\";\r\n if (col.filterType === \"number\") return \"number\";\r\n // Deriva de `type` da coluna\r\n if (col.type === \"number\" || col.type === \"currency\") return \"number\";\r\n if (col.type === \"status\" || col.type === \"boolean\") return \"select\";\r\n return \"text\";\r\n}\r\n","import type { ReactNode } from \"react\";\r\nimport { ChevronRight } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\n/**\r\n * Metadados de hierarquia da row, propagados do `buildTreeRows` até a cell da\r\n * coluna primária. Bundle estável (objeto novo só quando muda) pra não invalidar\r\n * o memo da row sem necessidade.\r\n */\r\nexport type DataTableTreeMeta = {\r\n level: number;\r\n hasChildren: boolean;\r\n isExpanded: boolean;\r\n descendantCount: number;\r\n childCount: number;\r\n};\r\n\r\nexport type DataTableTreeToggleProps = {\r\n meta: DataTableTreeMeta;\r\n /** Conteúdo original da cell (label da coluna primária). */\r\n children: ReactNode;\r\n /** Mostra \"(N)\" descendentes ao lado do label. */\r\n showDescendantCount?: boolean;\r\n /** Toggle expand/collapse do nó. */\r\n onToggle: () => void;\r\n};\r\n\r\n/**\r\n * Prefixo de tree-data na coluna primária: indentação por nível + chevron\r\n * (quando o nó tem filhos) + label + contagem opcional de descendentes.\r\n *\r\n * Indentação: `calc(var(--spacing-pad-2xl) * level)` — usa o token DS\r\n * `pad-2xl` (16px) como unidade por nível, multiplicado inline. Sem hardcode de\r\n * px (a unidade é o CSS var do token; o multiplicador é o nível, um número).\r\n *\r\n * Nós-folha (sem filhos) reservam o mesmo espaço do chevron (`size-icon-sm`)\r\n * pra que os labels alinhem verticalmente independente de ter ou não chevron.\r\n */\r\nexport function DataTableTreeToggle({\r\n meta,\r\n children,\r\n showDescendantCount = false,\r\n onToggle,\r\n}: DataTableTreeToggleProps) {\r\n const { level, hasChildren, isExpanded, descendantCount } = meta;\r\n\r\n return (\r\n <span\r\n className=\"flex items-center gap-gp-xs w-full min-w-0\"\r\n style={{\r\n // Unidade = token DS pad-2xl (16px) via CSS var; multiplicador = nível.\r\n paddingLeft: `calc(var(--spacing-pad-2xl) * ${level})`,\r\n }}\r\n >\r\n {hasChildren ? (\r\n <button\r\n type=\"button\"\r\n aria-label={isExpanded ? \"Recolher\" : \"Expandir\"}\r\n aria-expanded={isExpanded}\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onToggle();\r\n }}\r\n className={cn(\r\n \"shrink-0 flex items-center justify-center\",\r\n \"size-icon-md rounded-radius-sm\",\r\n \"text-fg-muted hover:text-fg-strong hover:bg-bg-muted\",\r\n \"transition-colors duration-150\",\r\n \"focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand\",\r\n )}\r\n >\r\n <ChevronRight\r\n className={cn(\r\n \"size-icon-sm transition-transform duration-150\",\r\n isExpanded && \"rotate-90\",\r\n )}\r\n aria-hidden\r\n />\r\n </button>\r\n ) : (\r\n // Espaçador do tamanho do botão do chevron — mantém labels alinhados.\r\n <span className=\"shrink-0 size-icon-md\" aria-hidden />\r\n )}\r\n <span className=\"flex-1 min-w-0 truncate\">{children}</span>\r\n {showDescendantCount && descendantCount > 0 && (\r\n <span className=\"shrink-0 text-fg-muted tabular-nums text-body-xs\">\r\n ({descendantCount})\r\n </span>\r\n )}\r\n </span>\r\n );\r\n}\r\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * Estilos das add-ons de célula do DataTable (read-more + copy-cell).\r\n * Visual isolado aqui — `data-table-cell-addons.tsx` não carrega classe crua.\r\n */\r\nexport const cellAddonsStyles = tv({\r\n slots: {\r\n /** Wrapper raiz da célula com add-ons — `group` habilita reveal no hover. */\r\n root: \"group/cell-addon flex items-center gap-gp-xs w-full min-w-0\",\r\n /** Texto truncado (1 linha) com reticências. */\r\n truncate: \"min-w-0 flex-1 truncate\",\r\n /** Texto truncado multi-linha (line-clamp via style inline). */\r\n clamp: \"min-w-0 flex-1 overflow-hidden\",\r\n /** Botão \"Ler mais\" inline. */\r\n readMoreBtn:\r\n \"shrink-0 text-fg-brand text-body-xs font-medium hover:underline focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand rounded-radius-sm\",\r\n /** Botão de copiar — revelado no hover/focus da célula. */\r\n copyBtn: [\r\n \"shrink-0 inline-flex items-center justify-center size-icon-md rounded-radius-md\",\r\n \"text-fg-muted hover:text-fg-default hover:bg-bg-muted\",\r\n \"opacity-0 group-hover/cell-addon:opacity-100 focus-visible:opacity-100\",\r\n \"transition-opacity duration-150\",\r\n \"focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand\",\r\n ],\r\n /** Conteúdo do popover do \"Ler mais\". Largura via token semântico\r\n * (tooltip-lg = 320px) — reveal de texto é conceitualmente um tooltip. */\r\n readMorePopover:\r\n \"flex flex-col gap-gp-md p-pad-lg max-w-tooltip-lg text-body-sm text-fg-default whitespace-pre-wrap break-words\",\r\n },\r\n});\r\n","import { useCallback, useRef, useState, type ReactNode } from \"react\";\r\nimport { Check, Copy } from \"lucide-react\";\r\nimport {\r\n Popover,\r\n PopoverTrigger,\r\n PopoverContent,\r\n} from \"@/components/shadcn/popover\";\r\nimport { cellAddonsStyles } from \"./data-table-cell-addons.styles\";\r\n\r\nconst styles = cellAddonsStyles();\r\n\r\n/* ── Read-more ──────────────────────────────────────────────────────── */\r\n\r\nexport type ReadMoreConfig = {\r\n /** Nº de linhas antes de truncar. Default 1 (single-line + reticências). */\r\n lines?: number;\r\n /** Texto do gatilho. Default \"Ler mais\". */\r\n label?: string;\r\n};\r\n\r\nexport type DataTableReadMoreCellProps = {\r\n /** Conteúdo renderizado (a célula base — string ou ReactNode). */\r\n children: ReactNode;\r\n /** Texto puro pro popover + acessibilidade. Default: deriva de `children` se string. */\r\n text?: string;\r\n config: ReadMoreConfig;\r\n};\r\n\r\n/**\r\n * Célula \"Ler mais\" — trunca o conteúdo (1 ou N linhas com reticências) e\r\n * revela o texto completo num popover ao clicar no gatilho. DS-equivalente do\r\n * `ReadMoreCell` legado (que usava tooltip NextUI): aqui usamos `Popover`.\r\n *\r\n * Só mostra o gatilho quando há texto; conteúdo vazio cai no truncate puro.\r\n */\r\nexport function DataTableReadMoreCell({\r\n children,\r\n text,\r\n config,\r\n}: DataTableReadMoreCellProps) {\r\n const lines = config.lines ?? 1;\r\n const fullText =\r\n text ?? (typeof children === \"string\" ? children : undefined);\r\n const hasContent =\r\n fullText != null ? fullText.trim().length > 0 : children != null;\r\n\r\n const truncateNode =\r\n lines > 1 ? (\r\n <span\r\n className={styles.clamp()}\r\n style={{\r\n display: \"-webkit-box\",\r\n WebkitLineClamp: lines,\r\n WebkitBoxOrient: \"vertical\",\r\n }}\r\n >\r\n {children}\r\n </span>\r\n ) : (\r\n <span className={styles.truncate()}>{children}</span>\r\n );\r\n\r\n if (!hasContent) {\r\n return <span className={styles.root()}>{truncateNode}</span>;\r\n }\r\n\r\n return (\r\n <span className={styles.root()}>\r\n {truncateNode}\r\n <Popover>\r\n <PopoverTrigger asChild>\r\n <button\r\n type=\"button\"\r\n className={styles.readMoreBtn()}\r\n onClick={(e) => e.stopPropagation()}\r\n onPointerDown={(e) => e.stopPropagation()}\r\n >\r\n {config.label ?? \"Ler mais\"}\r\n </button>\r\n </PopoverTrigger>\r\n <PopoverContent\r\n align=\"start\"\r\n className=\"p-0\"\r\n onClick={(e) => e.stopPropagation()}\r\n >\r\n <div className={styles.readMorePopover()}>{children}</div>\r\n </PopoverContent>\r\n </Popover>\r\n </span>\r\n );\r\n}\r\n\r\n/* ── Copy-cell ──────────────────────────────────────────────────────── */\r\n\r\n/** Janela (ms) que o feedback \"Copiado!\" fica visível. */\r\nconst COPY_FEEDBACK_MS = 2000;\r\n\r\nexport type CopyableConfig = {\r\n /** Valor copiado pro clipboard. Default: texto da célula. */\r\n value?: string;\r\n /** aria-label do botão. Default \"Copiar\". */\r\n label?: string;\r\n};\r\n\r\nexport type DataTableCopyCellProps = {\r\n children: ReactNode;\r\n /** Texto a copiar (resolvido pelo consumer ou derivado do value). */\r\n copyText: string;\r\n config: CopyableConfig;\r\n};\r\n\r\n/**\r\n * Célula copiável — ícone de copiar revelado no hover/focus da célula, com\r\n * feedback \"Copiado!\" (check) por ~2s. Usa `navigator.clipboard` (sem\r\n * dependência nova). Para o click no botão de borbulhar pra seleção/row click.\r\n */\r\nexport function DataTableCopyCell({\r\n children,\r\n copyText,\r\n config,\r\n}: DataTableCopyCellProps) {\r\n const [copied, setCopied] = useState(false);\r\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n\r\n const handleCopy = useCallback(\r\n (e: React.MouseEvent) => {\r\n e.stopPropagation();\r\n const text = copyText ?? \"\";\r\n const done = () => {\r\n setCopied(true);\r\n if (timerRef.current) clearTimeout(timerRef.current);\r\n timerRef.current = setTimeout(() => setCopied(false), COPY_FEEDBACK_MS);\r\n };\r\n // clipboard API moderna; fallback silencioso se indisponível (http/iframe).\r\n if (navigator.clipboard?.writeText) {\r\n navigator.clipboard.writeText(text).then(done).catch(() => {});\r\n } else {\r\n done();\r\n }\r\n },\r\n [copyText],\r\n );\r\n\r\n const hasContent = copyText != null && copyText.trim().length > 0;\r\n\r\n return (\r\n <span className={styles.root()}>\r\n <span className={styles.truncate()}>{children}</span>\r\n {hasContent && (\r\n <button\r\n type=\"button\"\r\n className={styles.copyBtn()}\r\n aria-label={\r\n copied ? \"Copiado!\" : (config.label ?? \"Copiar\")\r\n }\r\n title={copied ? \"Copiado!\" : (config.label ?? \"Copiar\")}\r\n onClick={handleCopy}\r\n onPointerDown={(e) => e.stopPropagation()}\r\n >\r\n {copied ? (\r\n <Check className=\"size-icon-xs text-fg-success\" aria-hidden />\r\n ) : (\r\n <Copy className=\"size-icon-xs\" aria-hidden />\r\n )}\r\n </button>\r\n )}\r\n </span>\r\n );\r\n}\r\n","import { memo, type ReactNode, type MutableRefObject } from \"react\";\r\nimport { ChevronRight } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { TableRow, TableCell, SELECTION_COLUMN_WIDTH } from \"../../Table\";\r\nimport { Checkbox } from \"@/components/shadcn/checkbox\";\r\nimport { columnTypeRegistry } from \"../column-types\";\r\nimport { applyValueGetter } from \"../utils/resolve-value\";\r\nimport type {\r\n DataTableColumnDef,\r\n FilterValue,\r\n GridRowId,\r\n} from \"../data-table.types\";\r\nimport { DataTableEditCell } from \"./data-table-edit-cell\";\r\nimport { DataTableActionsCell } from \"./data-table-actions-cell\";\r\nimport { DataTableTreeToggle, type DataTableTreeMeta } from \"./data-table-tree-toggle\";\r\nimport {\r\n DataTableReadMoreCell,\r\n DataTableCopyCell,\r\n} from \"./data-table-cell-addons\";\r\n\r\n/**\r\n * Estado de edição inline da row (só não-null pra row com célula em edição).\r\n * Bundled num objeto pra que `isLoading`/`error` não vazem pras outras rows:\r\n * só a row em edição recebe um objeto novo → só ela re-renderiza.\r\n */\r\nexport type DataTableRowEditState = {\r\n field: string;\r\n isLoading: boolean;\r\n error: string | null;\r\n};\r\n\r\n/**\r\n * Handlers da row — passados via REF estável (atualizado a cada render do pai).\r\n * Evita re-render por mudança de identidade de handler (o ref nunca muda) e\r\n * evita stale closures (lê sempre o `.current` mais recente no event time).\r\n */\r\nexport type DataTableRowHandlers<T> = {\r\n getRowId: (row: T) => GridRowId;\r\n onRowClick: (row: T, index: number) => void;\r\n onRowKeyDown: (e: React.KeyboardEvent<HTMLDivElement>, index: number, row: T) => void;\r\n onRowFocus: (index: number) => void;\r\n toggleRowSelection: (row: T) => void;\r\n toggleRowExpansion: (rowId: GridRowId) => void;\r\n /** Toggle expand/collapse de um nó da árvore (modo tree-data). */\r\n toggleTreeNode: (rowId: GridRowId) => void;\r\n startEditingCell: (rowId: GridRowId, field: string) => void;\r\n onCellEditCommit: (params: {\r\n row: T;\r\n field: string;\r\n value: unknown;\r\n oldValue: unknown;\r\n }) => void;\r\n onCellEditCancel: () => void;\r\n registerRef: (index: number, el: HTMLDivElement | null) => void;\r\n};\r\n\r\nexport type DataTableRowProps<T> = {\r\n row: T;\r\n index: number;\r\n rowId: GridRowId;\r\n /* ── Estado reativo da row (comparado pelo memo) ─────────────── */\r\n selected: boolean;\r\n focused: boolean;\r\n expanded: boolean;\r\n /** null quando a row não está em edição; objeto novo só pra row editando. */\r\n editState: DataTableRowEditState | null;\r\n /** Classe da row — computada no pai (getRowClassName) pra o memo comparar. */\r\n rowClassName?: string;\r\n virtualStyle?: React.CSSProperties;\r\n /* ── Dados de render (comparados — mudam → row re-renderiza) ──── */\r\n columns: DataTableColumnDef<T>[];\r\n columnWidths: Record<string, number>;\r\n stickyOffsets: Record<string, number>;\r\n selectionEnabled: boolean;\r\n clickable: boolean;\r\n useRowExpansion: boolean;\r\n expandableColField: string | null;\r\n /* ── Tree-data (modo hierárquico) ─────────────────────────────── */\r\n /** Field da coluna primária da árvore — recebe indentação + chevron. null = sem tree. */\r\n treeColField: string | null;\r\n /** Metadados de hierarquia da row (level/hasChildren/...). null fora do modo tree. */\r\n treeMeta: DataTableTreeMeta | null;\r\n /** Mostra contagem de descendentes \"(N)\" no nó. */\r\n treeShowDescendantCount: boolean;\r\n /* ── Handlers (ref estável — NÃO comparado) ──────────────────── */\r\n handlers: MutableRefObject<DataTableRowHandlers<T>>;\r\n};\r\n\r\nfunction DataTableRowInner<T>({\r\n row,\r\n index,\r\n rowId,\r\n selected,\r\n focused,\r\n expanded,\r\n editState,\r\n rowClassName,\r\n virtualStyle,\r\n columns,\r\n columnWidths,\r\n stickyOffsets,\r\n selectionEnabled,\r\n clickable,\r\n useRowExpansion,\r\n expandableColField,\r\n treeColField,\r\n treeMeta,\r\n treeShowDescendantCount,\r\n handlers,\r\n}: DataTableRowProps<T>) {\r\n return (\r\n <TableRow\r\n ref={(el) => handlers.current.registerRef(index, el)}\r\n selected={selected}\r\n focused={focused}\r\n clickable={clickable}\r\n onClick={() => handlers.current.onRowClick(row, index)}\r\n rootProps={{\r\n onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) =>\r\n handlers.current.onRowKeyDown(e, index, row),\r\n onFocus: () => handlers.current.onRowFocus(index),\r\n style: virtualStyle,\r\n }}\r\n className={rowClassName}\r\n >\r\n {selectionEnabled && (\r\n <TableCell width={SELECTION_COLUMN_WIDTH} align=\"center\" purpose=\"selection\">\r\n <Checkbox\r\n checked={selected}\r\n onCheckedChange={() => handlers.current.toggleRowSelection(row)}\r\n onClick={(e) => e.stopPropagation()}\r\n aria-label=\"Selecionar linha\"\r\n />\r\n </TableCell>\r\n )}\r\n {columns.map((col) => {\r\n const field = String(col.field);\r\n const isActionsCol = col.type === \"actions\";\r\n const value = isActionsCol ? undefined : applyValueGetter(row, col);\r\n const isEditingThisCell = editState?.field === field;\r\n const isEditable = !isActionsCol && col.editable === true;\r\n const isExpandableCol =\r\n useRowExpansion && col.expandable === true && field === expandableColField;\r\n const isTreeCol = treeColField != null && field === treeColField && treeMeta != null;\r\n\r\n // Fallback chain de render:\r\n // 1. edit cell 2. actions 3. col.render 4. registry.renderCell\r\n // 5. col.valueFormatter 6. registry.formatValue 7. raw value\r\n const typeDef = col.type ? columnTypeRegistry.get(col.type) : undefined;\r\n const baseContent = isEditingThisCell\r\n ? (\r\n <DataTableEditCell\r\n column={col}\r\n row={row}\r\n initialValue={value}\r\n isLoading={editState!.isLoading}\r\n error={editState!.error}\r\n onCommit={(newValue) =>\r\n handlers.current.onCellEditCommit({ row, field, value: newValue, oldValue: value })\r\n }\r\n onCancel={handlers.current.onCellEditCancel}\r\n />\r\n )\r\n : isActionsCol && col.getActions && !col.render\r\n ? <DataTableActionsCell row={row} actions={col.getActions({ row })} />\r\n : col.render\r\n ? col.render({ row, value })\r\n : typeDef?.renderCell\r\n ? typeDef.renderCell({\r\n value,\r\n row,\r\n options: col.filterOptions,\r\n column: {\r\n field: String(col.field),\r\n headerName: col.headerName,\r\n valueFormatter: col.valueFormatter,\r\n typeOptions: col.typeOptions,\r\n },\r\n })\r\n : col.valueFormatter\r\n ? col.valueFormatter(value)\r\n : typeDef?.formatValue\r\n ? typeDef.formatValue(value)\r\n : value;\r\n\r\n // Add-ons de célula (read-more / copy). Não aplicam em actions, célula\r\n // em edição nem coluna de árvore (tree gerencia o próprio truncate).\r\n // Texto puro derivado do formatter/value pra popover + clipboard.\r\n const addonsEligible = !isActionsCol && !isEditingThisCell && !isTreeCol;\r\n const plainText =\r\n col.valueFormatter\r\n ? col.valueFormatter(value)\r\n : typeDef?.formatValue\r\n ? typeDef.formatValue(value)\r\n : value != null\r\n ? String(value)\r\n : \"\";\r\n const contentWithAddons =\r\n addonsEligible && col.readMore\r\n ? (\r\n <DataTableReadMoreCell\r\n text={plainText}\r\n config={col.readMore === true ? {} : col.readMore}\r\n >\r\n {baseContent as ReactNode}\r\n </DataTableReadMoreCell>\r\n )\r\n : addonsEligible && col.copyable\r\n ? (() => {\r\n const cfg = col.copyable === true ? {} : col.copyable;\r\n const copyText =\r\n typeof cfg.value === \"function\"\r\n ? cfg.value(row)\r\n : cfg.value ?? plainText;\r\n return (\r\n <DataTableCopyCell\r\n copyText={copyText}\r\n config={{ label: cfg.label }}\r\n >\r\n {baseContent as ReactNode}\r\n </DataTableCopyCell>\r\n );\r\n })()\r\n : (baseContent as ReactNode);\r\n\r\n const content = isTreeCol ? (\r\n <DataTableTreeToggle\r\n meta={treeMeta!}\r\n showDescendantCount={treeShowDescendantCount}\r\n onToggle={() => handlers.current.toggleTreeNode(rowId)}\r\n >\r\n {baseContent as ReactNode}\r\n </DataTableTreeToggle>\r\n ) : isExpandableCol ? (\r\n <span className=\"flex items-center gap-gp-md w-full\">\r\n <ChevronRight\r\n className={cn(\r\n \"shrink-0 size-icon-sm text-fg-muted transition-transform duration-150\",\r\n expanded && \"rotate-90\",\r\n )}\r\n aria-hidden\r\n />\r\n <span className=\"flex-1 min-w-0\">{contentWithAddons}</span>\r\n </span>\r\n ) : (\r\n contentWithAddons\r\n );\r\n const tooltipText =\r\n isActionsCol || isEditingThisCell\r\n ? undefined\r\n : col.ellipsis || !col.render\r\n ? col.valueFormatter\r\n ? col.valueFormatter(value)\r\n : value != null\r\n ? String(value)\r\n : undefined\r\n : undefined;\r\n const cellRootProps: React.HTMLAttributes<HTMLDivElement> | undefined =\r\n isEditable || isExpandableCol\r\n ? {\r\n ...(isEditable && {\r\n onDoubleClick: (e: React.MouseEvent) => {\r\n e.stopPropagation();\r\n handlers.current.startEditingCell(rowId, field);\r\n },\r\n \"data-editable\": \"true\",\r\n }),\r\n ...(isExpandableCol && {\r\n onClick: (e: React.MouseEvent) => {\r\n e.stopPropagation();\r\n handlers.current.toggleRowExpansion(rowId);\r\n },\r\n \"data-expandable\": \"true\",\r\n \"aria-expanded\": expanded,\r\n style: { cursor: \"pointer\" },\r\n }),\r\n }\r\n : undefined;\r\n const effectiveAlign = col.align ?? typeDef?.defaultAlign;\r\n // Tree col + add-ons (read-more/copy) gerenciam o próprio truncate —\r\n // desativa o ellipsis da cell pra não clipar chevron/botão.\r\n const hasAddons =\r\n addonsEligible && (col.readMore != null || col.copyable != null);\r\n const effectiveEllipsis =\r\n isTreeCol || hasAddons\r\n ? false\r\n : (col.ellipsis ?? typeDef?.defaultEllipsis);\r\n return (\r\n <TableCell\r\n key={field}\r\n field={field}\r\n width={columnWidths[field]}\r\n pinned={col.pinned}\r\n pinOffset={stickyOffsets[field]}\r\n align={effectiveAlign}\r\n ellipsis={effectiveEllipsis}\r\n purpose={isActionsCol ? \"actions\" : undefined}\r\n label={col.headerName}\r\n tooltip={tooltipText}\r\n rootProps={cellRootProps}\r\n className={isEditingThisCell ? \"!px-pad-xs !py-0\" : undefined}\r\n >\r\n {content as ReactNode}\r\n </TableCell>\r\n );\r\n })}\r\n </TableRow>\r\n );\r\n}\r\n\r\n/**\r\n * `DataTableRow` — row memoizada. Barreira de re-render: só re-renderiza quando\r\n * suas props reativas mudam (selected/focused/expanded/editState) ou os dados de\r\n * render (columns/widths). Mudanças globais de estado do DataTable (foco em outra\r\n * row, abrir popover, refresh) NÃO repintam rows não-afetadas.\r\n *\r\n * Generics preservados via cast (React.memo perde o param de tipo).\r\n */\r\nexport const DataTableRow = memo(DataTableRowInner) as typeof DataTableRowInner;\r\n","import { ChevronDown, ChevronRight } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport type { DataTableColumnDef } from \"../data-table.types\";\r\nimport type { DataTableGroupRow } from \"../utils/group-rows\";\r\nimport { renderAggregate } from \"../utils/aggregate\";\r\n\r\nexport type DataTableGroupHeaderRowProps<T> = {\r\n group: DataTableGroupRow<T>;\r\n /** Colunas efetivas (visíveis) — usado pra renderizar subtotalizers inline. */\r\n columns: DataTableColumnDef<T>[];\r\n columnWidths: Record<string, number>;\r\n stickyOffsets: Record<string, number>;\r\n hasSelection?: boolean;\r\n /** Click no chevron — toggle expand/collapse. */\r\n onToggle: () => void;\r\n /** Style inline pra virtualização (position absolute + transform). */\r\n style?: React.CSSProperties;\r\n /** Override do conteúdo — quando passado, substitui o layout default\r\n * (chevron + label + count + subtotalizers nas cells) por ReactNode livre\r\n * ocupando a row inteira. Mantém o click handler do toggle no wrapper. */\r\n renderHeader?: (params: {\r\n group: {\r\n key: string;\r\n field: string;\r\n value: unknown;\r\n label: string;\r\n count: number;\r\n isExpanded: boolean;\r\n };\r\n toggle: () => void;\r\n }) => React.ReactNode;\r\n};\r\n\r\n/**\r\n * Header row de um grupo. Span full-width, mostra:\r\n * - Chevron clicável (▶/▼)\r\n * - Label do grupo (valor formatado via column.valueFormatter)\r\n * - Count badge \"(N)\"\r\n * - Subtotalizers inline para colunas com `aggregate` (alinhados às cells)\r\n *\r\n * Sticky lateral é preservado pra colunas pinned (o chevron + label moram na\r\n * primeira cell não-pinned, demais cells renderizam aggregate se houver).\r\n */\r\nexport function DataTableGroupHeaderRow<T>({\r\n group,\r\n columns,\r\n columnWidths,\r\n stickyOffsets,\r\n hasSelection = false,\r\n onToggle,\r\n style,\r\n renderHeader,\r\n}: DataTableGroupHeaderRowProps<T>) {\r\n const ChevronIcon = group.isExpanded ? ChevronDown : ChevronRight;\r\n\r\n // Override: free-form render ocupando full row, sem alinhamento de colunas.\r\n if (renderHeader) {\r\n return (\r\n <div\r\n role=\"row\"\r\n data-group-header=\"true\"\r\n data-group-key={group.key}\r\n aria-expanded={group.isExpanded}\r\n style={style}\r\n className={cn(\r\n \"flex w-full min-w-full\",\r\n \"bg-bg-subtle\",\r\n \"border-b border-border-table\",\r\n \"transition-colors duration-150\",\r\n // Sticky horizontal: free-form header gruda no left=0 e ocupa\r\n // viewport width pra não ser cortado por scroll horizontal.\r\n \"sticky left-0\",\r\n )}\r\n >\r\n {renderHeader({\r\n group: {\r\n key: group.key,\r\n field: group.field,\r\n value: group.value,\r\n label: group.label,\r\n count: group.count,\r\n isExpanded: group.isExpanded,\r\n },\r\n toggle: onToggle,\r\n })}\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n role=\"row\"\r\n data-group-header=\"true\"\r\n data-group-key={group.key}\r\n aria-expanded={group.isExpanded}\r\n style={style}\r\n className={cn(\r\n \"flex w-max min-w-full h-[42px]\",\r\n \"bg-bg-subtle hover:bg-bg-muted\",\r\n \"border-b border-border-table\",\r\n \"cursor-pointer select-none\",\r\n \"transition-colors duration-150\",\r\n )}\r\n onClick={onToggle}\r\n >\r\n {hasSelection && (\r\n <div className=\"shrink-0 w-[56px] h-[42px]\" />\r\n )}\r\n {columns.map((col, idx) => {\r\n const field = String(col.field);\r\n const width = columnWidths[field];\r\n const isPinned = col.pinned === \"left\" || col.pinned === \"right\";\r\n // Cell style (width + sticky offsets quando pinned)\r\n const cellStyle: React.CSSProperties = {\r\n width,\r\n minWidth: width,\r\n maxWidth: width,\r\n };\r\n if (isPinned && stickyOffsets[field] !== undefined) {\r\n if (col.pinned === \"left\") cellStyle.left = stickyOffsets[field];\r\n if (col.pinned === \"right\") cellStyle.right = stickyOffsets[field];\r\n }\r\n // Primeira cell não-pinned (ou primeira cell se nenhuma pinned-left)\r\n // recebe chevron + label + count. Demais recebem aggregate se definido.\r\n const isFirstNonPinnedLeft =\r\n idx === columns.findIndex((c) => c.pinned !== \"left\");\r\n\r\n return (\r\n <div\r\n key={field}\r\n data-field={field}\r\n className={cn(\r\n \"shrink-0 flex items-center px-pad-2xl gap-gp-md\",\r\n \"text-body-md font-medium text-fg-strong\",\r\n isPinned && \"sticky z-[5] bg-bg-subtle\",\r\n )}\r\n style={cellStyle}\r\n >\r\n {isFirstNonPinnedLeft ? (\r\n <>\r\n <ChevronIcon\r\n className=\"shrink-0 size-icon-sm text-fg-muted transition-transform\"\r\n aria-hidden\r\n />\r\n <span className=\"truncate\">{group.label}</span>\r\n <span className=\"text-fg-muted tabular-nums\">\r\n ({group.count})\r\n </span>\r\n </>\r\n ) : col.aggregate ? (\r\n <GroupAggregate column={col} rows={group.rows} />\r\n ) : null}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n );\r\n}\r\n\r\n/* ── Subtotalizer inline — reusa logica do TotalizerRow ──────────── */\r\n\r\nfunction GroupAggregate<T>({\r\n column,\r\n rows,\r\n}: {\r\n column: DataTableColumnDef<T>;\r\n rows: T[];\r\n}) {\r\n const content = renderAggregate(column, rows);\r\n if (content == null || content === \"\") return null;\r\n return <span className=\"text-fg-muted\">{content}</span>;\r\n}\r\n","import type { ReactNode } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport type { DataTableGroupRow } from \"../utils/group-rows\";\n\nexport type DataTableGroupContentRowProps<T> = {\n group: DataTableGroupRow<T>;\n /** Render do consumer — recebe `group` (incluindo `rows`) e devolve qualquer ReactNode. */\n render: (params: {\n group: {\n key: string;\n field: string;\n value: unknown;\n label: string;\n count: number;\n rows: T[];\n };\n }) => ReactNode;\n /** Style inline pra virtualização. */\n style?: React.CSSProperties;\n};\n\n/**\n * Slot de conteúdo livre do grupo — substitui as N child TableRows quando\n * consumer passa renderGroupContent. Ocupa row inteira (não alinhado a colunas),\n * sticky left=0 pra não ser cortado por scroll horizontal da tabela principal.\n *\n * Use cases: sub-tabela com colunas diferentes, lista compacta, cards, gráficos,\n * qualquer composição que o consumer queira dentro do grupo expandido.\n *\n * Trade-off com virtualização: tanstack/react-virtual usa `estimateRowHeight`\n * fixo. Se o conteúdo customizado tem altura variável, virtualização pode\n * sub/super estimar — passe `estimateRowHeight` adequado ao seu conteúdo,\n * ou desligue virtualize quando renderGroupContent estiver ativo.\n */\nexport function DataTableGroupContentRow<T>({\n group,\n render,\n style,\n}: DataTableGroupContentRowProps<T>) {\n return (\n <div\n role=\"row\"\n data-group-content=\"true\"\n data-group-key={group.key}\n style={style}\n className={cn(\n \"flex w-full min-w-full\",\n \"bg-bg-table\",\n \"border-b border-border-table\",\n // Sticky horizontal: gruda no left=0 do viewport pra ocupar área visível\n // independente do scroll horizontal da tabela.\n \"sticky left-0\",\n )}\n >\n {render({\n group: {\n key: group.key,\n field: group.field,\n value: group.value,\n label: group.label,\n count: group.count,\n rows: group.rows,\n },\n })}\n </div>\n );\n}\n","import type { DataTableColumnDef } from \"../data-table.types\";\nimport { applyValueGetter } from \"./resolve-value\";\n\n/** Marker symbol pra distinguir GroupRow de data row T no render branching.\n * Pattern symbol-as-discriminator evita conflito acidental com props do T. */\nexport const GROUP_ROW_TYPE = Symbol(\"dt-group-row\");\n\n/** Marker symbol pra \"slot de conteúdo customizado do grupo\" — quando consumer\n * passa renderGroupContent, esse marker substitui as N child rows por 1 row\n * full-width que delega 100% pro render do consumer. */\nexport const GROUP_CONTENT_TYPE = Symbol(\"dt-group-content\");\n\n/** Row sintética inserida no array antes de cada grupo. */\nexport type DataTableGroupRow<T = unknown> = {\n __type: typeof GROUP_ROW_TYPE;\n /** Field usado pra agrupar (== props.groupBy). */\n field: string;\n /** Valor raw do grupo (ex: \"active\", \"inactive\"). */\n value: unknown;\n /** Label formatado pra display (passa por column.valueFormatter se houver). */\n label: string;\n /** Quantidade de rows nesse grupo. */\n count: number;\n /** Rows do grupo — usado pra subtotalizers + selectGroup. */\n rows: T[];\n /** Está expandido? Se false, child rows são skipped do array. */\n isExpanded: boolean;\n /** Chave unica do grupo — `${field}|${value}` */\n key: string;\n};\n\n/** \"Content slot\" marker — substitui as child rows quando consumer passa\n * renderGroupContent. Carrega referência ao group pra que o consumer tenha\n * acesso a label/count/rows no callback. */\nexport type DataTableGroupContent<T = unknown> = {\n __type: typeof GROUP_CONTENT_TYPE;\n /** Mesma key do group pai. */\n key: string;\n /** Referência ao group pai (label, count, rows). */\n group: DataTableGroupRow<T>;\n};\n\n/** Type guard pra GroupRow. */\nexport function isGroupRow<T>(\n row: T | DataTableGroupRow<T> | DataTableGroupContent<T>,\n): row is DataTableGroupRow<T> {\n return (\n row != null &&\n typeof row === \"object\" &&\n \"__type\" in row &&\n (row as { __type: symbol }).__type === GROUP_ROW_TYPE\n );\n}\n\n/** Type guard pra GroupContent (slot custom). */\nexport function isGroupContent<T>(\n row: T | DataTableGroupRow<T> | DataTableGroupContent<T>,\n): row is DataTableGroupContent<T> {\n return (\n row != null &&\n typeof row === \"object\" &&\n \"__type\" in row &&\n (row as { __type: symbol }).__type === GROUP_CONTENT_TYPE\n );\n}\n\n// resolveGroupValue agora delega pro shared `applyValueGetter` (utils/resolve-value.ts).\n// Quando `col` não existe (field sem ColumnDef), usa stub minimal pra reaproveitar.\n\n/**\n * Reshape do array de rows em (GroupRow | T)[] alternados.\n *\n * Ordem: groups aparecem na ordem da primeira ocorrencia (não sortado por label).\n * Pra ordem específica, consumer pode passar rows já ordenadas pelo group field.\n *\n * Rows com value `undefined`/`null` no field caem no grupo \"(sem valor)\".\n *\n * @param rows Rows já filtradas/buscadas/ordenadas (output do processor)\n * @param field Campo de agrupamento (== props.groupBy)\n * @param expandedKeys Set de keys de grupos expandidos\n * @param defaultExpanded Quando grupo NÃO está em expandedKeys, este é o estado default\n * @param col Column def do field — usada pra valueGetter e valueFormatter\n */\nexport function groupRows<T>(\n rows: T[],\n field: string,\n expandedKeys: Set<string>,\n defaultExpanded: boolean,\n col: DataTableColumnDef<T> | undefined,\n /** Quando true, substitui as N child rows por 1 GroupContent marker.\n * Consumer renderiza conteúdo livre via renderGroupContent. */\n useCustomContent = false,\n): Array<DataTableGroupRow<T> | DataTableGroupContent<T> | T> {\n const groupsMap = new Map<string, { value: unknown; rows: T[] }>();\n\n // Stub minimal pra reusar applyValueGetter quando col não existe (field órfão).\n const colOrStub = (col ?? {\n field,\n headerName: \"\",\n }) as DataTableColumnDef<T>;\n\n for (const row of rows) {\n const rawValue = applyValueGetter(row, colOrStub);\n const key = `${field}|${rawValue ?? \"__null__\"}`;\n if (!groupsMap.has(key)) {\n groupsMap.set(key, { value: rawValue, rows: [] });\n }\n groupsMap.get(key)!.rows.push(row);\n }\n\n const result: Array<DataTableGroupRow<T> | DataTableGroupContent<T> | T> = [];\n for (const [key, group] of groupsMap.entries()) {\n // Resolve label via valueFormatter da coluna, senão toString do valor\n const labelRaw =\n group.value == null || group.value === \"\"\n ? \"(sem valor)\"\n : col?.valueFormatter\n ? col.valueFormatter(group.value)\n : String(group.value);\n\n // Default expanded a menos que key esteja explicitamente collapsada\n // (toggle inverte do default). Tracking via Set de keys que diferem do default.\n const isExpanded = expandedKeys.has(key) ? !defaultExpanded : defaultExpanded;\n\n const groupRow: DataTableGroupRow<T> = {\n __type: GROUP_ROW_TYPE,\n field,\n value: group.value,\n label: labelRaw,\n count: group.rows.length,\n rows: group.rows,\n isExpanded,\n key,\n };\n result.push(groupRow);\n if (isExpanded) {\n if (useCustomContent) {\n // 1 slot custom no lugar das N rows — consumer decide o render\n result.push({\n __type: GROUP_CONTENT_TYPE,\n key,\n group: groupRow,\n });\n } else {\n // Default: N TableRows iguais a uma tabela normal\n result.push(...group.rows);\n }\n }\n }\n return result;\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type DataTableRowExpansionProps<T> = {\n row: T;\n render: (params: { row: T }) => ReactNode;\n /** Style inline pra virtualização. */\n style?: React.CSSProperties;\n};\n\n/**\n * Slot expandido abaixo de uma row — full-width, sticky-left no eixo horizontal.\n *\n * Não respeita estrutura de colunas da tabela. Consumer pode renderizar:\n * - Sub-tabela com colunas próprias\n * - Lista compacta de campos (key/value)\n * - Cards de detalhe\n * - Gráficos, timeline, qualquer coisa\n *\n * `sticky left-0` garante que o conteúdo fica visível mesmo quando há scroll\n * horizontal na tabela principal (cells da row vão pra direita, mas o\n * expansion permanece ancorado no viewport).\n *\n * Trade-off com virtualize: `estimateRowHeight` é fixo. Se conteúdo expandido\n * tem altura variável grande, virtualização pode sub/super estimar — passe\n * `estimateRowHeight` adequado ou desligue virtualize.\n */\nexport function DataTableRowExpansion<T>({\n row,\n render,\n style,\n}: DataTableRowExpansionProps<T>) {\n return (\n <div\n role=\"row\"\n data-row-expansion=\"true\"\n style={style}\n className={cn(\n \"flex w-full min-w-full\",\n \"bg-bg-subtle\",\n \"border-b border-border-table\",\n // Sticky horizontal pra ocupar viewport visível, não cortar no scroll-X\n \"sticky left-0\",\n )}\n >\n {render({ row })}\n </div>\n );\n}\n","import type { GridRowId } from \"../data-table.types\";\n\n/** Marker pra \"row expansion\" — substitui ou se intercala com data rows.\n * Symbol-as-discriminator pra evitar conflito com props do T. */\nexport const ROW_EXPANSION_TYPE = Symbol(\"dt-row-expansion\");\n\nexport type DataTableRowExpansionItem<T = unknown> = {\n __type: typeof ROW_EXPANSION_TYPE;\n /** ID da row que está expandida (== getRowId(row)). */\n id: GridRowId;\n /** Referência à row pai pra que o render do consumer tenha acesso. */\n row: T;\n};\n\n/** Type guard pra ExpansionRow. Aceita union ampla (T | GroupRow | GroupContent | etc)\n * pra coexistir com outras transformações no mesmo array. */\nexport function isExpansionRow<T>(\n item: unknown,\n): item is DataTableRowExpansionItem<T> {\n return (\n item != null &&\n typeof item === \"object\" &&\n \"__type\" in item &&\n (item as { __type: symbol }).__type === ROW_EXPANSION_TYPE\n );\n}\n\n/**\n * Reshape do array de rows pra incluir markers de expansão.\n * Após cada row que tem ID em `expandedIds`, insere 1 marker de expansão.\n *\n * Resultado é um array misto `(T | DataTableRowExpansionItem<T>)[]` — o render\n * faz branching via `isExpansionRow` type guard. Virtualizer recebe esse array\n * direto e calcula scroll height baseado em count.\n *\n * Quando `expandedIds` vazia ou nenhum row match, retorna o array original\n * (referência preservada pra evitar re-renders desnecessários).\n */\nexport function expandRows<T>(\n rows: T[],\n expandedIds: Set<GridRowId>,\n getRowId: (row: T) => GridRowId,\n): Array<T | DataTableRowExpansionItem<T>> {\n if (expandedIds.size === 0) return rows;\n let hasAnyMatch = false;\n for (const row of rows) {\n if (expandedIds.has(getRowId(row))) {\n hasAnyMatch = true;\n break;\n }\n }\n if (!hasAnyMatch) return rows;\n\n const result: Array<T | DataTableRowExpansionItem<T>> = [];\n for (const row of rows) {\n result.push(row);\n const id = getRowId(row);\n if (expandedIds.has(id)) {\n result.push({ __type: ROW_EXPANSION_TYPE, id, row });\n }\n }\n return result;\n}\n","import { useMemo } from \"react\";\nimport type {\n SortPopoverColumn,\n SortPopoverCriterion,\n} from \"../../TableToolbar\";\nimport type { DataTableColumnDef, SortModel } from \"../data-table.types\";\n\nexport type UseSortPopoverAdapterParams<T> = {\n effectiveColumns: DataTableColumnDef<T>[];\n sortModels: SortModel[];\n setSortModels: (models: SortModel[]) => void;\n};\n\nexport type UseSortPopoverAdapterResult = {\n /** Colunas filtradas (sem actions, sortable !== false) no formato do SortPopover. */\n sortPopoverColumns: SortPopoverColumn[];\n /** Critérios atuais (field + dir) — mapeado de sortModels. */\n sortPopoverCriteria: SortPopoverCriterion[];\n /** Handler que converte critérios do popover → setSortModels. */\n handleSortChange: (criteria: SortPopoverCriterion[]) => void;\n};\n\n/**\n * Adapter: ColumnDef + SortModel ↔ SortPopover props.\n *\n * Extraído do data-table.tsx pra isolar a tradução entre tipos do TableToolbar\n * e tipos do DataTable. Filtra colunas não-sortables (type === \"actions\" ou\n * sortable === false) — só aparecem no popover as que fazem sentido.\n */\nexport function useSortPopoverAdapter<T>({\n effectiveColumns,\n sortModels,\n setSortModels,\n}: UseSortPopoverAdapterParams<T>): UseSortPopoverAdapterResult {\n const sortPopoverColumns = useMemo<SortPopoverColumn[]>(\n () =>\n effectiveColumns\n .filter((c) => c.type !== \"actions\" && c.sortable !== false)\n .map((c) => ({\n key: String(c.field),\n label: c.headerName,\n icon: c.icon,\n })),\n [effectiveColumns],\n );\n\n const sortPopoverCriteria = useMemo<SortPopoverCriterion[]>(\n () => sortModels.map((s) => ({ key: s.field, dir: s.direction })),\n [sortModels],\n );\n\n const handleSortChange = (criteria: SortPopoverCriterion[]) => {\n setSortModels(criteria.map((c) => ({ field: c.key, direction: c.dir })));\n };\n\n return {\n sortPopoverColumns,\n sortPopoverCriteria,\n handleSortChange,\n };\n}\n","import { useMemo } from \"react\";\nimport type { ColsPopoverColumn } from \"../../TableToolbar\";\nimport type { ColumnPinned } from \"../../Table\";\nimport type { DataTableColumnDef } from \"../data-table.types\";\n\nexport type UseColsPopoverAdapterParams<T> = {\n columns: DataTableColumnDef<T>[];\n hiddenColumns: Set<string>;\n pinnedColumns: Record<string, ColumnPinned>;\n handleShow: (field: string) => void;\n handleHide: (field: string) => void;\n handlePin: (field: string, side: ColumnPinned) => void;\n handleReorder: (order: string[]) => void;\n};\n\nexport type UseColsPopoverAdapterResult = {\n /** Colunas no formato do ColsPopover (sem actions). */\n colsPopoverColumns: ColsPopoverColumn[];\n /** Set de fields visíveis (calculado de hiddenColumns). */\n visibleColsSet: Set<string>;\n /** Set de fields pinned (left ou right). */\n pinnedColsSet: Set<string>;\n /** Aplica toggle de visibilidade — converte Set → handleShow/handleHide. */\n handleVisibleChange: (next: Set<string>) => void;\n /** Aplica toggle de pin — converte Set → handlePin(\"left\"/undefined). */\n handlePinnedChange: (next: Set<string>) => void;\n /** Reordena colunas via dnd interno do popover. */\n handleColumnsReorder: (reordered: ColsPopoverColumn[]) => void;\n};\n\n/**\n * Adapter: ColumnDef + visibility/pin state ↔ ColsPopover props.\n *\n * Extraído do data-table.tsx pra isolar a tradução entre o popover de colunas\n * (que trabalha com Sets de keys) e o estado interno do DataTable (que usa\n * `Set<hiddenColumns>` + `Record<field, \"left\"|\"right\">`).\n */\nexport function useColsPopoverAdapter<T>({\n columns,\n hiddenColumns,\n pinnedColumns,\n handleShow,\n handleHide,\n handlePin,\n handleReorder,\n}: UseColsPopoverAdapterParams<T>): UseColsPopoverAdapterResult {\n const colsPopoverColumns = useMemo<ColsPopoverColumn[]>(\n () =>\n columns\n // Coluna actions é estrutural — não aparece no popover de visibilidade.\n .filter((c) => c.type !== \"actions\")\n .map((c) => ({\n key: String(c.field),\n label: c.headerName,\n icon: c.icon,\n })),\n [columns],\n );\n\n const visibleColsSet = useMemo<Set<string>>(\n () =>\n new Set(\n columns\n .map((c) => String(c.field))\n .filter((f) => !hiddenColumns.has(f)),\n ),\n [columns, hiddenColumns],\n );\n\n const pinnedColsSet = useMemo<Set<string>>(\n () =>\n new Set(\n Object.entries(pinnedColumns)\n .filter(([, pin]) => pin === \"left\" || pin === \"right\")\n .map(([field]) => field),\n ),\n [pinnedColumns],\n );\n\n const handleVisibleChange = (next: Set<string>) => {\n const allFields = columns.map((c) => String(c.field));\n for (const f of allFields) {\n if (next.has(f) && hiddenColumns.has(f)) {\n handleShow(f);\n } else if (!next.has(f) && !hiddenColumns.has(f)) {\n handleHide(f);\n }\n }\n };\n\n const handlePinnedChange = (next: Set<string>) => {\n const allFields = columns.map((c) => String(c.field));\n for (const f of allFields) {\n const isPinned =\n pinnedColumns[f] === \"left\" || pinnedColumns[f] === \"right\";\n if (next.has(f) && !isPinned) {\n handlePin(f, \"left\");\n } else if (!next.has(f) && isPinned) {\n handlePin(f, undefined);\n }\n }\n };\n\n const handleColumnsReorder = (reordered: ColsPopoverColumn[]) => {\n handleReorder(reordered.map((c) => c.key));\n };\n\n return {\n colsPopoverColumns,\n visibleColsSet,\n pinnedColsSet,\n handleVisibleChange,\n handlePinnedChange,\n handleColumnsReorder,\n };\n}\n","import { useMemo } from \"react\";\r\nimport type { ReactNode } from \"react\";\r\nimport type {\r\n AppliedFilter,\r\n FilterPopoverColumn,\r\n FilterPopoverEntry,\r\n} from \"../../TableToolbar\";\r\nimport { columnTypeRegistry } from \"../column-types\";\r\nimport type { ColumnOption } from \"../column-types\";\r\nimport type {\r\n DataTableColumnDef,\r\n FilterItem,\r\n FilterModel,\r\n} from \"../data-table.types\";\r\nimport {\r\n MULTI_VALUE_OPERATORS,\r\n genFilterId,\r\n filterValueIsEmpty as isFilterValueEmpty,\r\n promoteOperatorForColumn,\r\n} from \"../utils/filter-ops\";\r\n\r\nexport type FilterGroup<T> = {\r\n key: string;\r\n field: string;\r\n operator: FilterItem[\"operator\"];\r\n items: FilterItem[];\r\n};\r\n\r\nexport type UseFilterPopoverAdapterParams<T> = {\r\n /** Colunas efetivas pós hidden/order. */\r\n effectiveColumns: DataTableColumnDef<T>[];\r\n /** ColumnDef props originais — usado pra options de filtros. */\r\n allColumns: DataTableColumnDef<T>[];\r\n /** Rows (client mode) pra auto-extract options de select. */\r\n rows: T[] | undefined;\r\n /** FilterModel atual + setter. */\r\n filterModel: FilterModel;\r\n setFilterModel: (model: FilterModel) => void;\r\n /** Map de field → DataTableColumnDef (memoized externamente pra evitar dupla criação). */\r\n colsByField: Map<string, DataTableColumnDef<T>>;\r\n /** Map de field → label do header. */\r\n colLabelMap: Record<string, string>;\r\n /** Chave de chip pendente de abertura — pra incluir items vazios renderizando \"phantom chip\". */\r\n pendingOpenChipKey: string | null;\r\n};\r\n\r\nexport type UseFilterPopoverAdapterResult<T> = {\r\n filterPopoverColumns: FilterPopoverColumn[];\r\n filterPopoverEntries: FilterPopoverEntry[];\r\n appliedGroups: FilterGroup<T>[];\r\n appliedFilters: AppliedFilter[];\r\n removeGroup: (groupKey: string) => void;\r\n updateGroupValue: (groupKey: string, newValue: unknown) => void;\r\n getGroupOptions: (groupKey: string) => ColumnOption[];\r\n handleFiltersChange: (entries: FilterPopoverEntry[]) => void;\r\n isFilterValueEmpty: (v: unknown) => boolean;\r\n};\r\n\r\n/**\r\n * Adapter completo: ColumnDef + FilterModel ↔ FilterPopover/ToolbarApplied props.\r\n *\r\n * Encapsula a tradução entre o estado do DataTable (FilterModel.items lista flat)\r\n * e o estado visual do TableToolbar (chips agrupados por field+operator). Mantém\r\n * regras importantes:\r\n * - \"Phantom chip\" (item vazio renderiza chip se `pendingOpenChipKey` casa) pra\r\n * que o filter shortcut do header tenha popover âncora válido.\r\n * - `between` (tupla) → 1 item single com value=tupla; demais → spread em N items.\r\n * - `renderChipValue` do registry vence labelOf padrão.\r\n * - Items vazios filtrados na renderização normal (sem polluir o toolbar).\r\n */\r\nexport function useFilterPopoverAdapter<T>({\r\n effectiveColumns,\r\n allColumns,\r\n rows,\r\n filterModel,\r\n setFilterModel,\r\n colsByField,\r\n colLabelMap,\r\n pendingOpenChipKey,\r\n}: UseFilterPopoverAdapterParams<T>): UseFilterPopoverAdapterResult<T> {\r\n const filterPopoverColumns = useMemo<FilterPopoverColumn[]>(\r\n () =>\r\n effectiveColumns\r\n .filter((c) => c.enableColumnFilter)\r\n .map((c) => {\r\n let popoverType: FilterPopoverColumn[\"type\"] = \"text\";\r\n if (c.filterType === \"number\") popoverType = \"number\";\r\n else if (c.filterType === \"select\" || c.filterType === \"multiSelect\") {\r\n popoverType = \"select\";\r\n }\r\n let options = c.filterOptions?.map((o) => ({\r\n value: String(o.value),\r\n label: o.label,\r\n }));\r\n if (popoverType === \"select\" && (!options || options.length === 0) && rows) {\r\n const set = new Set<string>();\r\n for (const r of rows) {\r\n const v = c.valueGetter\r\n ? c.valueGetter(r)\r\n : (r as Record<string, unknown>)[String(c.field)];\r\n if (v != null && v !== \"\") set.add(String(v));\r\n }\r\n options = Array.from(set).map((v) => ({ value: v, label: v }));\r\n }\r\n return {\r\n key: String(c.field),\r\n label: c.headerName,\r\n type: popoverType,\r\n options,\r\n filterType: c.filterType,\r\n };\r\n }),\r\n [effectiveColumns, rows],\r\n );\r\n\r\n const filterPopoverEntries = useMemo<FilterPopoverEntry[]>(() => {\r\n // 1ª passada: coletar items por chave multi (field|operator)\r\n const multiGroups = new Map<string, FilterItem[]>();\r\n for (const item of filterModel.items) {\r\n if (MULTI_VALUE_OPERATORS.has(item.operator)) {\r\n const key = `${item.field}|${item.operator}`;\r\n if (!multiGroups.has(key)) multiGroups.set(key, []);\r\n multiGroups.get(key)!.push(item);\r\n }\r\n }\r\n\r\n // 2ª passada: emitir entries NA ORDEM ORIGINAL do filterModel.\r\n // Multi groups são emitidos UMA vez, na posição do primeiro item do grupo\r\n // (preserva visual position quando user toggla valores). Sem isso, multi\r\n // groups eram empurrados pro fim e o chip pulava de posição ao editar.\r\n const seenMultiKeys = new Set<string>();\r\n const result: FilterPopoverEntry[] = [];\r\n for (const item of filterModel.items) {\r\n if (MULTI_VALUE_OPERATORS.has(item.operator)) {\r\n const key = `${item.field}|${item.operator}`;\r\n if (seenMultiKeys.has(key)) continue;\r\n seenMultiKeys.add(key);\r\n const groupItems = multiGroups.get(key)!;\r\n result.push({\r\n // ⚠️ ID ESTÁVEL = `${field}|${operator}` (não groupItems[0].id que\r\n // muda a cada spread no handleFiltersChange). Sem isso, key do\r\n // FilterRowEditor mudava → unmount/remount → Popover interno do\r\n // MultiSelectFieldDropdown perdia state e FECHAVA a cada toggle.\r\n id: key,\r\n columnKey: groupItems[0].field,\r\n // Vocabulário único: op em id longo do FilterModel (\"equals\", \"neq\"…)\r\n // em todo o fluxo — sem tradução curto↔longo. Os CHIPS resolvem o\r\n // LABEL via `opLabel` (registry do column-type), com DEFAULT_OP_LABELS\r\n // (também ids longos) como fallback.\r\n op: groupItems[0].operator,\r\n value: groupItems\r\n .map((it) => it.value)\r\n .filter((v) => v != null && v !== \"\"),\r\n });\r\n } else {\r\n result.push({\r\n id: item.id,\r\n columnKey: item.field,\r\n op: item.operator,\r\n value: item.value ?? \"\",\r\n });\r\n }\r\n }\r\n\r\n return result;\r\n }, [filterModel]);\r\n\r\n const appliedGroups = useMemo<FilterGroup<T>[]>(() => {\r\n const grouped = new Map<string, FilterItem[]>();\r\n for (const item of filterModel.items) {\r\n const key = `${item.field}|${item.operator}`;\r\n const isEmpty = isFilterValueEmpty(item.value);\r\n // Items vazios são pulados — exceção: pending pra abrir popover (filter shortcut)\r\n if (isEmpty && key !== pendingOpenChipKey) continue;\r\n if (!grouped.has(key)) grouped.set(key, []);\r\n grouped.get(key)!.push(item);\r\n }\r\n return Array.from(grouped.entries()).map(([key, items]) => ({\r\n key,\r\n field: items[0].field,\r\n operator: items[0].operator,\r\n items,\r\n }));\r\n }, [filterModel, pendingOpenChipKey]);\r\n\r\n const appliedFilters = useMemo<AppliedFilter[]>(\r\n () =>\r\n appliedGroups.map((g) => {\r\n const col = colsByField.get(g.field);\r\n const columnLabel = colLabelMap[g.field] ?? g.field;\r\n\r\n // Label do operador resolvido pelo REGISTRY do tipo da coluna — fonte\r\n // única, casa com o que o popover mostra (ex: currency `gt` = \"maior que\",\r\n // não \">\"). ToolbarApplied usa `opLabel` quando presente; senão cai no\r\n // DEFAULT_OP_LABELS (fallback genérico pra uso standalone).\r\n const typeId = col?.filterType ?? col?.type ?? \"text\";\r\n const typeDef = columnTypeRegistry.get(typeId);\r\n const opLabel = typeDef.operators?.find((o) => o.id === g.operator)?.label;\r\n\r\n // Chip placeholder: grupo cujos items todos têm value vazio.\r\n // Acontece em 2 cenários:\r\n // 1) Filter shortcut do header (chip \"fantasma\" via pendingOpenChipKey)\r\n // 2) showEmptyFilterChips=true com filterModel pré-ativos vazios\r\n // ToolbarApplied usa isEmpty pra renderizar apenas o columnLabel.\r\n const allItemsEmpty = g.items.every((it) => isFilterValueEmpty(it.value));\r\n if (allItemsEmpty) {\r\n return {\r\n id: g.key,\r\n columnLabel,\r\n op: g.operator,\r\n opLabel,\r\n value: [],\r\n isEmpty: true,\r\n };\r\n }\r\n\r\n const labelOf = (v: unknown): string => {\r\n const opt = col?.filterOptions?.find(\r\n (o) => String(o.value) === String(v),\r\n );\r\n return opt?.label ?? String(v);\r\n };\r\n\r\n if (typeDef.renderChipValue && g.items.length > 0) {\r\n // Passa options pro renderChipValue resolver value → label friendly.\r\n // Sem isso, o chip mostrava o RAW value (ex: \"active\" em vez de \"Ativo\").\r\n const chipOptions = col?.filterOptions as ColumnOption[] | undefined;\r\n const chipValues = g.items.map((it) =>\r\n typeDef.renderChipValue!(it.value as never, chipOptions),\r\n );\r\n const filteredChips = chipValues.filter(\r\n (v) => v != null && v !== \"\",\r\n );\r\n const value: ReactNode | ReactNode[] =\r\n filteredChips.length === 1\r\n ? filteredChips[0]\r\n : filteredChips.length <= 2\r\n ? (filteredChips as ReactNode[])\r\n : `${filteredChips.length} selecionados`;\r\n return {\r\n id: g.key,\r\n columnLabel,\r\n op: g.operator,\r\n value,\r\n };\r\n }\r\n\r\n const allValues: string[] = [];\r\n for (const item of g.items) {\r\n if (Array.isArray(item.value)) {\r\n for (const v of item.value as unknown[]) allValues.push(labelOf(v));\r\n } else if (item.value != null) {\r\n allValues.push(labelOf(item.value));\r\n }\r\n }\r\n const value: ReactNode | ReactNode[] =\r\n allValues.length <= 2 ? allValues : `${allValues.length} selecionados`;\r\n return {\r\n id: g.key,\r\n columnLabel,\r\n op: g.operator,\r\n opLabel,\r\n value,\r\n };\r\n }),\r\n [appliedGroups, colLabelMap, colsByField],\r\n );\r\n\r\n const removeGroup = (groupKey: string) => {\r\n const group = appliedGroups.find((g) => g.key === groupKey);\r\n if (!group) return;\r\n const ids = new Set(group.items.map((i) => i.id));\r\n setFilterModel({\r\n ...filterModel,\r\n items: filterModel.items.filter((i) => !ids.has(i.id)),\r\n });\r\n };\r\n\r\n const updateGroupValue = (groupKey: string, newValue: unknown) => {\r\n const group = appliedGroups.find((g) => g.key === groupKey);\r\n if (!group) return;\r\n const groupIds = new Set(group.items.map((i) => i.id));\r\n const newItems: FilterItem[] = [];\r\n const isTupleOperator = group.operator === \"between\";\r\n\r\n // multiSelect ⇒ operador sempre isAnyOf/isNoneOf (ver promoteOperatorForColumn).\r\n const col = colsByField.get(group.field);\r\n const effectiveOperator = promoteOperatorForColumn(group.operator, col);\r\n\r\n if (isTupleOperator) {\r\n const isEmpty =\r\n newValue == null ||\r\n (Array.isArray(newValue) &&\r\n newValue.every(\r\n (x) => x == null || (typeof x === \"string\" && x.length === 0),\r\n ));\r\n if (!isEmpty) {\r\n newItems.push({\r\n id: genFilterId(),\r\n field: group.field,\r\n operator: effectiveOperator,\r\n value: newValue as FilterItem[\"value\"],\r\n });\r\n }\r\n } else {\r\n const arr = Array.isArray(newValue)\r\n ? (newValue as unknown[])\r\n : newValue != null && newValue !== \"\"\r\n ? [newValue]\r\n : [];\r\n for (const v of arr) {\r\n newItems.push({\r\n id: genFilterId(),\r\n field: group.field,\r\n operator: effectiveOperator,\r\n value: v as FilterItem[\"value\"],\r\n });\r\n }\r\n }\r\n // Preserva a POSIÇÃO ORIGINAL do grupo no array — sem isso, o chip era\r\n // empurrado pro fim ao editar valor (visualmente confuso quando há 3+ chips).\r\n // Substituímos os items do grupo IN-PLACE pelos newItems, na posição da\r\n // primeira ocorrência.\r\n const reconstructed: FilterItem[] = [];\r\n let inserted = false;\r\n for (const item of filterModel.items) {\r\n if (groupIds.has(item.id)) {\r\n if (!inserted) {\r\n reconstructed.push(...newItems);\r\n inserted = true;\r\n }\r\n // demais items do grupo: skip (já adicionados via spread acima)\r\n } else {\r\n reconstructed.push(item);\r\n }\r\n }\r\n // Fallback defensivo: se grupo não foi achado (edge case), append no fim\r\n if (!inserted) reconstructed.push(...newItems);\r\n\r\n setFilterModel({ ...filterModel, items: reconstructed });\r\n };\r\n\r\n const getGroupOptions = (groupKey: string): ColumnOption[] => {\r\n const group = appliedGroups.find((g) => g.key === groupKey);\r\n if (!group) return [];\r\n const col = colsByField.get(group.field);\r\n if (col?.filterOptions && col.filterOptions.length > 0) {\r\n return col.filterOptions.map((o) => ({\r\n label: o.label,\r\n value: o.value as string | number,\r\n color: o.color,\r\n }));\r\n }\r\n const rowsForExtract = rows ?? [];\r\n const set = new Set<string>();\r\n for (const r of rowsForExtract) {\r\n const v = col?.valueGetter\r\n ? col.valueGetter(r)\r\n : (r as Record<string, unknown>)[group.field];\r\n if (v != null && v !== \"\") set.add(String(v));\r\n }\r\n return Array.from(set).map((v) => ({ label: v, value: v }));\r\n };\r\n\r\n const handleFiltersChange = (entries: FilterPopoverEntry[]) => {\r\n const items: FilterItem[] = [];\r\n for (const e of entries) {\r\n // op já vem em id longo do FilterModel (vocabulário único) — sem remap.\r\n const rawOperator = e.op as FilterItem[\"operator\"];\r\n\r\n // multiSelect ⇒ operador sempre isAnyOf/isNoneOf (ver promoteOperatorForColumn).\r\n const col = colsByField.get(e.columnKey);\r\n const operator = promoteOperatorForColumn(rawOperator, col);\r\n\r\n // Operadores multi (isAnyOf/isNoneOf): popover passa value=array\r\n // (vimos como 1 entry agrupada em filterPopoverEntries); spreadar\r\n // de volta em N items no filterModel (1 por valor), pra match com\r\n // a representação interna que outros caminhos como updateGroupValue\r\n // já esperam (1 item por valor selecionado).\r\n if (MULTI_VALUE_OPERATORS.has(operator) && Array.isArray(e.value)) {\r\n for (const v of e.value as unknown[]) {\r\n if (v == null || v === \"\") continue;\r\n items.push({\r\n id: genFilterId(),\r\n field: e.columnKey,\r\n operator,\r\n value: v as FilterItem[\"value\"],\r\n });\r\n }\r\n } else {\r\n items.push({\r\n id: e.id,\r\n field: e.columnKey,\r\n operator,\r\n value: e.value as FilterItem[\"value\"],\r\n });\r\n }\r\n }\r\n setFilterModel({ ...filterModel, items });\r\n };\r\n\r\n return {\r\n filterPopoverColumns,\r\n filterPopoverEntries,\r\n appliedGroups,\r\n appliedFilters,\r\n removeGroup,\r\n updateGroupValue,\r\n getGroupOptions,\r\n handleFiltersChange,\r\n isFilterValueEmpty,\r\n };\r\n}\r\n","import { useMemo } from \"react\";\nimport type { KanbanCardData, KanbanColumn } from \"../../Kanban\";\nimport { getFieldValue } from \"../utils/resolve-value\";\nimport type {\n DataTableKanbanConfig,\n GridRowId,\n} from \"../data-table.types\";\n\ntype UseDataTableViewModeOptions<T> = {\n /** Rows processadas (já com filter+search+sort aplicados pelo processor). */\n rows: T[];\n config: DataTableKanbanConfig<T> | undefined;\n /** Resolve id da row (default: row.id). */\n getRowId: (row: T) => GridRowId;\n};\n\ntype UseDataTableViewModeResult = {\n columns: KanbanColumn[];\n cards: KanbanCardData[];\n};\n\n/**\n * Transformer DataTable → Kanban.\n *\n * Recebe as rows já processadas pelo `useDataTableProcessor` (filter + search +\n * sort + selection aplicados) e produz `{ columns, cards }` no formato que o\n * `<Kanban>` primitive consome.\n *\n * Colunas:\n * - Quando `config.columns` é fornecido, usa diretamente (consumer controla ordem,\n * labels, dotColor, canReceiveDrop, canDragFrom).\n * - Caso contrário, deriva automaticamente: extrai valores únicos de\n * `groupByField` na ordem de primeira aparição, gera `KanbanColumn` com\n * `id = String(value)`, `label = String(value)` — sem dotColor.\n *\n * Cards:\n * - Cada row vira 1 `KanbanCardData` com:\n * - `id = getRowId(row)` convertido pra string (KanbanCardData.id é string)\n * - `columnId = String(row[groupByField])`\n * - Demais slots de `config.renderCard({ row })`\n * - Rows com `groupByField` resolvendo pra null/undefined são silenciosamente\n * omitidas (não há coluna fantasma \"sem categoria\"). Consumer pode declarar\n * uma coluna explícita com canReceiveDrop:false se quiser tratar esse caso.\n *\n * Performance: memoizado em `rows` + `config`. Não recomputa quando paginação\n * ou outros estados não-relevantes pra board mudam.\n */\nexport function useDataTableViewMode<T>({\n rows,\n config,\n getRowId,\n}: UseDataTableViewModeOptions<T>): UseDataTableViewModeResult {\n return useMemo(() => {\n if (!config) return { columns: [], cards: [] };\n\n const { groupByField, columns: explicitColumns, renderCard } = config;\n const field = String(groupByField);\n\n // Build cards primeiro — precisamos dos columnIds pra derivar colunas\n const cards: KanbanCardData[] = [];\n const seenColumnIds = new Set<string>();\n const orderedColumnIds: string[] = [];\n\n for (const row of rows) {\n const rawColumnValue = getFieldValue(row as Record<string, unknown>, field);\n if (rawColumnValue === null || rawColumnValue === undefined) continue;\n\n const columnId = String(rawColumnValue);\n const slots = renderCard({ row });\n\n cards.push({\n id: String(getRowId(row)),\n columnId,\n ...slots,\n });\n\n if (!seenColumnIds.has(columnId)) {\n seenColumnIds.add(columnId);\n orderedColumnIds.push(columnId);\n }\n }\n\n // Resolve colunas: explícitas (consumer controla) OU derivadas (ordem de aparição)\n const columns: KanbanColumn[] = explicitColumns\n ? explicitColumns\n : orderedColumnIds.map((id) => ({ id, label: id }));\n\n return { columns, cards };\n }, [rows, config, getRowId]);\n}\n","import {\r\n forwardRef,\r\n useCallback,\r\n useEffect,\r\n useMemo,\r\n useRef,\r\n useState,\r\n} from \"react\";\r\nimport type { Ref, ReactNode } from \"react\";\r\nimport {\r\n DndContext,\r\n PointerSensor,\r\n KeyboardSensor,\r\n useSensor,\r\n useSensors,\r\n closestCenter,\r\n type DragEndEvent,\r\n} from \"@dnd-kit/core\";\r\nimport {\r\n SortableContext,\r\n horizontalListSortingStrategy,\r\n arrayMove,\r\n sortableKeyboardCoordinates,\r\n} from \"@dnd-kit/sortable\";\r\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport {\r\n Table,\r\n TableBody,\r\n TableCardRow,\r\n TableHead,\r\n TableHeadCell,\r\n SELECTION_COLUMN_WIDTH,\r\n} from \"../Table\";\r\nimport { useMediaQuery } from \"../MenuSidebar/use-media-query\";\r\nimport { Checkbox } from \"@/components/shadcn/checkbox\";\r\nimport { Button } from \"@/components/ui/Button/button\";\r\nimport {\r\n MoreHorizontal,\r\n Rows2,\r\n Rows3,\r\n Rows4,\r\n RefreshCw,\r\n FileText,\r\n Filter as FilterIcon,\r\n LayoutGrid,\r\n Table as TableIcon,\r\n List as ListIcon,\r\n Settings2,\r\n Maximize2,\r\n Minimize2,\r\n} from \"lucide-react\";\r\nimport {\r\n TableToolbar,\r\n ToolbarSearch,\r\n ToolbarToolButton,\r\n ToolbarSegmented,\r\n ToolbarApplied,\r\n ToolbarActions,\r\n ToolbarFilterButton,\r\n BulkActionsBar,\r\n isFilterEntryActive,\r\n TableToolbarViews,\r\n MoreMenu,\r\n MoreMenuItem as MoreMenuItemEl,\r\n MoreMenuSeparator,\r\n} from \"../TableToolbar\";\r\nimport type { ToolbarSegmentedItem } from \"../TableToolbar\";\r\nimport { FooterTable, FooterTableSkeleton } from \"../FooterTable\";\r\nimport { Kanban } from \"../Kanban\";\r\nimport { List } from \"../List\";\r\nimport type { ListItemData } from \"../List\";\r\nimport type {\r\n DataTableProps,\r\n DataTableColumnDef,\r\n DataTableRef,\r\n DataTableViewMode,\r\n FilterItem,\r\n FilterValue,\r\n DataTableExportFormat,\r\n DataTableMoreMenuItem,\r\n GridRowId,\r\n} from \"./data-table.types\";\r\nimport type { TableDensity } from \"../Table\";\r\nimport { dataTableStyles } from \"./data-table.styles\";\r\nimport {\r\n DEFAULT_CARD_BREAKPOINT,\r\n DEFAULT_OVERSCAN,\r\n MIN_REFRESH_SPINNER_MS,\r\n DENSITY_ROW_HEIGHT,\r\n} from \"./data-table.constants\";\r\nimport { defaultOperatorForFilterType } from \"./utils/filter-ops\";\r\nimport { DataTableProvider } from \"./context/data-table-context\";\r\nimport { useDataTableController } from \"./hooks/use-data-table-controller\";\r\nimport { useGrabToScroll } from \"./hooks/use-grab-to-scroll\";\r\nimport { DataTableEmpty } from \"./parts/data-table-empty\";\r\nimport { DataTableLoading } from \"./parts/data-table-loading\";\r\nimport { DataTableNoResults } from \"./parts/data-table-no-results\";\r\nimport { DataTableColumnMenu } from \"./parts/data-table-column-menu\";\r\nimport { DataTableActionsCell } from \"./parts/data-table-actions-cell\";\r\nimport { DataTableSortableHeadCell } from \"./parts/sortable-head-cell\";\r\nimport { DataTableTotalizerRow } from \"./parts/data-table-totalizer-row\";\r\nimport {\r\n DataTableRow,\r\n type DataTableRowHandlers,\r\n} from \"./parts/data-table-row\";\r\nimport { DataTableGroupHeaderRow } from \"./parts/data-table-group-header-row\";\r\nimport { DataTableGroupContentRow } from \"./parts/data-table-group-content-row\";\r\nimport { groupRows, isGroupRow, isGroupContent } from \"./utils/group-rows\";\r\nimport { DataTableRowExpansion } from \"./parts/data-table-row-expansion\";\r\nimport { expandRows, isExpansionRow } from \"./utils/expand-rows\";\r\nimport { buildTreeRows, isTreeRow } from \"./utils/tree-rows\";\r\nimport type { DataTableTreeMeta } from \"./parts/data-table-tree-toggle\";\r\nimport { useSortPopoverAdapter } from \"./hooks/use-sort-popover-adapter\";\r\nimport { useColsPopoverAdapter } from \"./hooks/use-cols-popover-adapter\";\r\nimport { useFilterPopoverAdapter } from \"./hooks/use-filter-popover-adapter\";\r\nimport { useDataTableViewMode } from \"./hooks/use-data-table-view-mode\";\r\nimport { applyValueGetter } from \"./utils/resolve-value\";\r\nimport {\r\n Popover,\r\n PopoverTrigger,\r\n PopoverContent,\r\n} from \"@/components/shadcn/popover\";\r\nimport { columnTypeRegistry } from \"./column-types\";\r\n// Settings drill-down + panels do layout canônico (default). Já importados\r\n// do barrel `../TableToolbar` (TableToolbar/ToolbarSearch/etc acima).\r\nimport {\r\n ToolbarSettingsMenu,\r\n SortPanel,\r\n ColsPanel,\r\n FilterPanel,\r\n ToolbarSimpleFilterDrawer as SimpleFilterDrawer,\r\n} from \"../TableToolbar\";\r\n// DataTableFloatingBulkBar still exported from barrel for opt-in use;\r\n// default DataTable now uses inline BulkActionsBar via TableToolbar.bulkBar.\r\n\r\nconst styles = dataTableStyles();\r\n\r\n/* ── Density toggle items (stable ref) ────────────────────────────── */\r\n\r\nconst DENSITY_ITEMS: ToolbarSegmentedItem<TableDensity>[] = [\r\n { value: \"compact\", children: <Rows4 />, label: \"Compacto\" },\r\n { value: \"standard\", children: <Rows3 />, label: \"Padrão\" },\r\n { value: \"comfortable\", children: <Rows2 />, label: \"Confortável\" },\r\n];\r\n\r\n/* View mode toggle items: montados dinamicamente no componente (table +\r\n list? + kanban?) conforme listConfig/kanbanConfig — ver resolvedViewToggle. */\r\n\r\n/**\r\n * Resolve o valor de uma cell — delega pro shared `applyValueGetter`\r\n * (utils/resolve-value.ts) pra evitar duplicação com processor + group-rows.\r\n */\r\nfunction resolveCellValue<T>(row: T, col: DataTableColumnDef<T>): unknown {\r\n return applyValueGetter(row, col);\r\n}\r\n\r\nfunction DataTableInternal<T>(\r\n props: DataTableProps<T>,\r\n ref: Ref<DataTableRef>,\r\n) {\r\n const controller = useDataTableController(props, ref);\r\n const {\r\n contextValue,\r\n isLoading,\r\n isDataEmpty,\r\n isNoResults,\r\n scrollContainerRef,\r\n rowsToRender,\r\n rowsAllPagesProcessed,\r\n totalAfterFilter,\r\n cols,\r\n sort,\r\n pagination,\r\n selection,\r\n density,\r\n search,\r\n filters,\r\n exporter,\r\n isServerMode,\r\n savedViews,\r\n applyViewById,\r\n applyDefault,\r\n saveCurrentAsView,\r\n query,\r\n // States novos centralizados (viewMode/groupBy/expandedRowIds + setters)\r\n viewMode,\r\n setViewMode,\r\n groupBy,\r\n expandedRowIds: controllerExpandedRowIds,\r\n setExpandedRowIds: controllerSetExpandedRowIds,\r\n toggleRowExpansion: controllerToggleRowExpansion,\r\n } = controller;\r\n\r\n const toolbarConfig = props.toolbar ?? {};\r\n const paginationConfig = props.paginationConfig ?? { enabled: true };\r\n const selectionConfig = props.selectionConfig ?? { enabled: false };\r\n\r\n const isKanban = viewMode === \"kanban\" && Boolean(props.kanbanConfig);\r\n const isList = viewMode === \"list\" && Boolean(props.listConfig);\r\n\r\n /* ── Grab-to-scroll horizontal (nativo, opt-out) ──────────────────\r\n * Arrastar o corpo pra rolar lateralmente. Anexa pointer listeners ao\r\n * mesmo `scrollContainerRef` que o `<Table>` usa. No-op em touch e abaixo\r\n * do threshold (clique/seleção preservados). Ligado por padrão — passe\r\n * `grabToScroll={false}` pra desabilitar. */\r\n useGrabToScroll(scrollContainerRef, props.grabToScroll !== false);\r\n\r\n /* ── Fullscreen toggle (opt-in) ───────────────────────────────────\r\n * Expande o container raiz pra ocupar a viewport inteira. Esc fecha. */\r\n const [isFullscreen, setIsFullscreen] = useState(false);\r\n const enableFullscreen = toolbarConfig.enableFullscreen === true;\r\n const toggleFullscreen = useCallback(() => {\r\n setIsFullscreen((prev) => !prev);\r\n }, []);\r\n useEffect(() => {\r\n if (!isFullscreen) return;\r\n const onKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") setIsFullscreen(false);\r\n };\r\n document.addEventListener(\"keydown\", onKeyDown);\r\n return () => document.removeEventListener(\"keydown\", onKeyDown);\r\n }, [isFullscreen]);\r\n\r\n const handleViewModeChange = useCallback(\r\n (mode: DataTableViewMode) => {\r\n setViewMode(mode);\r\n },\r\n [setViewMode],\r\n );\r\n\r\n /**\r\n * Resolved view toggle: consumer-provided OR auto-rendered.\r\n * Auto-render quando `kanbanConfig` está definido E `toolbar.viewToggle`\r\n * NÃO foi explicitamente passado (undefined = \"use default\"; null = \"esconder\").\r\n */\r\n const resolvedViewToggle = useMemo<ReactNode>(() => {\r\n if (props.toolbar?.viewToggle !== undefined)\r\n return props.toolbar.viewToggle;\r\n // Auto-render quando há ao menos uma view alternativa (kanban e/ou lista).\r\n if (!props.kanbanConfig && !props.listConfig) return null;\r\n const items: ToolbarSegmentedItem<DataTableViewMode>[] = [\r\n { value: \"table\", children: <TableIcon />, label: \"Tabela\" },\r\n ];\r\n if (props.listConfig)\r\n items.push({ value: \"list\", children: <ListIcon />, label: \"Lista\" });\r\n if (props.kanbanConfig)\r\n items.push({ value: \"kanban\", children: <LayoutGrid />, label: \"Kanban\" });\r\n return (\r\n <ToolbarSegmented\r\n value={viewMode}\r\n onValueChange={handleViewModeChange}\r\n items={items}\r\n aria-label=\"Modo de visualização\"\r\n />\r\n );\r\n }, [\r\n props.toolbar?.viewToggle,\r\n props.kanbanConfig,\r\n props.listConfig,\r\n viewMode,\r\n handleViewModeChange,\r\n ]);\r\n\r\n /* ── List view — items processados (filter+search+sort), aninhados se\r\n hierarchical (mesmo path do tree-data). Só quando viewMode=list. ── */\r\n const listItems = useMemo<ListItemData[]>(() => {\r\n const cfg = props.listConfig;\r\n if (!isList || !cfg) return [];\r\n const getRowId = contextValue.getRowId;\r\n const pathFn = cfg.getPath ?? props.getTreeDataPath;\r\n // Flat + paginated → usa a página atual (rowsToRender); senão todas.\r\n const rows =\r\n cfg.paginated && !(cfg.hierarchical && pathFn)\r\n ? rowsToRender\r\n : rowsAllPagesProcessed;\r\n if (cfg.hierarchical && pathFn) {\r\n const pathOf = pathFn;\r\n const shells = new Map<string, ListItemData & { children?: ListItemData[] }>();\r\n for (const r of rows) {\r\n const id = String(getRowId(r));\r\n shells.set(id, { id, title: \"\", data: r, children: [] });\r\n }\r\n const out: ListItemData[] = [];\r\n for (const r of rows) {\r\n const path = pathOf(r).map(String);\r\n const id = path[path.length - 1];\r\n const parentId = path.length > 1 ? path[path.length - 2] : null;\r\n const item = shells.get(id);\r\n if (!item) continue;\r\n const parent = parentId ? shells.get(parentId) : undefined;\r\n if (parent) (parent.children as ListItemData[]).push(item);\r\n else out.push(item);\r\n }\r\n for (const it of shells.values())\r\n if (it.children && it.children.length === 0) delete it.children;\r\n return out;\r\n }\r\n return rows.map((r) => ({ id: String(getRowId(r)), title: \"\", data: r }));\r\n }, [\r\n isList,\r\n props.listConfig,\r\n props.getTreeDataPath,\r\n rowsAllPagesProcessed,\r\n rowsToRender,\r\n contextValue.getRowId,\r\n ]);\r\n\r\n const listDefaultExpandedIds = useMemo<Set<string> | undefined>(() => {\r\n const cfg = props.listConfig;\r\n if (!isList || !cfg?.hierarchical || cfg.defaultExpanded === false)\r\n return undefined;\r\n return new Set(rowsAllPagesProcessed.map((r) => String(contextValue.getRowId(r))));\r\n }, [isList, props.listConfig, rowsAllPagesProcessed, contextValue.getRowId]);\r\n\r\n /* ── View mode items do mobile (icon + label fluid), dinâmico ─────── */\r\n const mobileViewItems = useMemo<ToolbarSegmentedItem<DataTableViewMode>[]>(() => {\r\n const mk = (\r\n value: DataTableViewMode,\r\n icon: ReactNode,\r\n label: string,\r\n ): ToolbarSegmentedItem<DataTableViewMode> => ({\r\n value,\r\n label,\r\n children: (\r\n <span className=\"inline-flex items-center gap-gp-sm\">\r\n {icon} {label}\r\n </span>\r\n ),\r\n });\r\n const items = [mk(\"table\", <TableIcon />, \"Tabela\")];\r\n if (props.listConfig) items.push(mk(\"list\", <ListIcon />, \"Lista\"));\r\n if (props.kanbanConfig) items.push(mk(\"kanban\", <LayoutGrid />, \"Kanban\"));\r\n return items;\r\n }, [props.listConfig, props.kanbanConfig]);\r\n\r\n /* ── Kanban transformer (somente quando viewMode=kanban) ──────── */\r\n const kanbanView = useDataTableViewMode({\r\n // Em kanban, paginação não se aplica — usamos `rowsAllPagesProcessed`\r\n // (filter+search+sort completos, sem paginação) pra alimentar o board.\r\n rows: isKanban ? rowsAllPagesProcessed : ([] as T[]),\r\n config: isKanban ? props.kanbanConfig : undefined,\r\n getRowId: contextValue.getRowId,\r\n });\r\n\r\n /* ── Bridge selection (GridSelectionState ↔ Set<string>) ──────── */\r\n const kanbanSelectedIds = useMemo<Set<string> | undefined>(() => {\r\n if (!isKanban || !selectionConfig.enabled) return undefined;\r\n if (selection.state.type !== \"include\") return undefined; // exclude-mode N/A em kanban\r\n return new Set(Array.from(selection.state.ids).map(String));\r\n }, [isKanban, selectionConfig.enabled, selection.state]);\r\n\r\n /**\r\n * Lookup `cardId → row` memoizado pra bridges que precisam resolver row\r\n * original a partir do cardId (renderCardContent, getCardMenuItems,\r\n * toggleSelect, onOpenCard). Evita N find() lineares por render.\r\n */\r\n const kanbanCardIdToRow = useMemo<Map<string, T>>(() => {\r\n if (!isKanban) return new Map();\r\n const map = new Map<string, T>();\r\n for (const row of rowsAllPagesProcessed) {\r\n map.set(String(contextValue.getRowId(row)), row);\r\n }\r\n return map;\r\n }, [isKanban, rowsAllPagesProcessed, contextValue.getRowId]);\r\n\r\n const kanbanToggleSelect = useCallback(\r\n (cardId: string) => {\r\n if (!isKanban || !selectionConfig.enabled) return;\r\n const row = kanbanCardIdToRow.get(cardId);\r\n if (row) selection.toggleRow(row);\r\n },\r\n [isKanban, selectionConfig.enabled, kanbanCardIdToRow, selection],\r\n );\r\n\r\n /* ── Bridge getCardMenuItems (cardId → row → consumer fn) ─────── */\r\n const kanbanGetCardMenuItems = useMemo(() => {\r\n if (!isKanban || !props.kanbanConfig?.getCardMenuItems) return undefined;\r\n const userFn = props.kanbanConfig.getCardMenuItems;\r\n return (card: { id: string }) => {\r\n const row = kanbanCardIdToRow.get(card.id);\r\n return row ? userFn(row) : [];\r\n };\r\n }, [isKanban, props.kanbanConfig, kanbanCardIdToRow]);\r\n\r\n /* ── Bridge onOpenCard (delega ao onRowClick existente) ───────── */\r\n const kanbanOnOpenCard = useMemo(() => {\r\n if (!isKanban || !props.onRowClick) return undefined;\r\n const userFn = props.onRowClick;\r\n return (cardId: string) => {\r\n const row = kanbanCardIdToRow.get(cardId);\r\n if (row) userFn(row);\r\n };\r\n }, [isKanban, props.onRowClick, kanbanCardIdToRow]);\r\n\r\n /* ── Bridge renderCardContent (resolve row + delega) ──────────── */\r\n const kanbanRenderCardContent = useMemo(() => {\r\n if (!isKanban || !props.kanbanConfig?.renderCardContent) return undefined;\r\n const userFn = props.kanbanConfig.renderCardContent;\r\n return (params: {\r\n card: { id: string };\r\n selected: boolean;\r\n open: boolean;\r\n }) => {\r\n const row = kanbanCardIdToRow.get(params.card.id);\r\n if (!row) return null;\r\n return userFn({\r\n // KanbanRenderCardParams (do primitive) já entrega { card, selected, open }\r\n // mas o consumer do DataTable espera receber também a `row` original\r\n card: params.card as never,\r\n row,\r\n selected: params.selected,\r\n open: params.open,\r\n });\r\n };\r\n }, [isKanban, props.kanbanConfig, kanbanCardIdToRow]);\r\n\r\n /* ── Adapters: ColumnDef → FilterPopover props (extraído em hook) ── */\r\n\r\n /** Filter shortcut state — chip a abrir auto após click no header icon.\r\n * Mora aqui porque várias funções fora do adapter usam (handleFilterShortcut,\r\n * renderChip onOpenChange, isFilterValueEmpty cleanup). O adapter consome via prop. */\r\n const [pendingOpenChipKey, setPendingOpenChipKey] = useState<string | null>(\r\n null,\r\n );\r\n\r\n /** Chip de filtro aplicado aberto via clique (controlado). Necessário pra\r\n * `onClose` do renderFastFilterInput funcionar — selects/boolean usam\r\n * `<Select open>` forçado, que trava o dismiss por clique-fora; sem open\r\n * controlado o popover não fecha ao escolher o valor (item 8). */\r\n const [openChipKey, setOpenChipKey] = useState<string | null>(null);\r\n\r\n /** Column label lookup for applied filter chips. */\r\n const colLabelMap = useMemo<Record<string, string>>(\r\n () =>\r\n Object.fromEntries(\r\n cols.effectiveColumns.map((c) => [String(c.field), c.headerName]),\r\n ),\r\n [cols.effectiveColumns],\r\n );\r\n\r\n /** Column lookup map for option label resolution. */\r\n const colsByField = useMemo(\r\n () => new Map(cols.effectiveColumns.map((c) => [String(c.field), c])),\r\n [cols.effectiveColumns],\r\n );\r\n\r\n const {\r\n filterPopoverColumns,\r\n filterPopoverEntries,\r\n appliedGroups,\r\n appliedFilters,\r\n removeGroup,\r\n updateGroupValue,\r\n getGroupOptions,\r\n handleFiltersChange,\r\n isFilterValueEmpty,\r\n } = useFilterPopoverAdapter({\r\n effectiveColumns: cols.effectiveColumns,\r\n allColumns: props.columns,\r\n rows: props.rows,\r\n filterModel: filters.filterModel,\r\n setFilterModel: filters.setFilterModel,\r\n colsByField,\r\n colLabelMap,\r\n pendingOpenChipKey,\r\n });\r\n\r\n // Há filtro REAL ativo? Ignora linhas em branco do query builder (entry sem\r\n // valor) — senão o botão Filtros fica \"verde\" indicando filtro que não existe.\r\n const hasActiveFilter = filterPopoverEntries.some(isFilterEntryActive);\r\n\r\n /* ── Empty filter chips placeholders (prop `showEmptyFilterChips`) ───\r\n * Lista de fields que aparecem como chips placeholder na toolbar mesmo\r\n * sem filtro com valor. Chips são CALCULADOS — não vivem em filterModel.\r\n * Quando user clica num placeholder: cria item vazio no filterModel +\r\n * abre popover via pendingOpenChipKey (mecanismo já existente).\r\n * Quando user remove (X): adiciona ao set local `dismissedPlaceholders`.\r\n * Cleanup automático em outros lugares fica intacto. */\r\n const [dismissedPlaceholders, setDismissedPlaceholders] = useState<\r\n Set<string>\r\n >(() => new Set());\r\n\r\n /** Fields que JÁ TÊM item COM VALOR no filterModel — placeholders desses fields\r\n * são suprimidos. Items vazios (sem valor preenchido) NÃO contam — assim quando\r\n * user adiciona condição via popover Filtros e seleciona o field, o chip\r\n * placeholder permanece visível até receber valor. Sem essa checagem o\r\n * placeholder sumia da toolbar no momento que o user escolhia o field e só\r\n * voltava se ele tirasse o item via cleanup automático. */\r\n const fieldsWithFilter = useMemo(\r\n () =>\r\n new Set(\r\n filters.filterModel.items\r\n .filter((i) => !isFilterValueEmpty(i.value))\r\n .map((i) => i.field),\r\n ),\r\n [filters.filterModel, isFilterValueEmpty],\r\n );\r\n\r\n /** Lista efetiva de placeholders a renderizar. */\r\n const effectivePlaceholderFields = useMemo(() => {\r\n if (!props.showEmptyFilterChips?.length) return [] as string[];\r\n return props.showEmptyFilterChips.filter(\r\n (field) =>\r\n !fieldsWithFilter.has(field) && !dismissedPlaceholders.has(field),\r\n );\r\n }, [props.showEmptyFilterChips, fieldsWithFilter, dismissedPlaceholders]);\r\n\r\n /** Placeholders renderizados como AppliedFilter \"virtuais\" — id prefixado pra detectar. */\r\n const PLACEHOLDER_ID_PREFIX = \"__placeholder__\";\r\n const placeholderFilters = useMemo<typeof appliedFilters>(() => {\r\n return effectivePlaceholderFields.map((field) => ({\r\n id: `${PLACEHOLDER_ID_PREFIX}${field}`,\r\n columnLabel: colLabelMap[field] ?? field,\r\n op: \"\",\r\n value: [],\r\n isEmpty: true,\r\n }));\r\n }, [effectivePlaceholderFields, colLabelMap]);\r\n\r\n /** Lista final de chips na toolbar — **ordenada pela ordem dos fields em\r\n * showEmptyFilterChips**. Quando user preenche um placeholder, ele vira\r\n * filtro real mas mantém a posição original (não \"pula\" pro fim).\r\n * Filtros reais de fields NÃO listados em showEmptyFilterChips aparecem\r\n * após os \"nativos\" (na ordem do filterModel). */\r\n const enhancedAppliedFilters = useMemo(() => {\r\n const showFields = props.showEmptyFilterChips ?? [];\r\n if (showFields.length === 0) return appliedFilters;\r\n\r\n // Map id (group.key) -> field via appliedGroups\r\n const fieldByGroupKey = new Map<string, string>();\r\n for (const g of appliedGroups) {\r\n fieldByGroupKey.set(g.key, g.field);\r\n }\r\n\r\n // Map field -> chip (placeholder OU real)\r\n const placeholderByField = new Map(\r\n placeholderFilters.map((f) => [\r\n f.id.slice(PLACEHOLDER_ID_PREFIX.length),\r\n f,\r\n ]),\r\n );\r\n // ⚠️ Um field pode ter MÚLTIPLOS chips reais (ex: 2 filtros de Email com\r\n // operators diferentes — `contém` e `=`). Por isso armazenamos array,\r\n // não 1 chip único. Renderizamos todos preservando a ordem do filterModel.\r\n const realChipsByField = new Map<string, typeof appliedFilters>();\r\n for (const f of appliedFilters) {\r\n const field = fieldByGroupKey.get(String(f.id));\r\n if (!field) continue;\r\n if (!realChipsByField.has(field)) realChipsByField.set(field, []);\r\n realChipsByField.get(field)!.push(f);\r\n }\r\n\r\n // Chips \"nativos\" — ordem do array showEmptyFilterChips.\r\n // Se há filtros reais → renderiza TODOS (1+) na posição do field.\r\n // Se não há filtros reais e o placeholder não foi descartado → renderiza placeholder.\r\n const orderedNativeChips: typeof appliedFilters = [];\r\n for (const field of showFields) {\r\n const realChips = realChipsByField.get(field);\r\n if (realChips && realChips.length > 0) {\r\n orderedNativeChips.push(...realChips);\r\n } else {\r\n const placeholder = placeholderByField.get(field);\r\n if (placeholder) orderedNativeChips.push(placeholder);\r\n }\r\n }\r\n\r\n // Filtros reais de fields NÃO listados em showEmptyFilterChips (aparecem depois)\r\n const showFieldsSet = new Set(showFields);\r\n const otherChips = appliedFilters.filter((f) => {\r\n const field = fieldByGroupKey.get(String(f.id));\r\n return !field || !showFieldsSet.has(field);\r\n });\r\n\r\n return [...orderedNativeChips, ...otherChips];\r\n }, [\r\n placeholderFilters,\r\n appliedFilters,\r\n appliedGroups,\r\n props.showEmptyFilterChips,\r\n ]);\r\n\r\n /** Handler de remove que intercepta placeholders. */\r\n const handleRemoveFilter = useCallback(\r\n (id: string) => {\r\n if (id.startsWith(PLACEHOLDER_ID_PREFIX)) {\r\n const field = id.slice(PLACEHOLDER_ID_PREFIX.length);\r\n setDismissedPlaceholders((prev) => {\r\n const next = new Set(prev);\r\n next.add(field);\r\n return next;\r\n });\r\n return;\r\n }\r\n removeGroup(id);\r\n },\r\n [removeGroup],\r\n );\r\n\r\n /** Click num placeholder: cria item vazio + abre popover via pendingOpenChipKey. */\r\n const handleActivatePlaceholder = useCallback(\r\n (field: string) => {\r\n const col = colsByField.get(field);\r\n if (!col) return;\r\n const operator = defaultOperatorForFilterType(col.filterType);\r\n const newId =\r\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\r\n ? crypto.randomUUID()\r\n : `f_${field}_${Date.now()}`;\r\n filters.setFilterModel({\r\n ...filters.filterModel,\r\n items: [\r\n ...filters.filterModel.items,\r\n { id: newId, field, operator, value: undefined },\r\n ],\r\n });\r\n setPendingOpenChipKey(`${field}|${operator}`);\r\n },\r\n [colsByField, filters],\r\n );\r\n\r\n /* ── Adapters: ColumnDef → SortPopover props (extraído em hook) ── */\r\n\r\n const { sortPopoverColumns, sortPopoverCriteria, handleSortChange } =\r\n useSortPopoverAdapter({\r\n effectiveColumns: cols.effectiveColumns,\r\n sortModels: sort.sortModels,\r\n setSortModels: sort.setSortModels,\r\n });\r\n\r\n /* ── Adapters: ColumnDef → ColsPopover props (extraído em hook) ── */\r\n\r\n // Colunas na ORDEM ATUAL (columnOrder), incl. ocultas — pro popover refletir\r\n // o estado real. Passar props.columns (ordem original) fazia o popover ignorar\r\n // reorders anteriores e embaralhar ao arrastar.\r\n const orderedAllColumns = useMemo(() => {\r\n const byField = new Map(\r\n props.columns.map((c) => [String(c.field), c] as const),\r\n );\r\n const inOrder = new Set(cols.columnOrder);\r\n const ordered = cols.columnOrder\r\n .map((f) => byField.get(f))\r\n .filter((c): c is (typeof props.columns)[number] => Boolean(c));\r\n const rest = props.columns.filter((c) => !inOrder.has(String(c.field)));\r\n return [...ordered, ...rest];\r\n }, [props.columns, cols.columnOrder]);\r\n\r\n const {\r\n colsPopoverColumns,\r\n visibleColsSet,\r\n pinnedColsSet,\r\n handleVisibleChange,\r\n handlePinnedChange,\r\n handleColumnsReorder,\r\n } = useColsPopoverAdapter({\r\n columns: orderedAllColumns,\r\n hiddenColumns: cols.hiddenColumns,\r\n pinnedColumns: cols.pinnedColumns,\r\n handleShow: cols.handleShow,\r\n handleHide: cols.handleHide,\r\n handlePin: cols.handlePin,\r\n handleReorder: cols.handleReorder,\r\n });\r\n\r\n /* ── Saved Views: shape adapter pro TableToolbarViews ──────────── */\r\n // Mock sem multi-user: TODAS as views salvas localmente sao \"minhas\"\r\n // (eu sou o criador, posso deletar todas — publica ou privada).\r\n // Backend real depois vai mapear owner ao usuario que criou; views publicas\r\n // de OUTROS chegam com `owner: <id>` + `ownerName: \"Nome\"`.\r\n\r\n /**\r\n * Views pro toolbar: presets (read-only, owner='preset') primeiro,\r\n * depois as criadas pelo user (owner='me').\r\n */\r\n const viewsForToolbar = useMemo(\r\n () => [\r\n ...(props.defaultViews ?? []).map((p) => ({\r\n id: p.id,\r\n name: p.name,\r\n owner: \"preset\",\r\n })),\r\n ...savedViews.views.map((v) => ({\r\n id: v.id,\r\n name: v.name,\r\n // Preserva o dono vindo do service (backend real). Ausente = \"me\"\r\n // (compat com o mock, que nao tem multi-user).\r\n owner: v.owner ?? \"me\",\r\n ownerName: v.ownerName,\r\n })),\r\n ],\r\n [props.defaultViews, savedViews.views],\r\n );\r\n\r\n const handleViewApply = (id: string) => {\r\n applyViewById(id);\r\n };\r\n\r\n /* ── Refresh: server dispara refetch; client pisca spinner ────── */\r\n\r\n // `v2FilterOpen` controla o drawer do funil simples (o filtro avançado vive\r\n // no menu de Configurações, não no split button).\r\n const [v2FilterOpen, setV2FilterOpen] = useState(false);\r\n\r\n const [isRefreshing, setIsRefreshing] = useState(false);\r\n const handleRefresh = () => {\r\n if (isRefreshing) return;\r\n setIsRefreshing(true);\r\n if (isServerMode) {\r\n query.refresh();\r\n }\r\n // Mantem o spinner visivel por 400ms minimo (UX feedback)\r\n setTimeout(() => setIsRefreshing(false), MIN_REFRESH_SPINNER_MS);\r\n };\r\n\r\n /* ── Export config tipada ─────────────────────────────────────── */\r\n\r\n const exportConfig = useMemo(() => {\r\n const raw = toolbarConfig.enableExport;\r\n if (!raw) return null;\r\n const defaultCsv: DataTableExportFormat[] = [\r\n { id: \"csv\", label: \"CSV\", icon: <FileText /> },\r\n ];\r\n if (raw === true) {\r\n return { formats: defaultCsv, items: [] as DataTableMoreMenuItem[] };\r\n }\r\n return {\r\n formats: raw.formats?.length ? raw.formats : defaultCsv,\r\n items: raw.items ?? [],\r\n };\r\n }, [toolbarConfig.enableExport]);\r\n\r\n /* ── Column DnD (Fase C) ──────────────────────────────────────────\r\n * Sensors: PointerSensor com `distance: 5` exige 5px de drag antes de ativar —\r\n * preserva click-to-sort no header (click puro nao dispara dnd).\r\n * KeyboardSensor permite reordenar via teclado (Space/Enter pra \"pegar\",\r\n * Setas pra mover, Space/Enter pra soltar, Esc pra cancelar).\r\n */\r\n const dndSensors = useSensors(\r\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\r\n useSensor(KeyboardSensor, {\r\n coordinateGetter: sortableKeyboardCoordinates,\r\n }),\r\n );\r\n\r\n const handleColumnDragEnd = (event: DragEndEvent) => {\r\n const { active, over } = event;\r\n if (!over || active.id === over.id) return;\r\n // active.id e over.id sao os fields (sortableId == field)\r\n const order = cols.columnOrder;\r\n const fromIdx = order.indexOf(String(active.id));\r\n const toIdx = order.indexOf(String(over.id));\r\n if (fromIdx < 0 || toIdx < 0) return;\r\n cols.handleReorder(arrayMove(order, fromIdx, toIdx));\r\n };\r\n\r\n // IDs dos itens sortable — usa columnOrder (que respeita visibilidade nao,\r\n // mas effectiveColumns sim). Usar effectiveColumns garante que itens hidden\r\n // nao entram no contexto (evita ID stale).\r\n const sortableIds = useMemo(\r\n () => cols.effectiveColumns.map((c) => String(c.field)),\r\n [cols.effectiveColumns],\r\n );\r\n\r\n /* ── Inline edit state (Fase D) ────────────────────────────────────\r\n * Uma celula editavel por vez. Identificada por { rowId, field }.\r\n * Double-click numa cell com `column.editable: true` entra em edit mode.\r\n * Commit (Enter/blur) chama `onCellEditCommit({id,field,value,oldValue,row})`.\r\n * Esc cancela sem chamar callback. */\r\n const [editingCell, setEditingCell] = useState<{\r\n rowId: GridRowId;\r\n field: string;\r\n } | null>(null);\r\n // Fase F.1 — async commit. Quando onCellEditCommit retorna Promise:\r\n // editLoading=true mostra spinner overlay + bloqueia input; editError guarda\r\n // mensagem se promise rejeitar (mantem edit aberto pra retry).\r\n const [editLoading, setEditLoading] = useState(false);\r\n const [editError, setEditError] = useState<string | null>(null);\r\n\r\n /** Adiciona filtro vazio pra coluna (ou abre o existente) + sinaliza pra abrir\r\n * o popover do chip correspondente. Operador default deriva do filterType:\r\n * - select/multiSelect → equals\r\n * - date → between (range — preset mais útil pra datas)\r\n * - demais (text/number) → contains */\r\n const handleFilterShortcut = (col: DataTableColumnDef<T>) => {\r\n const field = String(col.field);\r\n // Fonte única: mesma inferência usada no resto do DataTable. Evita a\r\n // divergência anterior (number/currency caíam em \"contains\", que esses\r\n // tipos nem suportam → filtro inerte).\r\n const operator = defaultOperatorForFilterType(col.filterType);\r\n const chipKey = `${field}|${operator}`;\r\n const initialValue: FilterValue =\r\n operator === \"between\" ? [null, null] : \"\";\r\n\r\n // Se ja existe grupo pra essa coluna+operator, so abre. Senao, adiciona vazio + abre.\r\n const existing = filters.filterModel.items.find(\r\n (it) => it.field === field && it.operator === operator,\r\n );\r\n if (!existing) {\r\n filters.setFilterModel({\r\n ...filters.filterModel,\r\n items: [\r\n ...filters.filterModel.items,\r\n {\r\n id: `shortcut-${field}-${operator}-${Date.now()}`,\r\n field,\r\n operator,\r\n value: initialValue,\r\n },\r\n ],\r\n });\r\n }\r\n // setTimeout 0 garante que o chip ja foi renderizado quando setamos o pending\r\n setTimeout(() => setPendingOpenChipKey(chipKey), 0);\r\n };\r\n\r\n /* ── Keyboard nav state (Fase E.1) ────────────────────────────────\r\n * focusedRowIndex eh o indice (0-based) da row focada na pagina atual.\r\n * null = nenhuma. Setado pelo handler de keyDown abaixo e pelo click.\r\n * Row focada recebe tabIndex=0 + visual outline brand. Restante tabIndex=-1.\r\n * Auto-scroll via ref.scrollIntoView({block:\"nearest\"}). */\r\n const [focusedRowIndex, setFocusedRowIndex] = useState<number | null>(null);\r\n const rowRefs = useRef<Map<number, HTMLDivElement>>(new Map());\r\n\r\n // Reset focus quando a pagina muda (pagination, filter, sort, page size).\r\n // Sem isso, indice stale aponta pra row que nao existe mais.\r\n useEffect(() => {\r\n setFocusedRowIndex(null);\r\n }, [\r\n pagination.paginationModel.page,\r\n pagination.paginationModel.pageSize,\r\n filters.filterModel,\r\n search.debouncedValue,\r\n sort.sortModels,\r\n ]);\r\n\r\n const handleRowKeyDown = (\r\n e: React.KeyboardEvent<HTMLDivElement>,\r\n rowIndex: number,\r\n row: T,\r\n ) => {\r\n const lastIdx = rowsToRender.length - 1;\r\n let nextIdx: number | null = null;\r\n\r\n if (e.key === \"ArrowDown\") {\r\n nextIdx = Math.min(rowIndex + 1, lastIdx);\r\n } else if (e.key === \"ArrowUp\") {\r\n nextIdx = Math.max(rowIndex - 1, 0);\r\n } else if (e.key === \"Home\") {\r\n nextIdx = 0;\r\n } else if (e.key === \"End\") {\r\n nextIdx = lastIdx;\r\n } else if (e.key === \"PageDown\") {\r\n nextIdx = Math.min(rowIndex + 10, lastIdx);\r\n } else if (e.key === \"PageUp\") {\r\n nextIdx = Math.max(rowIndex - 10, 0);\r\n } else if (e.key === \"Enter\") {\r\n e.preventDefault();\r\n props.onRowClick?.(row);\r\n return;\r\n } else if (e.key === \" \" && selectionConfig.enabled) {\r\n e.preventDefault();\r\n selection.toggleRow(row);\r\n return;\r\n } else {\r\n return;\r\n }\r\n\r\n e.preventDefault();\r\n setFocusedRowIndex(nextIdx);\r\n // Foco programatico + scroll.\r\n // - Modo normal: setTimeout 0 (espera React reconciliar tabIndex) → focus + scrollIntoView.\r\n // - Modo virtualizado: scrollToIndex primeiro pra row entrar no DOM;\r\n // depois setTimeout maior (50ms) pra virtualizer renderizar; depois focus.\r\n if (virtualize) {\r\n rowVirtualizer.scrollToIndex(nextIdx, { align: \"auto\" });\r\n setTimeout(() => {\r\n const el = rowRefs.current.get(nextIdx!);\r\n el?.focus();\r\n }, 50);\r\n } else {\r\n setTimeout(() => {\r\n const el = rowRefs.current.get(nextIdx!);\r\n el?.focus();\r\n el?.scrollIntoView({ block: \"nearest\", behavior: \"smooth\" });\r\n }, 0);\r\n }\r\n };\r\n\r\n const handleCellEditCommit = async (params: {\r\n row: T;\r\n field: string;\r\n value: any;\r\n oldValue: any;\r\n }) => {\r\n const id = contextValue.getRowId(params.row);\r\n const result = props.onCellEditCommit?.({\r\n id,\r\n field: params.field,\r\n value: params.value,\r\n oldValue: params.oldValue,\r\n row: params.row,\r\n });\r\n // Sincrono ou sem callback → fecha imediato\r\n if (!(result instanceof Promise)) {\r\n setEditingCell(null);\r\n setEditError(null);\r\n return;\r\n }\r\n // Async: loading overlay + await + tratamento de erro.\r\n setEditLoading(true);\r\n setEditError(null);\r\n try {\r\n await result;\r\n setEditingCell(null);\r\n } catch (err) {\r\n setEditError(err instanceof Error ? err.message : String(err));\r\n // NAO fecha — user pode corrigir e tentar de novo, ou Esc pra cancelar\r\n } finally {\r\n setEditLoading(false);\r\n }\r\n };\r\n\r\n /** Cancelamento manual (Esc) — limpa tudo. */\r\n const handleCellEditCancel = () => {\r\n setEditingCell(null);\r\n setEditLoading(false);\r\n setEditError(null);\r\n };\r\n\r\n /* ── Agrupamento — Fase F.4 ────────────────────────────────────────\r\n * `groupBy` vem do controller (controlled/uncontrolled). Quando definido,\r\n * rows são reshape em (GroupRow | T)[] alternados. expandedGroupKeys guarda\r\n * toggles DIFERENTES do default — if defaultGroupExpanded=true: keys no set\r\n * são collapsed; vice-versa. Permite \"expandir tudo\" sem precisar setar N\r\n * keys explicitamente. */\r\n const groupByField = groupBy;\r\n const defaultGroupExpanded = props.defaultGroupExpanded !== false; // default true\r\n const [expandedGroupKeys, setExpandedGroupKeys] = useState<Set<string>>(\r\n () => new Set(),\r\n );\r\n const groupColumn = useMemo(\r\n () =>\r\n groupByField\r\n ? props.columns.find((c) => String(c.field) === groupByField)\r\n : undefined,\r\n [props.columns, groupByField],\r\n );\r\n const useCustomGroupContent = !!props.renderGroupContent;\r\n const groupedRows = useMemo(() => {\r\n if (!groupByField) return rowsToRender;\r\n return groupRows(\r\n rowsToRender,\r\n groupByField,\r\n expandedGroupKeys,\r\n defaultGroupExpanded,\r\n groupColumn,\r\n useCustomGroupContent,\r\n );\r\n }, [\r\n rowsToRender,\r\n groupByField,\r\n expandedGroupKeys,\r\n defaultGroupExpanded,\r\n groupColumn,\r\n useCustomGroupContent,\r\n ]);\r\n\r\n const toggleGroup = (key: string) => {\r\n setExpandedGroupKeys((prev) => {\r\n const next = new Set(prev);\r\n if (next.has(key)) next.delete(key);\r\n else next.add(key);\r\n return next;\r\n });\r\n };\r\n\r\n /* ── Row expansion — Fase F.4b ──────────────────────────────────────\r\n * State `expandedRowIds: GridRowId[]` vem do controller (controlled/\r\n * uncontrolled). Aliasing local com Set pra preservar API interna usada\r\n * por `isRowExpanded` lookups O(1) + iteração. */\r\n const expandedRowIds = useMemo(\r\n () => new Set(controllerExpandedRowIds),\r\n [controllerExpandedRowIds],\r\n );\r\n const useRowExpansion = !!props.renderRowExpansion && !groupByField;\r\n\r\n const toggleRowExpansion = controllerToggleRowExpansion;\r\n\r\n // Pre-compute expandable column field pra usar no cell render\r\n const expandableColField = useMemo(() => {\r\n if (!useRowExpansion) return null;\r\n const col = props.columns.find((c) => c.expandable === true);\r\n return col ? String(col.field) : null;\r\n }, [props.columns, useRowExpansion]);\r\n\r\n /* ── Tree-data — Fase F.4c ──────────────────────────────────────────\r\n * Hierarquia multi-nível derivada de `getTreeDataPath`. Reconstrói a árvore\r\n * a partir das rows (já filtradas/ordenadas) e produz TreeRows ordenadas com\r\n * level/hasChildren/descendantCount. Reusa `expandedRowIds` como estado de\r\n * expansão de nós. Mutuamente exclusivo com groupBy (groupBy tem precedência)\r\n * e com row-expansion (tree tem precedência sobre row-expansion). */\r\n const useTreeData = !!props.getTreeDataPath && !groupByField;\r\n const treeDefaultExpanded = props.treeData?.defaultExpanded !== false; // default true\r\n const treeShowDescendantCount = props.treeData?.showDescendantCount === true;\r\n\r\n // Coluna primária da árvore: a que marca `treeColumn: true`, senão a primeira\r\n // coluna não-actions.\r\n const treeColField = useMemo(() => {\r\n if (!useTreeData) return null;\r\n const marked = props.columns.find((c) => c.treeColumn === true);\r\n if (marked) return String(marked.field);\r\n const firstData = props.columns.find((c) => c.type !== \"actions\");\r\n return firstData ? String(firstData.field) : null;\r\n }, [props.columns, useTreeData]);\r\n\r\n const treeRows = useMemo(() => {\r\n if (!useTreeData || !props.getTreeDataPath) return null;\r\n return buildTreeRows(\r\n rowsToRender,\r\n props.getTreeDataPath,\r\n contextValue.getRowId,\r\n expandedRowIds,\r\n treeDefaultExpanded,\r\n );\r\n }, [\r\n useTreeData,\r\n props.getTreeDataPath,\r\n rowsToRender,\r\n contextValue,\r\n expandedRowIds,\r\n treeDefaultExpanded,\r\n ]);\r\n\r\n /**\r\n * Toggle de um nó da árvore = toggle de `expandedRowIds` (mesma máquina de\r\n * row-expansion: o Set guarda ids que DIFEREM do default de expansão).\r\n *\r\n * NÃO reusa `toggleRowExpansion` do controller: aquele respeita `singleExpand`\r\n * (abrir um colapsa os demais), o que CORROMPE a árvore — colapsar/expandir um\r\n * ramo apagaria a divergência de ramos não relacionados. Em tree-data cada nó\r\n * diverge do default de forma independente, então togglamos só a membership do\r\n * id no Set via `controllerSetExpandedRowIds` (preserva controlled/\r\n * uncontrolled + persistência).\r\n */\r\n const toggleTreeNode = useCallback(\r\n (id: GridRowId) => {\r\n const next = expandedRowIds.has(id)\r\n ? Array.from(expandedRowIds).filter((x) => x !== id)\r\n : [...Array.from(expandedRowIds), id];\r\n controllerSetExpandedRowIds(next);\r\n },\r\n [expandedRowIds, controllerSetExpandedRowIds],\r\n );\r\n\r\n // Expand-all / collapse-all programático da árvore vive no controller\r\n // (`expandAllTree`/`collapseAllTree`), exposto via imperative handle\r\n // (`DataTableRef`). Usa `collectExpandableTreeIds` (tree-rows.ts) sobre todas\r\n // as rows pós-filtro/sort pra montar o Set de divergência, respeitando\r\n // `treeData.defaultExpanded`. O app dispara via `ref.current.expandAllTree()` /\r\n // `ref.current.collapseAllTree()`; a toolbar do DS não embute botões (slice\r\n // mantido só nos métodos do ref).\r\n\r\n // Array de items renderizados — quando há expansion/tree, intercala markers.\r\n // Precedência: groupBy > tree-data > row-expansion.\r\n const finalItems = useMemo(() => {\r\n if (groupByField) return groupedRows;\r\n if (useTreeData && treeRows) return treeRows;\r\n if (useRowExpansion && expandedRowIds.size > 0) {\r\n return expandRows(rowsToRender, expandedRowIds, contextValue.getRowId);\r\n }\r\n return rowsToRender;\r\n }, [\r\n groupByField,\r\n groupedRows,\r\n useTreeData,\r\n treeRows,\r\n useRowExpansion,\r\n expandedRowIds,\r\n rowsToRender,\r\n contextValue,\r\n ]);\r\n\r\n // Handlers da row via REF estável (latest-ref pattern): o objeto ref nunca\r\n // muda → não invalida o memo do <DataTableRow>; o `.current` é atualizado a\r\n // cada render → sem stale closure no event time. Permite memoizar rows sem\r\n // precisar useCallback em todos os handlers (que teriam dep-hell).\r\n const rowHandlersRef = useRef<DataTableRowHandlers<T>>(null as never);\r\n rowHandlersRef.current = {\r\n getRowId: contextValue.getRowId,\r\n onRowClick: (row, index) => {\r\n setFocusedRowIndex(index);\r\n props.onRowClick?.(row);\r\n },\r\n onRowKeyDown: (e, index, row) => handleRowKeyDown(e, index, row),\r\n onRowFocus: (index) => {\r\n if (focusedRowIndex !== index) setFocusedRowIndex(index);\r\n },\r\n toggleRowSelection: (row) => selection.toggleRow(row),\r\n toggleRowExpansion,\r\n toggleTreeNode,\r\n startEditingCell: (rowId, field) => setEditingCell({ rowId, field }),\r\n onCellEditCommit: handleCellEditCommit,\r\n onCellEditCancel: handleCellEditCancel,\r\n registerRef: (index, el) => {\r\n if (el) rowRefs.current.set(index, el);\r\n else rowRefs.current.delete(index);\r\n },\r\n };\r\n\r\n /* ── Virtualização — Fase F.3 ──────────────────────────────────────\r\n * Quando props.virtualize, renderiza apenas rows visíveis. Estimate de\r\n * row height deriva de density (compact=40, standard=56, comfortable=64).\r\n * Consumer pode override via props.estimateRowHeight.\r\n * scrollContainerRef vem do controller (compartilhado com useColumnAutoWidth). */\r\n const estimateRowHeight =\r\n props.estimateRowHeight ?? DENSITY_ROW_HEIGHT[density.density];\r\n const virtualize = props.virtualize === true;\r\n\r\n const rowVirtualizer = useVirtualizer({\r\n // count cobre todos os casos: rows simples, agrupadas, ou com expansion intercalada\r\n count: virtualize ? finalItems.length : 0,\r\n getScrollElement: () => scrollContainerRef.current,\r\n estimateSize: () => estimateRowHeight,\r\n overscan: props.overscan ?? DEFAULT_OVERSCAN,\r\n });\r\n\r\n /* ── Body content (Table primitivo) ───────────────────────────── */\r\n\r\n const tableBody = (\r\n <DndContext\r\n sensors={dndSensors}\r\n collisionDetection={closestCenter}\r\n onDragEnd={handleColumnDragEnd}\r\n >\r\n <Table\r\n density={density.density}\r\n cardBreakpoint={props.cardBreakpoint ?? DEFAULT_CARD_BREAKPOINT}\r\n className=\"min-h-0 max-h-full\"\r\n scrollRef={scrollContainerRef}\r\n >\r\n <TableHead>\r\n {selectionConfig.enabled && (\r\n <TableHeadCell\r\n width={SELECTION_COLUMN_WIDTH}\r\n align=\"center\"\r\n purpose=\"selection\"\r\n >\r\n <Checkbox\r\n checked={\r\n selection.isPageSelected(rowsToRender)\r\n ? true\r\n : selection.isPageIndeterminate(rowsToRender)\r\n ? \"indeterminate\"\r\n : false\r\n }\r\n onCheckedChange={() => selection.togglePage(rowsToRender)}\r\n aria-label=\"Selecionar página\"\r\n />\r\n </TableHeadCell>\r\n )}\r\n <SortableContext\r\n items={sortableIds}\r\n strategy={horizontalListSortingStrategy}\r\n >\r\n {cols.effectiveColumns.map((col) => {\r\n const field = String(col.field);\r\n const isActions = col.type === \"actions\";\r\n return (\r\n <DataTableSortableHeadCell\r\n key={field}\r\n sortableId={field}\r\n disableDrag={isActions}\r\n field={field}\r\n width={cols.columnWidths[field]}\r\n pinned={col.pinned}\r\n pinOffset={cols.stickyOffsets[field]}\r\n align={col.align}\r\n purpose={isActions ? \"actions\" : undefined}\r\n sortable={!isActions && col.sortable !== false}\r\n sortDirection={\r\n sort.sortModels.find((s) => s.field === field)?.direction ??\r\n null\r\n }\r\n sortIndex={(() => {\r\n // Mostra badge 1/2/3... apenas quando ha multi-sort (>= 2 criterios).\r\n if (sort.sortModels.length < 2) return undefined;\r\n const idx = sort.sortModels.findIndex(\r\n (s) => s.field === field,\r\n );\r\n return idx >= 0 ? idx + 1 : undefined;\r\n })()}\r\n onSortClick={() => sort.handleSort(field)}\r\n resizable={!isActions && col.resizable !== false}\r\n // Comita no state APENAS no mouseup — durante o drag a largura\r\n // é atualizada via DOM direto pelo TableHeadCell (sem re-render\r\n // do DataTable a cada mousemove, que parecia \"atualizando\").\r\n onResizeEnd={(w) => cols.handleResize(field, w)}\r\n icon={\r\n isActions\r\n ? undefined\r\n : (col.icon ??\r\n (col.type\r\n ? columnTypeRegistry.get(col.type).defaultIcon\r\n : undefined))\r\n }\r\n headMenu={\r\n !isActions ? (\r\n <>\r\n {/* Filter shortcut — abre popover do chip da coluna pra digitar valor.\r\n Se ja existe filtro, reabre. Visivel apenas em colunas enableColumnFilter. */}\r\n {col.enableColumnFilter && (\r\n <Button\r\n size=\"icon-2xs\"\r\n variant=\"ghost\"\r\n color=\"secondary\"\r\n aria-label={`Filtrar ${col.headerName}`}\r\n title={`Filtrar ${col.headerName}`}\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n handleFilterShortcut(col);\r\n }}\r\n onPointerDown={(e) => e.stopPropagation()}\r\n onMouseDown={(e) => e.stopPropagation()}\r\n >\r\n <FilterIcon />\r\n </Button>\r\n )}\r\n {col.enableColumnMenu !== false && (\r\n <DataTableColumnMenu\r\n columnName={col.headerName}\r\n sortDirection={\r\n sort.sortModels.find((s) => s.field === field)\r\n ?.direction ?? null\r\n }\r\n pinned={\r\n cols.pinnedColumns[field] === \"left\"\r\n ? \"left\"\r\n : cols.pinnedColumns[field] === \"right\"\r\n ? \"right\"\r\n : null\r\n }\r\n canHide={col.hideable !== false}\r\n onSortAsc={() =>\r\n sort.setSortModels([{ field, direction: \"asc\" }])\r\n }\r\n onSortDesc={() =>\r\n sort.setSortModels([{ field, direction: \"desc\" }])\r\n }\r\n onSortClear={() => sort.setSortModels([])}\r\n onPinLeft={() => cols.handlePin(field, \"left\")}\r\n onPinRight={() => cols.handlePin(field, \"right\")}\r\n onUnpin={() => cols.handlePin(field, undefined)}\r\n onHide={() => cols.handleHide(field)}\r\n extraItems={col.columnMenuItems}\r\n />\r\n )}\r\n </>\r\n ) : undefined\r\n }\r\n >\r\n {/* Header da coluna actions é sempre vazio — independe do `headerName`\r\n passado pelo consumer (uniformiza padrão de UX). */}\r\n {isActions ? null : col.headerName}\r\n </DataTableSortableHeadCell>\r\n );\r\n })}\r\n </SortableContext>\r\n </TableHead>\r\n <TableBody\r\n // Modo virtualizado é prop do TableBody primitive — aplica\r\n // height/position/block internamente. Sem hardcode no DataTable.\r\n virtualized={\r\n virtualize\r\n ? { totalHeight: rowVirtualizer.getTotalSize() }\r\n : undefined\r\n }\r\n >\r\n {(() => {\r\n // Branching: GroupHeader / GroupContent / DataRow.\r\n // - GroupHeader: column-aligned default, ou free-form via renderGroupHeader.\r\n // - GroupContent: slot custom (só aparece quando renderGroupContent definido) —\r\n // substitui as N child rows por 1 row full-width com conteudo livre.\r\n // - DataRow: fluxo normal (TableRow + cells).\r\n const renderItem = (\r\n item: T | ((typeof groupedRows)[number] & { __type?: symbol }),\r\n index: number,\r\n virtualStyle?: React.CSSProperties,\r\n ) => {\r\n if (isGroupRow<T>(item)) {\r\n return (\r\n <DataTableGroupHeaderRow\r\n key={item.key}\r\n group={item}\r\n columns={cols.effectiveColumns}\r\n columnWidths={cols.columnWidths}\r\n stickyOffsets={cols.stickyOffsets}\r\n hasSelection={selectionConfig.enabled === true}\r\n onToggle={() => toggleGroup(item.key)}\r\n style={virtualStyle}\r\n renderHeader={props.renderGroupHeader}\r\n />\r\n );\r\n }\r\n if (isGroupContent<T>(item) && props.renderGroupContent) {\r\n return (\r\n <DataTableGroupContentRow\r\n key={`${item.key}-content`}\r\n group={item.group}\r\n render={props.renderGroupContent}\r\n style={virtualStyle}\r\n />\r\n );\r\n }\r\n if (isExpansionRow<T>(item) && props.renderRowExpansion) {\r\n return (\r\n <DataTableRowExpansion\r\n key={`exp-${String(item.id)}`}\r\n row={item.row}\r\n render={props.renderRowExpansion}\r\n style={virtualStyle}\r\n />\r\n );\r\n }\r\n // Tree-data: desembrulha o TreeRow (mantém a row real intacta) e\r\n // calcula a meta de hierarquia pra a coluna primária renderizar\r\n // indentação + chevron.\r\n const treeNode = isTreeRow<T>(item) ? item : null;\r\n const row = (treeNode ? treeNode.row : item) as T;\r\n const rowId = contextValue.getRowId(row);\r\n const treeMeta: DataTableTreeMeta | null = treeNode\r\n ? {\r\n level: treeNode.level,\r\n hasChildren: treeNode.hasChildren,\r\n isExpanded: treeNode.isExpanded,\r\n descendantCount: treeNode.descendantCount,\r\n childCount: treeNode.childCount,\r\n }\r\n : null;\r\n const editState =\r\n editingCell?.rowId === rowId\r\n ? {\r\n field: editingCell.field,\r\n isLoading: editLoading,\r\n error: editError,\r\n }\r\n : null;\r\n return (\r\n <DataTableRow<T>\r\n key={String(rowId)}\r\n row={row}\r\n index={index}\r\n rowId={rowId}\r\n selected={selection.isRowSelected(row)}\r\n focused={focusedRowIndex === index}\r\n expanded={expandedRowIds.has(rowId)}\r\n editState={editState}\r\n rowClassName={props.getRowClassName?.({ row, index })}\r\n virtualStyle={virtualStyle}\r\n columns={cols.effectiveColumns}\r\n columnWidths={cols.columnWidths}\r\n stickyOffsets={cols.stickyOffsets}\r\n selectionEnabled={selectionConfig.enabled === true}\r\n clickable={!!props.onRowClick}\r\n useRowExpansion={useRowExpansion}\r\n expandableColField={expandableColField}\r\n treeColField={treeColField}\r\n treeMeta={treeMeta}\r\n treeShowDescendantCount={treeShowDescendantCount}\r\n handlers={rowHandlersRef}\r\n />\r\n );\r\n };\r\n\r\n // Render: virtualizado vs todos as rows. `finalItems` cobre rows\r\n // simples + agrupadas + com expansion intercalada.\r\n if (virtualize) {\r\n return rowVirtualizer.getVirtualItems().map((vi) =>\r\n renderItem(finalItems[vi.index], vi.index, {\r\n position: \"absolute\",\r\n top: 0,\r\n left: 0,\r\n width: \"100%\",\r\n height: `${vi.size}px`,\r\n transform: `translateY(${vi.start}px)`,\r\n }),\r\n );\r\n }\r\n return finalItems.map((item, i) => renderItem(item, i));\r\n })()}\r\n {/* Totalizer footer row (Fase E.2) — sticky no bottom do body */}\r\n {props.showTotalizers && (\r\n <DataTableTotalizerRow\r\n columns={cols.effectiveColumns}\r\n rows={rowsAllPagesProcessed}\r\n overrides={props.aggregateRow}\r\n columnWidths={cols.columnWidths}\r\n stickyOffsets={cols.stickyOffsets}\r\n hasSelection={selectionConfig.enabled === true}\r\n />\r\n )}\r\n </TableBody>\r\n </Table>\r\n </DndContext>\r\n );\r\n\r\n /* ── Card mode (responsivo mobile) ────────────────────────────────\r\n * Quando `cardBreakpoint` está habilitado e o viewport é menor que ele,\r\n * renderiza cada row como `<TableCardRow>` em vez de `<TableRow>`. O\r\n * toolbar e footer continuam idênticos — só o body que troca de view.\r\n *\r\n * Mapeamento das colunas → card:\r\n * - selection (checkbox) → header do card (esquerda)\r\n * - col.isPrimary OU 1ª não-actions → header do card (label primário)\r\n * - col.type === \"actions\" → headerActions (canto sup. direito)\r\n * - resto das colunas visíveis → items label/value no body\r\n *\r\n * Não suportado em card mode (degradam silenciosamente):\r\n * - Virtualização (renderiza todas as rows)\r\n * - Row expansion (toggle escondido)\r\n * - Inline editing (double-click pra editar)\r\n * - Column reordering / pinning / resize (sem sentido num card vertical)\r\n */\r\n const cardBp = props.cardBreakpoint ?? DEFAULT_CARD_BREAKPOINT;\r\n const cardModeQuery =\r\n cardBp === false ? \"(max-width: 0px)\" : `(max-width: ${cardBp - 1}px)`;\r\n const isMobileViewport = useMediaQuery(cardModeQuery);\r\n // Preferência de exibição no mobile: TABELA por default (antes era card forçado).\r\n // O user troca pra \"card\" via toggle no Configurações da tabela (só mobile).\r\n // Live (sem reload). cardBreakpoint={false} desabilita o card de vez.\r\n const cardPossible = isMobileViewport && cardBp !== false && !isKanban;\r\n const [mobileDisplay, setMobileDisplay] = useState<\"table\" | \"card\">(\"table\");\r\n const isCardMode = cardPossible && mobileDisplay === \"card\";\r\n\r\n /** Render do conteúdo de uma cell — versão simplificada (sem edit/expansion). */\r\n const getCardCellContent = (\r\n col: (typeof cols.effectiveColumns)[number],\r\n row: T,\r\n ): ReactNode => {\r\n const isActionsCol = col.type === \"actions\";\r\n const value = isActionsCol ? undefined : resolveCellValue(row, col);\r\n const typeDef = col.type ? columnTypeRegistry.get(col.type) : undefined;\r\n\r\n if (isActionsCol && col.getActions && !col.render) {\r\n return (\r\n <DataTableActionsCell row={row} actions={col.getActions({ row })} />\r\n );\r\n }\r\n if (col.render) {\r\n return col.render({ row, value });\r\n }\r\n if (typeDef?.renderCell) {\r\n return typeDef.renderCell({\r\n value,\r\n row,\r\n options: col.filterOptions,\r\n column: {\r\n field: String(col.field),\r\n headerName: col.headerName,\r\n valueFormatter: col.valueFormatter,\r\n typeOptions: col.typeOptions,\r\n },\r\n });\r\n }\r\n if (col.valueFormatter) return col.valueFormatter(value) as ReactNode;\r\n if (typeDef?.formatValue) return typeDef.formatValue(value) as ReactNode;\r\n return value as ReactNode;\r\n };\r\n\r\n // Resolve colunas especiais uma vez fora do map (evita re-cálculo por row)\r\n const cardPrimaryCol = isCardMode\r\n ? (cols.effectiveColumns.find((c) => c.isPrimary) ??\r\n cols.effectiveColumns.find((c) => c.type !== \"actions\"))\r\n : undefined;\r\n const cardActionsCol = isCardMode\r\n ? cols.effectiveColumns.find((c) => c.type === \"actions\")\r\n : undefined;\r\n const cardItemCols = isCardMode\r\n ? cols.effectiveColumns.filter(\r\n (c) => c !== cardPrimaryCol && c !== cardActionsCol,\r\n )\r\n : [];\r\n\r\n const cardBody = (\r\n <div className=\"flex flex-col gap-gp-md p-pad-2xl overflow-auto scrollbar-thin min-h-0 flex-1\">\r\n {rowsToRender.map((row) => {\r\n const isSel = selection.isRowSelected(row);\r\n const rowId = contextValue.getRowId(row);\r\n return (\r\n <TableCardRow\r\n key={String(rowId)}\r\n selected={isSel}\r\n clickable={!!props.onRowClick}\r\n onClick={\r\n props.onRowClick ? () => props.onRowClick?.(row) : undefined\r\n }\r\n header={\r\n <>\r\n {selectionConfig.enabled && (\r\n <Checkbox\r\n checked={isSel}\r\n onCheckedChange={() => selection.toggleRow(row)}\r\n onClick={(e) => e.stopPropagation()}\r\n aria-label=\"Selecionar linha\"\r\n />\r\n )}\r\n {cardPrimaryCol && (\r\n <div className=\"font-medium text-fg-default truncate flex-1 min-w-0\">\r\n {getCardCellContent(cardPrimaryCol, row)}\r\n </div>\r\n )}\r\n </>\r\n }\r\n headerActions={\r\n cardActionsCol\r\n ? getCardCellContent(cardActionsCol, row)\r\n : undefined\r\n }\r\n items={cardItemCols.map((col) => ({\r\n key: String(col.field),\r\n label: col.headerName ?? String(col.field),\r\n value: getCardCellContent(col, row),\r\n }))}\r\n />\r\n );\r\n })}\r\n </div>\r\n );\r\n\r\n /* ── Render principal ─────────────────────────────────────────── */\r\n\r\n return (\r\n <DataTableProvider value={contextValue}>\r\n <div\r\n className={cn(\r\n dataTableStyles({ fullscreen: isFullscreen }).root(),\r\n props.className,\r\n )}\r\n >\r\n {/* Toolbar */}\r\n <div className={styles.toolbarWrap()}>\r\n <>\r\n <TableToolbar\r\n viewToggle={resolvedViewToggle}\r\n savedViews={\r\n props.persistId ? (\r\n <TableToolbarViews\r\n views={viewsForToolbar}\r\n activeViewId={savedViews.currentViewId ?? undefined}\r\n onApply={handleViewApply}\r\n onApplyDefault={applyDefault}\r\n onDelete={savedViews.deleteView}\r\n onSave={async (data) => {\r\n await saveCurrentAsView(data.name, {\r\n isPublic: data.isPublic,\r\n });\r\n }}\r\n soloLabel={toolbarConfig.title}\r\n hideDivider\r\n allowCreate={props.allowCreateView !== false}\r\n // Sem esta linha, `maxTabs` ficava preso no default 3 do\r\n // TableToolbarViews e o 3º preset sumia da barra em silêncio, sem\r\n // o consumidor ter como aumentar. `undefined` mantém o default.\r\n maxTabs={props.maxViewTabs}\r\n />\r\n ) : undefined\r\n }\r\n refresh={\r\n toolbarConfig.enableRefresh !== false ? (\r\n <ToolbarToolButton\r\n icon={\r\n <RefreshCw\r\n className={isRefreshing ? \"animate-spin\" : \"\"}\r\n />\r\n }\r\n aria-label=\"Atualizar\"\r\n onClick={handleRefresh}\r\n />\r\n ) : undefined\r\n }\r\n search={\r\n toolbarConfig.enableSearch !== false ? (\r\n <ToolbarSearch\r\n value={search.inputValue}\r\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\r\n search.setInputValue(e.target.value)\r\n }\r\n // Enter/Escape tiram o foco → no mobile o teclado fecha\r\n // (busca é live, não precisa de submit; o \"ir\" do teclado\r\n // não tinha efeito e o teclado ficava preso).\r\n onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {\r\n if (e.key === \"Enter\" || e.key === \"Escape\") {\r\n e.currentTarget.blur();\r\n }\r\n }}\r\n placeholder=\"Buscar...\"\r\n />\r\n ) : undefined\r\n }\r\n filter={\r\n toolbarConfig.enableFilters !== false &&\r\n filterPopoverColumns.length > 0 ? (\r\n // Conta só entries com valor real — uma linha recém-adicionada\r\n // no query builder e ainda vazia NÃO ativa o indicador. O\r\n // unmount-purge do FilterPanel remove a linha em branco ao fechar.\r\n <ToolbarFilterButton\r\n isActive={hasActiveFilter}\r\n hasIndicator={hasActiveFilter}\r\n onClick={() => setV2FilterOpen(true)}\r\n />\r\n ) : undefined\r\n }\r\n actions={\r\n toolbarConfig.actions && toolbarConfig.actions.length > 0 ? (\r\n <ToolbarActions actions={toolbarConfig.actions} />\r\n ) : undefined\r\n }\r\n fullscreen={\r\n enableFullscreen ? (\r\n <ToolbarToolButton\r\n icon={isFullscreen ? <Minimize2 /> : <Maximize2 />}\r\n aria-label={\r\n isFullscreen ? \"Sair da tela cheia\" : \"Tela cheia\"\r\n }\r\n isActive={isFullscreen}\r\n onClick={toggleFullscreen}\r\n />\r\n ) : undefined\r\n }\r\n settings={\r\n <ToolbarSettingsMenu\r\n trigger={\r\n <ToolbarToolButton\r\n icon={<Settings2 />}\r\n aria-label=\"Configurações da tabela\"\r\n />\r\n }\r\n sortPanel={(onBack) => (\r\n <SortPanel\r\n onBack={onBack}\r\n columns={sortPopoverColumns}\r\n sortBy={sortPopoverCriteria}\r\n onSortByChange={handleSortChange}\r\n />\r\n )}\r\n colsPanel={\r\n toolbarConfig.enableColumns !== false\r\n ? (onBack) => (\r\n <ColsPanel\r\n onBack={onBack}\r\n columns={colsPopoverColumns}\r\n visibleCols={visibleColsSet}\r\n onVisibleChange={handleVisibleChange}\r\n pinnedCols={pinnedColsSet}\r\n onPinnedChange={handlePinnedChange}\r\n onColumnsReorder={handleColumnsReorder}\r\n />\r\n )\r\n : undefined\r\n }\r\n filterPanel={\r\n toolbarConfig.enableFilters !== false &&\r\n filterPopoverColumns.length > 0\r\n ? (onBack) => (\r\n <FilterPanel\r\n onBack={onBack}\r\n columns={filterPopoverColumns}\r\n filters={filterPopoverEntries}\r\n onFiltersChange={handleFiltersChange}\r\n enableAdvanced\r\n renderValueInput={({\r\n column,\r\n operator,\r\n value,\r\n onChange,\r\n }) => {\r\n const typeId =\r\n column.filterType ?? column.type ?? \"text\";\r\n const def = columnTypeRegistry.get(typeId);\r\n // op já em id longo do FilterModel — sem remap.\r\n const filterOp =\r\n operator as FilterItem[\"operator\"];\r\n return def.renderFilterInput({\r\n value: value as FilterValue,\r\n onChange: (v) => onChange(v),\r\n operator: filterOp,\r\n options: column.options,\r\n });\r\n }}\r\n getOperatorsForColumn={(column) => {\r\n const typeId =\r\n column.filterType ?? column.type ?? \"text\";\r\n const def = columnTypeRegistry.get(typeId);\r\n return def.operators?.map((o) => ({\r\n id: o.id,\r\n label: o.label,\r\n }));\r\n }}\r\n />\r\n )\r\n : undefined\r\n }\r\n density={\r\n toolbarConfig.enableDensity !== false ? (\r\n <ToolbarSegmented\r\n fluid\r\n value={density.density}\r\n onValueChange={(v) =>\r\n density.setDensity(v as TableDensity)\r\n }\r\n items={props.densityItems ?? DENSITY_ITEMS}\r\n ariaLabel=\"Densidade da tabela\"\r\n />\r\n ) : undefined\r\n }\r\n mobileViewToggle={\r\n resolvedViewToggle ? (\r\n (props.kanbanConfig || props.listConfig) &&\r\n props.toolbar?.viewToggle === undefined ? (\r\n <ToolbarSegmented\r\n fluid\r\n value={viewMode}\r\n onValueChange={handleViewModeChange}\r\n items={mobileViewItems}\r\n ariaLabel=\"Modo de visualização\"\r\n />\r\n ) : (\r\n resolvedViewToggle\r\n )\r\n ) : undefined\r\n }\r\n mobileDisplayToggle={\r\n // Linhas vs Cards — só faz sentido quando o card é possível\r\n // (viewport mobile + cardBreakpoint != false + não-kanban).\r\n cardPossible ? (\r\n <ToolbarSegmented\r\n fluid\r\n value={mobileDisplay}\r\n onValueChange={(v) =>\r\n setMobileDisplay(v as \"table\" | \"card\")\r\n }\r\n items={[\r\n {\r\n value: \"table\",\r\n label: \"Linhas\",\r\n children: (\r\n <span className=\"inline-flex items-center gap-gp-sm\">\r\n <Rows3 /> Linhas\r\n </span>\r\n ),\r\n },\r\n {\r\n value: \"card\",\r\n label: \"Cards\",\r\n children: (\r\n <span className=\"inline-flex items-center gap-gp-sm\">\r\n <LayoutGrid /> Cards\r\n </span>\r\n ),\r\n },\r\n ]}\r\n ariaLabel=\"Exibição da tabela\"\r\n />\r\n ) : undefined\r\n }\r\n mobileViews={\r\n props.persistId && (props.defaultViews?.length ?? 0) > 0\r\n ? {\r\n items: viewsForToolbar\r\n .filter((v) => v.owner === \"preset\")\r\n .map((v) => ({ id: v.id, name: v.name })),\r\n activeId: savedViews.currentViewId ?? undefined,\r\n onSelect: handleViewApply,\r\n }\r\n : undefined\r\n }\r\n />\r\n }\r\n more={\r\n exportConfig || toolbarConfig.moreMenu?.items?.length ? (\r\n <MoreMenu\r\n trigger={\r\n <ToolbarToolButton\r\n icon={<MoreHorizontal />}\r\n aria-label=\"Opções\"\r\n />\r\n }\r\n >\r\n {exportConfig &&\r\n exportConfig.formats.map((fmt) => {\r\n const isCsvDefault = fmt.id === \"csv\" && !fmt.onSelect;\r\n if (!isCsvDefault) {\r\n return (\r\n <MoreMenuItemEl\r\n key={fmt.id}\r\n onSelect={fmt.onSelect}\r\n >\r\n {fmt.icon}\r\n {fmt.label}\r\n </MoreMenuItemEl>\r\n );\r\n }\r\n return isServerMode ? (\r\n <MoreMenuItemEl\r\n key={fmt.id}\r\n onSelect={() => exporter.exportCsv(\"all\")}\r\n >\r\n {fmt.icon}\r\n {fmt.label} — Página atual\r\n </MoreMenuItemEl>\r\n ) : (\r\n <span key={fmt.id} className=\"contents\">\r\n <MoreMenuItemEl\r\n onSelect={() => exporter.exportCsv(\"all\")}\r\n >\r\n {fmt.icon}\r\n {fmt.label} — Todos\r\n </MoreMenuItemEl>\r\n <MoreMenuItemEl\r\n onSelect={() => exporter.exportCsv(\"filtered\")}\r\n >\r\n {fmt.icon}\r\n {fmt.label} — Filtrados\r\n </MoreMenuItemEl>\r\n <MoreMenuItemEl\r\n onSelect={() => exporter.exportCsv(\"selected\")}\r\n disabled={selection.selectedCount === 0}\r\n >\r\n {fmt.icon}\r\n {fmt.label} — Selecionados (\r\n {selection.selectedCount})\r\n </MoreMenuItemEl>\r\n </span>\r\n );\r\n })}\r\n {exportConfig && toolbarConfig.moreMenu?.items?.length ? (\r\n <MoreMenuSeparator />\r\n ) : null}\r\n {toolbarConfig.moreMenu?.items?.map((it) => (\r\n <MoreMenuItemEl\r\n key={it.id}\r\n onSelect={it.onSelect}\r\n disabled={it.disabled}\r\n variant={it.destructive ? \"destructive\" : \"default\"}\r\n >\r\n {it.icon}\r\n {it.label}\r\n </MoreMenuItemEl>\r\n ))}\r\n </MoreMenu>\r\n ) : undefined\r\n }\r\n bulkBar={\r\n selectionConfig.enabled && selection.selectedCount > 0 ? (\r\n <BulkActionsBar\r\n count={selection.selectedCount}\r\n onClear={selection.clear}\r\n >\r\n {selectionConfig.actions?.(\r\n selection.selectedIds,\r\n selection.clear,\r\n )}\r\n </BulkActionsBar>\r\n ) : undefined\r\n }\r\n />\r\n {/* Drawer do filtro simples (funil) — só v2 */}\r\n {toolbarConfig.enableFilters !== false &&\r\n filterPopoverColumns.length > 0 && (\r\n <SimpleFilterDrawer\r\n open={v2FilterOpen}\r\n onOpenChange={setV2FilterOpen}\r\n columns={filterPopoverColumns}\r\n filterModel={filters.filterModel}\r\n onFilterModelChange={filters.setFilterModel}\r\n hiddenFields={props.simpleFilter?.hiddenFields}\r\n title={props.simpleFilter?.title}\r\n size={props.simpleFilter?.size}\r\n />\r\n )}\r\n </>\r\n\r\n {/* Applied filter chips — agrupados por field+operator, clicaveis via renderChip → Popover.\r\n `pendingOpenId` deixa ToolbarApplied controlar visual de \"abrir auto\" sem\r\n o DataTable precisar saber qual chip está pendente (state mora no toolbar). */}\r\n <ToolbarApplied\r\n filters={enhancedAppliedFilters}\r\n onRemove={handleRemoveFilter}\r\n onClearAll={filters.clearFilters}\r\n pendingOpenId={pendingOpenChipKey}\r\n onPendingOpenIdChange={setPendingOpenChipKey}\r\n renderChip={(f, defaultChip, isPendingOpen) => {\r\n // Chip placeholder (showEmptyFilterChips array). Não tem group no\r\n // appliedGroups — clica → ativa o filtro (cria item vazio + abre popover).\r\n if (f.id.startsWith(PLACEHOLDER_ID_PREFIX)) {\r\n const field = f.id.slice(PLACEHOLDER_ID_PREFIX.length);\r\n return (\r\n <div\r\n role=\"button\"\r\n tabIndex={0}\r\n onClick={() => handleActivatePlaceholder(field)}\r\n onKeyDown={(e) => {\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n handleActivatePlaceholder(field);\r\n }\r\n }}\r\n className=\"contents cursor-pointer\"\r\n >\r\n {defaultChip}\r\n </div>\r\n );\r\n }\r\n const group = appliedGroups.find((g) => g.key === f.id);\r\n if (!group) return defaultChip;\r\n const col = colsByField.get(group.field);\r\n const items = group.items;\r\n // `between` (date/number range) é um caso especial — operador tupla.\r\n // Não spread, não promove pra multiSelect, usa o column-type direto\r\n // e passa value como tupla pro renderFastFilterInput.\r\n const isTupleOperator = group.operator === \"between\";\r\n const aggregateValues = isTupleOperator\r\n ? []\r\n : items.flatMap((it) =>\r\n Array.isArray(it.value)\r\n ? (it.value as unknown[])\r\n : it.value != null\r\n ? [it.value]\r\n : [],\r\n );\r\n const useMulti =\r\n !isTupleOperator &&\r\n (aggregateValues.length > 1 ||\r\n group.operator === \"isAnyOf\" ||\r\n group.operator === \"isNoneOf\" ||\r\n col?.filterType === \"multiSelect\" ||\r\n (col?.filterType === \"select\" &&\r\n (col?.filterOptions?.length ?? 0) > 0));\r\n const def = columnTypeRegistry.get(\r\n isTupleOperator\r\n ? (col?.filterType ?? \"text\")\r\n : useMulti\r\n ? \"multiSelect\"\r\n : (col?.filterType ?? \"text\"),\r\n );\r\n // currentValue:\r\n // - tuple (between): pega o value do primeiro item (já é tupla)\r\n // - multi: array agregado\r\n // - single: primeiro valor agregado\r\n const currentValue = isTupleOperator\r\n ? (items[0]?.value as unknown)\r\n : useMulti\r\n ? aggregateValues\r\n : aggregateValues[0];\r\n const options = getGroupOptions(group.key);\r\n // Controlled open: `isPendingOpen` vem do ToolbarApplied via\r\n // `pendingOpenId` prop — state mora no toolbar, DataTable só\r\n // controla quando setar via `setPendingOpenChipKey`.\r\n // Ao fechar, se o grupo só tem itens com valor vazio (caso do\r\n // shortcut que abriu mas user nao digitou nada), remove do filterModel.\r\n // Open controlado: pending (shortcut do header) OU clique no chip.\r\n // Controlar o open é o que permite o `onClose` fechar o popover\r\n // mesmo quando o `<Select open>` interno trava o clique-fora.\r\n const closeChip = () => {\r\n setOpenChipKey(null);\r\n if (isPendingOpen) setPendingOpenChipKey(null);\r\n // Cleanup: remove itens vazios deste grupo do filterModel\r\n const groupItems = group.items;\r\n const allEmpty = groupItems.every((it) =>\r\n isFilterValueEmpty(it.value),\r\n );\r\n if (allEmpty) {\r\n const ids = new Set(groupItems.map((it) => it.id));\r\n filters.setFilterModel({\r\n ...filters.filterModel,\r\n items: filters.filterModel.items.filter(\r\n (it) => !ids.has(it.id),\r\n ),\r\n });\r\n }\r\n };\r\n return (\r\n <Popover\r\n open={isPendingOpen || openChipKey === f.id}\r\n onOpenChange={(o) => {\r\n if (o) {\r\n setOpenChipKey(f.id);\r\n return;\r\n }\r\n closeChip();\r\n }}\r\n >\r\n <PopoverTrigger asChild>{defaultChip}</PopoverTrigger>\r\n <PopoverContent align=\"start\" className=\"p-0\">\r\n {def.renderFastFilterInput({\r\n value: currentValue as FilterValue,\r\n onChange: (v) => updateGroupValue(group.key, v),\r\n options,\r\n onClose: closeChip,\r\n })}\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n }}\r\n />\r\n </div>\r\n\r\n {/* Conteúdo */}\r\n {isLoading ? (\r\n (props.renderLoading ?? <DataTableLoading />)\r\n ) : isKanban ? (\r\n // Kanban gerencia seu próprio empty state interno (coluna sem cards).\r\n // Filter/search/sort/selection já estão aplicados via rowsAllPagesProcessed.\r\n <Kanban\r\n columns={kanbanView.columns}\r\n cards={kanbanView.cards}\r\n // Selection (bridge)\r\n selectedIds={kanbanSelectedIds}\r\n onToggleSelect={kanbanSelectedIds ? kanbanToggleSelect : undefined}\r\n // Detail panel (controlled) + click\r\n openCardId={props.kanbanConfig?.openCardId}\r\n onOpenCard={kanbanOnOpenCard}\r\n // Add card (botões \"+\" header + footer)\r\n onAddCard={props.kanbanConfig?.onAddCard}\r\n onAddInFooter={props.kanbanConfig?.onAddInFooter}\r\n hideFooterAdd={props.kanbanConfig?.hideFooterAdd}\r\n // Menus (auto via items OU manual via callback — items ganham se ambos definidos)\r\n getCardMenuItems={kanbanGetCardMenuItems}\r\n onCardMenu={\r\n kanbanGetCardMenuItems\r\n ? undefined\r\n : props.kanbanConfig?.onCardMenu\r\n }\r\n getColumnMenuItems={props.kanbanConfig?.getColumnMenuItems}\r\n onColumnMenu={\r\n props.kanbanConfig?.getColumnMenuItems\r\n ? undefined\r\n : props.kanbanConfig?.onColumnMenu\r\n }\r\n // Card content custom (override total do miolo)\r\n renderCard={kanbanRenderCardContent}\r\n // DnD\r\n enableDnD={props.kanbanConfig?.enableDnD}\r\n onCardMove={props.kanbanConfig?.onCardMove}\r\n // Textos\r\n emptyLabel={props.kanbanConfig?.emptyLabel}\r\n addLabel={props.kanbanConfig?.addLabel}\r\n />\r\n ) : isList && props.listConfig ? (\r\n // Lista: corpo trocado por <List> (mesma toolbar do DataTable).\r\n // Rows já filtradas/buscadas/ordenadas via rowsAllPagesProcessed.\r\n <div className=\"min-h-0 flex-1 overflow-auto scrollbar-thin\">\r\n <List\r\n items={listItems}\r\n layout={props.listConfig.hierarchical ? \"hierarchical\" : \"standard\"}\r\n branchHighlight=\"none\"\r\n defaultExpandedIds={listDefaultExpandedIds}\r\n renderItem={(item, state) =>\r\n props.listConfig!.renderItem(item.data as T, {\r\n depth: state.depth,\r\n open: state.open,\r\n })\r\n }\r\n onItemClick={\r\n props.onRowClick\r\n ? (id) => {\r\n const row = rowsAllPagesProcessed.find(\r\n (r) => String(contextValue.getRowId(r)) === id,\r\n );\r\n if (row) props.onRowClick!(row);\r\n }\r\n : undefined\r\n }\r\n getMenuItems={\r\n props.listConfig.getMenuItems\r\n ? (item) => props.listConfig!.getMenuItems!(item.data as T)\r\n : undefined\r\n }\r\n />\r\n </div>\r\n ) : isDataEmpty ? (\r\n (props.renderEmpty ?? <DataTableEmpty />)\r\n ) : isNoResults ? (\r\n (props.renderNoResults ?? (\r\n <DataTableNoResults\r\n onClearFilters={() => {\r\n filters.setFilterModel({ items: [], logicOperator: \"AND\" });\r\n search.setInputValue(\"\");\r\n }}\r\n />\r\n ))\r\n ) : isCardMode ? (\r\n cardBody\r\n ) : (\r\n tableBody\r\n )}\r\n\r\n {/* Footer (paginação) — só na view table.\r\n Durante loading mostra skeleton no lugar (mesma silhueta) pra\r\n evitar paginação \"1 página\" enquanto fetchData responde. */}\r\n {!isKanban &&\r\n (!isList ||\r\n (props.listConfig?.paginated && !props.listConfig?.hierarchical)) &&\r\n !useTreeData &&\r\n paginationConfig.enabled !== false &&\r\n (isLoading ? (\r\n <div className={styles.footerWrap()}>\r\n <FooterTableSkeleton />\r\n </div>\r\n ) : (\r\n !isDataEmpty && (\r\n <div className={styles.footerWrap()}>\r\n <FooterTable\r\n totalCount={totalAfterFilter}\r\n page={pagination.paginationModel.page}\r\n pageSize={pagination.paginationModel.pageSize}\r\n onPageChange={pagination.setPage}\r\n onPageSizeChange={pagination.setPageSize}\r\n pageSizeOptions={paginationConfig.pageSizeOptions}\r\n selectionCount={selection.selectedCount}\r\n />\r\n </div>\r\n )\r\n ))}\r\n </div>\r\n </DataTableProvider>\r\n );\r\n}\r\n\r\ntype DataTableComponent = <T>(\r\n props: DataTableProps<T> & { ref?: Ref<DataTableRef> },\r\n) => React.ReactElement;\r\n\r\nexport const DataTable = forwardRef(DataTableInternal) as DataTableComponent;\r\n","import type { ReactNode } from \"react\";\r\nimport { X } from \"lucide-react\";\r\nimport { Button } from \"@/components/ui/Button/button\";\r\nimport { dataTableStyles } from \"../data-table.styles\";\r\n\r\nconst styles = dataTableStyles();\r\n\r\nexport type DataTableFloatingBulkBarProps = {\r\n count: number;\r\n onClear: () => void;\r\n /** Render custom de actions a direita do count. */\r\n actions?: ReactNode;\r\n};\r\n\r\n/**\r\n * @deprecated DataTable usa `TableToolbar.bulkBar` slot com `<BulkActionsBar>`\r\n * inline desde 2026-05-12. Este componente flutuante é mantido por\r\n * backward-compat pra consumers standalone. Avaliar remoção em V2.\r\n */\r\nexport function DataTableFloatingBulkBar({\r\n count,\r\n onClear,\r\n actions,\r\n}: DataTableFloatingBulkBarProps) {\r\n if (count === 0) return null;\r\n return (\r\n <div className={styles.bulkBar()} role=\"region\" aria-label=\"Acoes em massa\">\r\n <span className=\"text-body-md font-medium whitespace-nowrap\">\r\n {count} selecionado{count > 1 ? \"s\" : \"\"}\r\n </span>\r\n {actions && <div className=\"flex items-center gap-gp-sm\">{actions}</div>}\r\n <Button\r\n size=\"icon-xs\"\r\n variant=\"ghost\"\r\n color=\"secondary\"\r\n aria-label=\"Limpar selecao\"\r\n onClick={onClear}\r\n >\r\n <X />\r\n </Button>\r\n </div>\r\n );\r\n}\r\n","import type {\n DataTablePresetView,\n DataTableViewMode,\n FilterItem,\n FilterModel,\n FilterOperator,\n FilterValue,\n GridRowId,\n SortModel,\n} from \"../data-table.types\";\nimport type { ColumnPinned, TableDensity } from \"../../Table\";\n\n/**\n * Filtro simplificado pra builder — `id` gerado automaticamente, `logicOperator`\n * default \"AND\". Consumer só fornece field/operator/value.\n */\nexport type PresetFilterInput = {\n field: string;\n operator?: FilterOperator;\n value?: FilterValue;\n};\n\nexport type PresetViewInput = {\n /** ID único e estável — sugerido prefixo `preset:` (ex: `\"preset:ativos\"`). */\n id: string;\n /** Label da view nos tabs e popovers. */\n name: string;\n /**\n * Filtros aplicados. Forma curta: `[{ field, operator?, value? }]`.\n * Operator default = `\"equals\"`. `id` é gerado automaticamente.\n */\n filters?: PresetFilterInput[];\n /** Combinação dos filtros — `\"AND\"` (default) ou `\"OR\"`. */\n filterLogic?: \"AND\" | \"OR\";\n /** Multi-sort: `[{ field, direction }]`. Default `[]`. */\n sort?: SortModel[];\n /** Density visual. Default `\"standard\"`. */\n density?: TableDensity;\n /** Colunas escondidas (default `[]`). */\n hiddenColumns?: string[];\n /** Pin por field — `{ \"field\": \"left\" | \"right\" }`. Default `{}`. */\n pinnedColumns?: Record<string, ColumnPinned>;\n /** Width override por field (px). Default `{}`. */\n columnWidths?: Record<string, number>;\n /** Ordem visual das colunas. Default = ordem original. */\n columnOrder?: string[];\n /** Modo de visualização — `\"table\"` (default) ou `\"kanban\"`. */\n viewMode?: DataTableViewMode;\n /** Field pelo qual agrupar (sem agrupamento se ausente). */\n groupBy?: string;\n /** Rows que iniciam expandidas. Default `[]`. */\n expandedRowIds?: GridRowId[];\n};\n\n/**\n * Builder pra declarar `DataTablePresetView` com defaults razoáveis e shape\n * mínimo. Elimina boilerplate de `filterModel.items[0].id`, `logicOperator`,\n * `sortModel: []`, etc.\n *\n * Exemplos:\n *\n * ```tsx\n * // Filtro simples\n * presetView({\n * id: \"preset:ativos\",\n * name: \"Ativos\",\n * filters: [{ field: \"statusId\", value: \"active\" }],\n * });\n *\n * // Kanban view agrupada\n * presetView({\n * id: \"preset:pipeline\",\n * name: \"Pipeline (Kanban)\",\n * viewMode: \"kanban\",\n * groupBy: \"statusId\",\n * });\n *\n * // Multi-filter + sort + layout customizado\n * presetView({\n * id: \"preset:high-value\",\n * name: \"Alto valor (decrescente)\",\n * filters: [\n * { field: \"value\", operator: \"gt\", value: 10000 },\n * { field: \"statusId\", value: \"active\" },\n * ],\n * sort: [{ field: \"value\", direction: \"desc\" }],\n * pinnedColumns: { name: \"left\" },\n * hiddenColumns: [\"lastContact\"],\n * });\n * ```\n */\nexport function presetView(input: PresetViewInput): DataTablePresetView {\n const {\n id,\n name,\n filters = [],\n filterLogic = \"AND\",\n sort = [],\n density = \"standard\",\n hiddenColumns,\n pinnedColumns,\n columnWidths,\n columnOrder,\n viewMode,\n groupBy,\n expandedRowIds,\n } = input;\n\n const filterItems: FilterItem[] = filters.map((f, idx) => ({\n id: `${id}-filter-${idx}`,\n field: f.field,\n operator: f.operator ?? \"equals\",\n value: f.value,\n }));\n\n const filterModel: FilterModel = {\n items: filterItems,\n logicOperator: filterLogic,\n };\n\n return {\n id,\n name,\n state: {\n filterModel,\n sortModel: sort,\n density,\n hiddenColumns,\n pinnedColumns,\n columnWidths,\n columnOrder,\n viewMode,\n groupBy,\n expandedRowIds,\n },\n };\n}\n","import { tv } from \"@/utils/tv\";\r\n\r\n/**\r\n * Panel styles — alinhado com `.tbl-form-drawer` do design-and-table-v2.\r\n *\r\n * Spec sandbox:\r\n * - position: fixed top/right/bottom 24px (gutter)\r\n * - width: 560px (default), max-width: calc(100vw - 48px)\r\n * - bg-bg-surface (light) / bg-bg-canvas (dark)\r\n * - border 1px + radius 14px (= radius-xl)\r\n * - shadow-sh-2xl + halo outline (6px alpha)\r\n * - flex column, overflow-hidden\r\n * - Mobile: ocupa quase tudo (gutter reduzido)\r\n */\r\n\r\n/* ── Container (override do SheetContent) ─────────────────────────────────── */\r\n/**\r\n * Container \"card flutuante\" estilo iGreen — fica destacado do viewport com\r\n * gutter de 24px, radius e halo. Responsivo: gutter encolhe no mobile.\r\n */\r\nexport const panelContainer = tv({\r\n base: [\r\n \"flex flex-col overflow-hidden\",\r\n \"rounded-radius-xl border border-border-default\",\r\n // Outline padrão de elementos flutuantes\r\n \"outline-float\",\r\n // Altura/largura responde ao side via inset (desktop):\r\n // right/left → inset-y define height, sizeClass define width\r\n // top/bottom → inset-x define width, height auto\r\n //\r\n // Mobile (max-md) — independente do side, vira sheet bottom-up colado nas\r\n // bordas do device: flush nas laterais + bottom, só topo arredondado, sem\r\n // outline/shadow, cap 92vh. Backdrop suave já vem do SheetOverlay (modal).\r\n // top-auto + bottom-0 sobrescrevem o inset-y-pad-4xl do desktop (media query\r\n // vence). NÃO usar inset-y-auto aqui — ele zeraria o bottom-0 (tailwind-merge\r\n // trata inset-y como superset de bottom e removeria a âncora).\r\n \"max-md:inset-x-0 max-md:bottom-0 max-md:top-auto max-md:!w-auto\",\r\n \"max-md:max-h-[92vh] max-md:rounded-b-none max-md:border-x-0 max-md:border-b-0\",\r\n \"max-md:outline-none max-md:shadow-none\",\r\n ],\r\n variants: {\r\n side: {\r\n right: \"inset-y-pad-4xl right-pad-4xl\",\r\n left: \"inset-y-pad-4xl left-pad-4xl\",\r\n top: \"inset-x-pad-4xl top-pad-4xl\",\r\n bottom: \"inset-x-pad-4xl bottom-pad-4xl\",\r\n },\r\n },\r\n});\r\n\r\n/* ── Header (.tbl-form-drawer-head) ───────────────────────────────────────── */\r\nexport const panelHeader = tv({\r\n base: [\r\n \"flex items-center justify-between gap-gp-xl flex-none\",\r\n \"px-[20px] py-[18px]\",\r\n \"border-b border-border-default\",\r\n ],\r\n});\r\n\r\nexport const panelHeaderText = tv({\r\n base: \"flex flex-col gap-gp-2xs min-w-0\",\r\n});\r\n\r\nexport const panelTitle = tv({\r\n base: [\r\n \"flex items-center gap-gp-md min-w-0\",\r\n \"text-body-lg font-bold text-fg-default tracking-[-0.01em]\",\r\n \"truncate\",\r\n ],\r\n});\r\n\r\nexport const panelTitleIcon = tv({\r\n base: \"size-[18px] text-fg-brand shrink-0\",\r\n});\r\n\r\nexport const panelDescription = tv({\r\n base: \"text-body-md text-fg-muted\",\r\n});\r\n\r\nexport const panelClose = tv({\r\n base: [\r\n \"grid place-items-center shrink-0\",\r\n \"w-form-sm h-form-sm rounded-radius-md\",\r\n \"bg-transparent border-0 cursor-pointer\",\r\n \"text-fg-muted opacity-60\",\r\n \"transition-[background-color,color,opacity] duration-150\",\r\n \"hover:bg-bg-muted hover:text-fg-default hover:opacity-100\",\r\n \"focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-secondary focus-visible:opacity-100\",\r\n \"dark:hover:bg-bg-muted-hover\",\r\n ],\r\n});\r\n\r\n/* ── Body (.tbl-form-drawer-body) ─────────────────────────────────────────── */\r\nexport const panelBody = tv({\r\n base: [\r\n // min-h-0 garante que o flex-1 encolha e o scroll ative (em vez de empurrar\r\n // header/footer). Scroll automático independente de viewport.\r\n \"flex-1 min-h-0 overflow-y-auto\",\r\n \"flex flex-col gap-gp-3xl\", // 20px gap entre form sections\r\n \"py-pad-4xl px-pad-3xl\", // 24px vertical / 20px horizontal\r\n \"scrollbar-thin\",\r\n ],\r\n});\r\n\r\n/* ── Footer (.tbl-form-drawer-foot) ───────────────────────────────────────── */\r\nexport const panelFooter = tv({\r\n base: [\r\n // Botões fluidos lado a lado; quebram pra empilhados quando não cabem.\r\n \"flex flex-wrap items-center gap-gp-md flex-none\",\r\n \"[&>*]:flex-1 [&>*]:min-w-[140px]\",\r\n \"px-[20px] py-[14px]\",\r\n \"border-t border-border-default\",\r\n ],\r\n});\r\n","import { X } from \"lucide-react\";\r\nimport { SheetClose, SheetTitle, SheetDescription } from \"@/components/shadcn/sheet\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport {\r\n panelHeader,\r\n panelHeaderText,\r\n panelTitle,\r\n panelTitleIcon,\r\n panelDescription,\r\n panelClose,\r\n} from \"./panel.styles\";\r\nimport type { LucideIcon } from \"@/lib/lucide-types\";\r\n\r\nexport type PanelHeaderProps = {\r\n title?: string;\r\n description?: string;\r\n titleIcon?: LucideIcon;\r\n /** Esconde o botão X de fechar */\r\n hideClose?: boolean;\r\n /** className do container do header */\r\n className?: string;\r\n};\r\n\r\nexport function PanelHeader({\r\n title,\r\n description,\r\n titleIcon: TitleIcon,\r\n hideClose,\r\n className,\r\n}: PanelHeaderProps) {\r\n return (\r\n <header className={cn(panelHeader(), className)}>\r\n <div className={panelHeaderText()}>\r\n {title && (\r\n <SheetTitle asChild>\r\n <h2 className={panelTitle()}>\r\n {TitleIcon && <TitleIcon className={panelTitleIcon()} strokeWidth={1.8} />}\r\n <span className=\"truncate\">{title}</span>\r\n </h2>\r\n </SheetTitle>\r\n )}\r\n {description && (\r\n <SheetDescription asChild>\r\n <p className={panelDescription()}>{description}</p>\r\n </SheetDescription>\r\n )}\r\n </div>\r\n {!hideClose && (\r\n <SheetClose className={panelClose()} aria-label=\"Fechar\">\r\n <X size={18} strokeWidth={1.7} />\r\n </SheetClose>\r\n )}\r\n </header>\r\n );\r\n}\r\n","import type { ReactNode } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { panelBody } from \"./panel.styles\";\n\nexport type PanelBodyProps = {\n children: ReactNode;\n className?: string;\n};\n\n/**\n * Container do body do panel — scroll interno, gap padrão entre seções.\n */\nexport function PanelBody({ children, className }: PanelBodyProps) {\n return <div className={cn(panelBody(), className)}>{children}</div>;\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { panelFooter } from \"./panel.styles\";\n\nexport type PanelFooterProps = {\n children: ReactNode;\n className?: string;\n};\n\n/**\n * Footer do panel — geralmente botões de ação alinhados à direita\n * (Cancelar / Salvar). Padding e border-top já aplicados.\n */\nexport function PanelFooter({ children, className }: PanelFooterProps) {\n return <footer className={cn(panelFooter(), className)}>{children}</footer>;\n}\n","import * as SheetPrimitive from \"@radix-ui/react-dialog\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport {\r\n Sheet,\r\n SheetTrigger,\r\n SheetOverlay,\r\n} from \"@/components/shadcn/sheet\";\r\nimport { panelContainer } from \"./panel.styles\";\r\nimport { PanelHeader } from \"./panel-header\";\r\nimport { PanelBody } from \"./panel-body\";\r\nimport { PanelFooter } from \"./panel-footer\";\r\nimport type { PanelProps, PanelSide, PanelSize } from \"./panel.types\";\r\n\r\n/**\r\n * Width pré-definida por size. `full` ocupa o viewport menos o gutter (24px each side).\r\n * Aceita também string CSS arbitrária (ex: \"720px\", \"60vw\").\r\n */\r\nconst SIZE_MAP: Record<PanelSize, string> = {\r\n sm: \"w-[320px]\",\r\n md: \"w-[560px]\",\r\n lg: \"w-[720px]\",\r\n xl: \"w-[920px]\",\r\n full: \"w-[calc(100vw-48px)] max-md:w-[calc(100vw-16px)]\",\r\n};\r\n\r\nfunction resolveSize(size?: PanelSize | string): string {\r\n if (!size) return SIZE_MAP.md;\r\n if (size in SIZE_MAP) return SIZE_MAP[size as PanelSize];\r\n return `w-[${size}]`;\r\n}\r\n\r\n/**\r\n * Slide-in animations por side. Distância 12 (= 48px ≈ 8% do panel md 560px) +\r\n * duration 220ms + easing custom (matching .tbl-form-drawer do sandbox).\r\n *\r\n * Desktop (md+): slide direcional conforme `side`.\r\n * Mobile (max-md): independente do side, slide bottom-up (sheet colado embaixo).\r\n */\r\nfunction slideAnimation(side: PanelSide): string {\r\n const desktop = {\r\n right: \"md:data-[state=closed]:slide-out-to-right-12 md:data-[state=open]:slide-in-from-right-12\",\r\n left: \"md:data-[state=closed]:slide-out-to-left-12 md:data-[state=open]:slide-in-from-left-12\",\r\n top: \"md:data-[state=closed]:slide-out-to-top-12 md:data-[state=open]:slide-in-from-top-12\",\r\n bottom: \"md:data-[state=closed]:slide-out-to-bottom-12 md:data-[state=open]:slide-in-from-bottom-12\",\r\n }[side];\r\n const mobile =\r\n \"max-md:data-[state=closed]:slide-out-to-bottom-12 max-md:data-[state=open]:slide-in-from-bottom-12\";\r\n return cn(\r\n \"ease-[cubic-bezier(0.4,0,0.2,1)]\",\r\n \"data-[state=open]:animate-in data-[state=closed]:animate-out\",\r\n \"data-[state=closed]:duration-[220ms] data-[state=open]:duration-[220ms]\",\r\n \"data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0\",\r\n desktop,\r\n mobile\r\n );\r\n}\r\n\r\n/**\r\n * Panel — drawer \"card flutuante\" estilo iGreen.\r\n *\r\n * Alinhado com `.tbl-form-drawer` do design-and-table-v2:\r\n * - Slide-in lateral (default: right) com gutter de 24px do viewport\r\n * - Radius 14px + halo outline + shadow-2xl\r\n * - Header (title + close X) + Body scrollável + Footer (actions)\r\n * - Mobile-adapt: vira sheet bottom-up colado nas bordas (flush x + bottom,\r\n * só topo arredondado, sem outline/shadow, max-height 92vh)\r\n *\r\n * Construído direto sobre SheetPrimitive.Content pra controle total do\r\n * positioning (evita conflito com inset-y-0/right-0/h-full do SheetContent).\r\n */\r\nexport function Panel({\r\n open,\r\n defaultOpen,\r\n onOpenChange,\r\n trigger,\r\n side = \"right\",\r\n size = \"md\",\r\n title,\r\n description,\r\n titleIcon,\r\n hideClose,\r\n footer,\r\n children,\r\n className,\r\n}: PanelProps) {\r\n const sizeClass = resolveSize(size);\r\n\r\n return (\r\n <Sheet open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\r\n {trigger && <SheetTrigger asChild>{trigger}</SheetTrigger>}\r\n <SheetPrimitive.Portal>\r\n <SheetOverlay />\r\n <SheetPrimitive.Content\r\n className={cn(\r\n \"fixed z-50 bg-bg-surface dark:bg-bg-canvas text-fg-default shadow-sh-2xl\",\r\n sizeClass,\r\n panelContainer({ side }),\r\n slideAnimation(side),\r\n className\r\n )}\r\n >\r\n <PanelHeader\r\n title={title}\r\n description={description}\r\n titleIcon={titleIcon}\r\n hideClose={hideClose}\r\n />\r\n <PanelBody>{children}</PanelBody>\r\n {footer && <PanelFooter>{footer}</PanelFooter>}\r\n </SheetPrimitive.Content>\r\n </SheetPrimitive.Portal>\r\n </Sheet>\r\n );\r\n}\r\n"],"names":["title","Avatar","AvatarGroup","ButtonGroupRoot","ButtonGroupPrimary","ButtonGroupChevron","Combobox","styles","TableRow","TableCell","TableHeadCell","DEFAULT_COLUMN_WIDTH","generateId","opValid","storageKey","formatShort","CalendarIcon","Calendar","column","toArray","normalize","LinkIcon","initials","color","columnTypeRegistry","isEmpty","s.board","s.root","s.card","s.column","s.columnDropInvalidDimmed","s.columnDropInvalidOver","s.columnDropTarget","s.columnHead","s.columnDot","s.columnTitle","s.columnCount","s.columnActionsSpacer","s.columnBody","s.columnEmpty","s.columnEmptyIcon","card","Fragment","s.columnAdd","s.dropPlaceholder","s.cardDragging","s.cardCheck","s.cardHead","s.cardTitleWrap","s.cardTitle","s.cardSubtitle","s.cardDesc","s.cardMeta","s.cardValue","s.cardFoot","s.cardMenuSlot","toggleRow","STORAGE_PREFIX","_","XIcon","groupItems","isFilterValueEmpty","value","TableIcon","ListIcon","FilterIcon","MoreMenuItemEl","MoreMenuSeparator","SimpleFilterDrawer"],"mappings":"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"}
|