@nextelco/common-ui 2.1.103 → 2.1.105
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/esm/assets/imagem-6ee08a37d9.png +0 -0
- package/dist/esm/assets/imagem-6fcae1b87b.png +0 -0
- package/dist/esm/index.js +142 -119
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/legacy/components/layout/Header/Header.css +1 -1
- package/dist/esm/legacy/components/molecules/PhotoAvatar/PhotoAvatar.js +9 -4
- package/dist/esm/legacy/components/molecules/PhotoAvatar/PhotoAvatar.js.map +1 -1
- package/dist/esm/legacy/components/molecules/Sidebar/Sidebar.css +1 -1
- package/dist/esm/legacy/components/organisms/RoleGuard/RoleGuard.js +14 -3
- package/dist/esm/legacy/components/organisms/RoleGuard/RoleGuard.js.map +1 -1
- package/dist/esm/legacy/pages/Error/ErrorPage.css +1 -1
- package/dist/esm/legacy/pages/Loading/Loading.css +2 -2
- package/dist/esm/legacy/pages/NotFound/NotFound.css +1 -1
- package/dist/esm/v1/components/lists/ListFinder/ListFinder.js +214 -0
- package/dist/esm/v1/components/lists/ListFinder/ListFinder.js.map +1 -0
- package/dist/esm/v1/components/lists/ListFinder/labels.js +18 -0
- package/dist/esm/v1/components/lists/ListFinder/labels.js.map +1 -0
- package/dist/esm/v1/components/tables/PaginatedTable/PaginatedTable.js +50 -0
- package/dist/esm/v1/components/tables/PaginatedTable/PaginatedTable.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/ColumnFilter.js +292 -0
- package/dist/esm/v1/components/tables/Table/ColumnFilter.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/OverlayScrollbar.js +129 -0
- package/dist/esm/v1/components/tables/Table/OverlayScrollbar.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/Table.js +1410 -0
- package/dist/esm/v1/components/tables/Table/Table.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/labels.js +44 -0
- package/dist/esm/v1/components/tables/Table/labels.js.map +1 -0
- package/dist/esm/v1/foundations/icons/icons.js +45 -2
- package/dist/esm/v1/foundations/icons/icons.js.map +1 -1
- package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js +32 -0
- package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js.map +1 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListCheckbox.js +28 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListCheckbox.js.map +1 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListItem.js +39 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListItem.js.map +1 -0
- package/dist/style.components.css +1 -1
- package/dist/style.css +1 -1
- package/dist/style.layered.css +1 -1
- package/dist/theme.css +256 -0
- package/dist/types/legacy/components/molecules/PhotoAvatar/PhotoAvatar.d.ts +2 -0
- package/dist/types/v1/components/lists/ListFinder/ListFinder.d.ts +60 -0
- package/dist/types/v1/components/lists/ListFinder/labels.d.ts +24 -0
- package/dist/types/v1/components/tables/PaginatedTable/PaginatedTable.d.ts +41 -0
- package/dist/types/v1/components/tables/Table/ColumnFilter.d.ts +48 -0
- package/dist/types/v1/components/tables/Table/OverlayScrollbar.d.ts +34 -0
- package/dist/types/v1/components/tables/Table/Table.d.ts +250 -0
- package/dist/types/v1/components/tables/Table/labels.d.ts +54 -0
- package/dist/types/v1/foundations/icons/icons.d.ts +17 -0
- package/dist/types/v1/index.d.ts +15 -1
- package/dist/types/v1/primitives/forms/Checkbox/Checkbox.d.ts +18 -0
- package/dist/types/v1/primitives/lists/ListItem/ListCheckbox.d.ts +14 -0
- package/dist/types/v1/primitives/lists/ListItem/ListItem.d.ts +35 -0
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Table.js","sources":["../../../../../../src/v1/components/tables/Table/Table.tsx"],"sourcesContent":["import React, { useState, useMemo, useRef, useEffect, useLayoutEffect, useCallback, Fragment } from 'react'\r\nimport {\r\n CheckIcon,\r\n ChevronDownIcon,\r\n ChevronLeftIcon,\r\n ChevronRightIcon,\r\n ChevronUpIcon,\r\n ChevronsUpDownIcon,\r\n CloseIcon,\r\n FilterIcon,\r\n LayersIcon,\r\n} from '../../../foundations/icons/icons'\r\nimport { ColumnFilter } from './ColumnFilter'\r\nimport { OverlayScrollbar } from './OverlayScrollbar'\r\nimport { DEFAULT_TABLE_LABELS, type TableLabels } from './labels'\r\n\r\nexport interface TableColumn<T> {\r\n /** Identifica a coluna (ordenação, filtros, agrupamento, ordem). Única na tabela. */\r\n key: string\r\n /** Título no cabeçalho. */\r\n label: string\r\n /** O que a célula mostra. */\r\n render: (row: T) => React.ReactNode\r\n /**\r\n * O valor por trás da célula: é por ele que se ordena, filtra e agrupa. Sem\r\n * ele a coluna não ordena, não filtra e não agrupa.\r\n */\r\n value?: (row: T) => string | number | null | undefined\r\n /** Por omissão `true` (quando há `value`). */\r\n sortable?: boolean\r\n /** Por omissão `true` (quando há `value`). */\r\n filterable?: boolean\r\n /**\r\n * Como se filtra esta coluna:\r\n * - `text` (omissão): lista de valores únicos com vistos\r\n * - `date`: intervalo De/Até\r\n * - `number`: intervalo Mín/Máx, ou a lista de valores\r\n *\r\n * Numa coluna de dinheiro ou de contagem, a lista de valores é inútil: são\r\n * centenas de números distintos, e ninguém procura \"10.04\".\r\n */\r\n filterType?: 'text' | 'date' | 'number'\r\n /** Agrupar é opt-in: só com `true`. Evita agrupar por valores contínuos (datas, decimais, €). */\r\n groupable?: boolean\r\n /**\r\n * Filtros extra no cabeçalho desta coluna, cada um com o seu funil.\r\n *\r\n * Para uma coluna que mostra mais do que um dado — um \"Início e Fim\" mostra\r\n * as duas pontas de um período, e um só filtro dava a lista dos PARES\r\n * (\"2026-07-03 → 2026-09-12\"), que não é por onde alguém procura.\r\n *\r\n * `filterType: 'date'` dá-lhe o intervalo De/Até em vez da lista de valores.\r\n */\r\n extraFilters?: {\r\n key: string\r\n label: string\r\n value: (row: T) => string | number | null | undefined\r\n filterType?: 'text' | 'date' | 'number'\r\n }[]\r\n headerClassName?: string\r\n cellClassName?: string\r\n /** Conteúdo extra por baixo do título da coluna (ex: um total). Recebe as linhas já filtradas. */\r\n headerExtra?: (rows: T[]) => React.ReactNode\r\n}\r\n\r\n/**\r\n * Ordenação e filtros do cabeçalho vivem dentro da tabela. Quem está por fora\r\n * (ex: exportar para Excel) precisa deles para não exportar linhas que a pessoa\r\n * filtrou fora: daí este handle, preenchido em `viewRef`.\r\n */\r\nexport interface TableView<T> {\r\n /** Aplica a ordenação e os filtros de coluna a qualquer lista (ex: o conjunto completo). */\r\n apply: (rows: T[]) => T[]\r\n /** O mesmo, com a ordenação e os filtros de `state` em vez dos do cabeçalho. */\r\n applyWith: (rows: T[], state: TableState) => T[]\r\n /** Linhas à vista, já ordenadas e filtradas (todas as páginas em modo cliente). */\r\n rows: T[]\r\n hasFilters: boolean\r\n /**\r\n * Há filtros, ordenação ou agrupamento ativos no cabeçalho, todos do lado do\r\n * cliente. Quem alimenta a tabela usa isto para não largar o conjunto\r\n * completo: sem ele, filtrar só olha para a página.\r\n */\r\n needsAllData: boolean\r\n /** Estado guardável da vista: filtros, ordenação e agrupamento. */\r\n getState: () => TableState\r\n /** Repõe um estado guardado (ex: ao aplicar uma vista que a pessoa guardou). */\r\n restore: (state: TableState | undefined) => void\r\n}\r\n\r\n/**\r\n * O que uma vista guardada leva da tabela. Conjuntos viram arrays para se\r\n * poder guardar em JSON.\r\n */\r\nexport interface TableState {\r\n columnFilters?: Record<string, string[]>\r\n dateFilters?: Record<string, { from?: string; to?: string }>\r\n /** Intervalos Mín/Máx. */\r\n numFilters?: Record<string, { min?: string; max?: string }>\r\n sortCol?: string | null\r\n sortDir?: 'asc' | 'desc'\r\n /** Colunas por que se agrupa, pela ordem dos níveis. */\r\n groupBy?: string[]\r\n}\r\n\r\nexport interface TableProps<T> {\r\n columns: TableColumn<T>[]\r\n /** As linhas a mostrar (a página atual, quando quem alimenta a tabela pagina). */\r\n data: T[]\r\n /**\r\n * O conjunto completo, para ordenar, filtrar e agrupar do lado do cliente.\r\n * Pode chegar mais tarde: a tabela pede-o com `onAllDataNeeded`.\r\n */\r\n allData?: T[]\r\n /** Linhas por página quando a tabela se pagina a si mesma (modo cliente). */\r\n pageSize?: number\r\n rowKey: (row: T) => string\r\n onRowClick?: (row: T) => void\r\n /** Duplo clique na linha: atalho para o detalhe, sem roubar o clique simples (seleção, edição). */\r\n onRowDoubleClick?: (row: T) => void\r\n loading?: boolean\r\n /** O conjunto completo (`allData`) está a carregar: ordenar, filtrar e agrupar esperam por ele. */\r\n allDataLoading?: boolean\r\n loadingLabel?: string\r\n /** Sem linhas. Por omissão `labels.empty`. */\r\n emptyLabel?: string\r\n emptySubLabel?: string\r\n /** Guarda os filtros na sessão do browser (`sessionStorage`) com esta chave, e repõe-nos ao voltar. */\r\n storageKey?: string\r\n /** Caixa de seleção em cada linha. */\r\n selectable?: boolean\r\n onSelectionChange?: (selectedKeys: Set<string>) => void\r\n /** Mudar este número limpa a seleção. */\r\n clearSelectionTrigger?: number\r\n /** Chamado quando a tabela precisa do conjunto completo (ordenar, filtrar ou agrupar sem `allData`). */\r\n onAllDataNeeded?: () => void\r\n /** Modo cliente sempre (paginação, ordenação e filtros sobre `allData`), mesmo sem interação. */\r\n alwaysClient?: boolean\r\n /** Ordenação inicial: a coluna. */\r\n defaultSortColumn?: string\r\n defaultSortDirection?: 'asc' | 'desc'\r\n /** Recebe o estado da vista (ordenação e filtros) para uso por fora. Ver `TableView`. */\r\n viewRef?: React.MutableRefObject<TableView<T> | null>\r\n /**\r\n * A tabela ocupa a ALTURA TODA que o pai lhe der, em vez de encolher com o\r\n * número de linhas. O cabeçalho fica fixo e só as linhas rolam.\r\n *\r\n * Sem isto, filtrar até sobrar uma linha encolhia a tabela, com meio ecrã em\r\n * branco por baixo e o rodapé a meio da página.\r\n *\r\n * Precisa de um pai com altura DEFINIDA (ex: `flex-1 min-h-0` dentro de uma\r\n * coluna de altura fixa). Para uma tabela pequena dentro de uma caixa, que\r\n * deve encolher com o conteúdo, deixar desligado.\r\n */\r\n fillHeight?: boolean\r\n /** Sem `fillHeight`: altura máxima da caixa (ex: `400` ou `'60vh'`), a partir da qual as linhas rolam. */\r\n maxHeight?: number | string\r\n /**\r\n * Quantas linhas a tabela está MESMO a mostrar, e se os filtros do cabeçalho\r\n * contam para isso.\r\n *\r\n * Uma contagem por fora (ex: o total que o servidor devolveu) não sabe dos\r\n * filtros de coluna, que são cá de dentro: filtrar até sobrar uma linha\r\n * deixava \"14 223 resultados\" por cima de uma lista de uma.\r\n *\r\n * `filtered: false` quer dizer \"não contes comigo\": não há filtros de coluna,\r\n * ou o conjunto completo ainda não chegou.\r\n *\r\n * `selfPaginated`: com o conjunto completo, a tabela ignora a página que lhe\r\n * dão e pagina-se a si mesma. Quem a alimenta deve então esconder a SUA\r\n * paginação, que deixa de ter efeito.\r\n */\r\n onVisibleChange?: (v: { visible: number; filtered: boolean; selfPaginated: boolean }) => void\r\n /**\r\n * Quantas colunas do início ficam congeladas no scroll horizontal. A caixa de\r\n * seleção, quando existe, vai junto.\r\n */\r\n frozenColumns?: number\r\n /**\r\n * Arrastar os cabeçalhos para mudar a ordem das colunas. Opt-in: a tabela só\r\n * avisa que coluna foi largada antes de qual. A ordem é de quem a alimenta,\r\n * que a guarda e muda `columns`.\r\n *\r\n * `beforeKey: null` = largada depois da última. Esc durante o arrasto desfaz.\r\n */\r\n onMoveColumn?: (key: string, beforeKey: string | null) => void\r\n /**\r\n * Com `fillHeight`: cada coluna fica com a largura do valor MAIS LARGO de\r\n * todo o `allData` (ou do título, se for maior), e não com a da página à\r\n * vista. Mudar de página ou filtrar não mexe nas larguras.\r\n *\r\n * Para conjuntos que já vêm inteiros: mede um exemplar de cada valor\r\n * distinto de cada coluna.\r\n */\r\n measureAllData?: boolean\r\n /**\r\n * Com `fillHeight`: barras de scroll desenhadas por cima das linhas, em vez\r\n * das do browser. A vertical do browser obrigava o cabeçalho a reservar-lhe\r\n * espaço; a horizontal punha uma faixa grossa por baixo das linhas.\r\n */\r\n overlayScrollbars?: boolean\r\n /** Classes da faixa dos títulos (com `onMoveColumn`). Por omissão `bg-slate-50`. */\r\n headerRowClassName?: string\r\n /**\r\n * Com `overlayScrollbars`: a barra horizontal centrada na aresta de baixo\r\n * (meio por cima do que vem a seguir). Desligar quando a tabela vive numa\r\n * caixa com `overflow-hidden`, senão a barra aparece cortada ao meio.\r\n */\r\n scrollbarOnEdge?: boolean\r\n /**\r\n * Com `overlayScrollbars`: a barra horizontal numa faixa própria POR BAIXO\r\n * das linhas (12px), em vez de por cima da última linha à vista.\r\n */\r\n horizontalScrollbarBelow?: boolean\r\n /**\r\n * A carregar: linhas-esqueleto nas colunas verdadeiras em vez do spinner ao\r\n * centro. O `loadingLabel` fica só para leitores de ecrã.\r\n */\r\n skeleton?: boolean\r\n /**\r\n * Com mais colunas à direita do que cabem, a aresta direita esbate-se em vez\r\n * de cortar as colunas a seco. Some ao chegar à última coluna.\r\n */\r\n fadeRight?: boolean\r\n /** Classes extra por linha (ex: uma cor por grupo de linhas). */\r\n rowClassName?: (row: T) => string | undefined\r\n /** Textos da tabela e dos filtros. Por omissão em português. */\r\n labels?: Partial<TableLabels>\r\n}\r\n\r\n/*\r\n Um só comparador de texto para todas as ordenações. `localeCompare` sem\r\n argumentos monta um por cada comparação — numa lista de milhares de linhas são\r\n dezenas de milhares de montagens por ordenação, e era isso que a fazia pesar.\r\n Mesmo resultado: é o comparador da língua por omissão, como o `localeCompare`.\r\n*/\r\nconst comparador = new Intl.Collator()\r\n\r\n/*\r\n A mola das trocas ao arrastar colunas (massa 1). Amortecimento = 2·√rigidez:\r\n criticamente amortecida, chega ao sítio sem ressaltar: 90% do caminho em\r\n ~120ms, assente em ~300ms (medido a 60 fps).\r\n*/\r\nconst MOLA_RIGIDEZ = 1200\r\nconst MOLA_AMORTECIMENTO = 2 * Math.sqrt(MOLA_RIGIDEZ)\r\n/** A esta distância do destino (px) a coluna já parece assente — ver `aoAssentar`. */\r\nconst PERTO_DE_ASSENTAR = 6\r\n\r\n/*\r\n A arrastar uma coluna: a mão fechada em toda a página, por cima dos cursores\r\n dos botões e das ligações por onde o rato passe, e sem escolher texto pelo\r\n caminho. Uma folha de estilo posta e tirada aqui, para a tabela não depender\r\n do CSS da app.\r\n*/\r\nlet estiloArrasto: HTMLStyleElement | null = null\r\nfunction cursorDeArrasto(ligado: boolean) {\r\n if (ligado && !estiloArrasto) {\r\n estiloArrasto = document.createElement('style')\r\n estiloArrasto.textContent = '*{cursor:grabbing!important;user-select:none!important}'\r\n document.head.appendChild(estiloArrasto)\r\n } else if (!ligado && estiloArrasto) {\r\n estiloArrasto.remove()\r\n estiloArrasto = null\r\n }\r\n}\r\n\r\n/** Quantos px o rato tem de andar com o botão em baixo para premir um título passar a arrastá-lo. */\r\nconst LIMIAR_ARRASTO = 4\r\n\r\n/** A fracção da largura da vizinha que já conta como passá-la, para qualquer dos lados. */\r\nconst FOLGA_TROCA = 0.75\r\n\r\ninterface GroupNode<T> {\r\n val: string\r\n path: string\r\n items: T[]\r\n children: GroupNode<T>[]\r\n}\r\n\r\n/**\r\n * A barra de paginação em cima da tabela (a do `PaginatedTable`), em vez da\r\n * troca de páginas no fundo. Interna: a app escolhe o `PaginatedTable`, não\r\n * liga isto na `Table`.\r\n */\r\nexport interface PaginacaoNoTopo {\r\n /** Total de linhas no servidor, quando é ele que pagina. */\r\n total?: number\r\n /** Página atual do servidor (a contar de 1). Com `onPageChange`, é o servidor que pagina. */\r\n page?: number\r\n onPageChange?: (page: number) => void\r\n /** Tamanhos de página à escolha. Sem isto não há escolha. */\r\n pageSizeOptions?: number[]\r\n onPageSizeChange?: (pageSize: number) => void\r\n}\r\n\r\n/** A tabela, com tudo. A `Table` e o `PaginatedTable` são predefinições dela. */\r\nexport function TableBase<T>({\r\n paginacaoNoTopo,\r\n columns: colunasBase, data, allData, pageSize, rowKey, onRowClick, onRowDoubleClick,\r\n loading: isLoading, allDataLoading: isAllDataLoading, loadingLabel, emptyLabel, emptySubLabel,\r\n storageKey, selectable, onSelectionChange, clearSelectionTrigger, onAllDataNeeded: onDataNeeded, alwaysClient,\r\n defaultSortColumn: defaultSortCol, defaultSortDirection: defaultSortDir, viewRef, fillHeight: preencheAltura = false,\r\n onVisibleChange: onVista, frozenColumns: colunasFixas = 0, onMoveColumn: onMoverColuna, measureAllData: larguraPeloConjunto = false,\r\n overlayScrollbars: barraSobreposta = false, headerRowClassName: classeCabecalho = 'bg-slate-50', scrollbarOnEdge: barraNaBorda = true,\r\n horizontalScrollbarBelow: barraHorizontalFora = false, skeleton: esqueletoAoCarregar = false, fadeRight: esbaterDireita = false,\r\n rowClassName, maxHeight, labels,\r\n}: TableProps<T> & { paginacaoNoTopo?: PaginacaoNoTopo }) {\r\n const L = { ...DEFAULT_TABLE_LABELS, ...labels }\r\n const vazio = emptyLabel ?? L.empty\r\n /*\r\n Com a barra sobreposta, a última coluna leva mais folga à direita: a barra\r\n passa por cima da ponta das linhas e, com os 12px de sempre, os valores\r\n encostados à direita (ex: números) ficavam colados a ela. É folga DENTRO da\r\n célula — a tabela não ganha goteira nenhuma — e a célula de medida leva-a\r\n também, senão a coluna ficava medida sem ela.\r\n */\r\n /*\r\n Arrastar colunas: a pré-visualização é SÓ visual.\r\n\r\n O arrasto é feito aqui, com eventos de ponteiro — não é o arrastar nativo\r\n do browser. Esse impunha os cursores dele (a seta com a caixa e o\r\n \"proibido\", a piscar entre si) e uma imagem-fantasma da coluna; assim o\r\n cursor é só a mão, e largar é sempre um `pointerup`, esteja o rato onde\r\n estiver.\r\n\r\n Durante o arrasto o DOM não muda de ordem — cada coluna é desenhada no sítio\r\n onde ficaria com um translateX (ver as molas, mais abaixo), e a ordem nova\r\n só chega à tabela ao largar. Reordenar o DOM a cada passo (a primeira\r\n versão) era um render da tabela inteira por passo.\r\n\r\n Em estado só a coluna arrastada (para o realce); onde cairia vive num ref,\r\n que muda a cada passo sem render nenhum.\r\n */\r\n const columns = colunasBase\r\n const [arrastada, setArrastada] = useState<string | null>(null)\r\n /*\r\n A coluna realçada. Nasce com o arrasto mas não acaba com ele: fica acesa\r\n até as colunas acabarem de deslizar — largar antes de a animação acabar\r\n apagava o realce a meio do caminho e perdia-se a coluna de vista — e depois\r\n esbate-se (ver `transicaoRealce`) em vez de desaparecer de repente.\r\n */\r\n const [realcada, setRealcada] = useState<string | null>(null)\r\n /** Onde cairia a arrastada: antes de `chave`, no fim (`null`), ou ainda em lado nenhum (`undefined`). */\r\n const alvoArrasto = useRef<string | null | undefined>(undefined)\r\n const recuoFim = (i: number) => (barraSobreposta && i === columns.length - 1 ? 'pr-6!' : '')\r\n /*\r\n Realça a coluna arrastada, do cabeçalho à última linha: fundo azul claro e\r\n um filete de cada lado. Esbatê-la (a primeira versão) punha em segundo plano\r\n precisamente a coluna que se está a seguir com os olhos.\r\n */\r\n const realce = (chave: string, cabecalho = false) => (realcada === chave\r\n // As fixas pintam o realce elas próprias (ver `fixa`): opacas, tapavam este.\r\n ? fixaMedida(chave) ? '' : `${cabecalho ? 'bg-proef-blue/15' : 'bg-proef-blue/5'} shadow-[inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)]`\r\n : cabecalho && fundoNosTitulos ? 'bg-slate-50' : '')\r\n /*\r\n Bordas SEPARADAS nas tabelas com colunas arrastáveis. Com as bordas\r\n colapsadas (o defeito do Tailwind), o Chrome pinta o fundo das células do\r\n cabeçalho à parte da própria célula, sem o translate: a arrastada deixava o\r\n realce pintado no sítio de onde saiu. Separadas, cada célula pinta o seu\r\n fundo e ele vai com ela.\r\n\r\n Separadas, as bordas de <tr> não se desenham. A linha debaixo do cabeçalho\r\n e os divisores entre linhas passam a ser uma sombra (um filete) da <tr>, e\r\n não bordas das células: são a estrutura da tabela, não da coluna — nas\r\n células iam com a arrastada, e onde ela saía ficava um buraco na linha.\r\n Só no cabeçalho `sticky` (sem caixa à parte) o filete fica nas células: lá\r\n os <th> são opacos e tapavam o da <tr>.\r\n\r\n O cinzento do cabeçalho também sai da <tr>: pintado nela, o Chrome passava\r\n a pintar o fundo das células junto com o dela — outra vez sem o translate,\r\n e o realce ficava no sítio de onde a coluna saiu enquanto durasse o\r\n esbater. Com o cabeçalho numa caixa à parte (`preencheAltura`), o cinzento\r\n vai para essa caixa e os títulos ficam transparentes: a coluna arrastada\r\n passa por cima das outras sem as tapar nem ser tapada. Sem caixa à parte\r\n (cabeçalho `sticky`), vai para cada <th>, que tem de ser opaco para as\r\n linhas não se verem a passar por baixo.\r\n */\r\n const bordasSeparadas = !!onMoverColuna\r\n const fundoNosTitulos = bordasSeparadas && !preencheAltura\r\n const classeTabela = bordasSeparadas ? 'text-left border-separate border-spacing-0' : 'text-left'\r\n /** O esbater do realce ao apagar-se — só o fundo e o filete; o translate não leva transição. */\r\n const transicaoRealce = onMoverColuna ? 'transition-[background-color,box-shadow] duration-300' : ''\r\n const [sortCol, setSortCol] = useState<string | null>(defaultSortCol ?? null)\r\n const [sortDir, setSortDir] = useState<'asc' | 'desc'>(defaultSortDir ?? 'asc')\r\n const [columnFilters, setColumnFilters] = useState<Record<string, Set<string>>>(() => {\r\n if (!storageKey) return {}\r\n try {\r\n const raw = sessionStorage.getItem(`dt_filters_${storageKey}`)\r\n if (!raw) return {}\r\n const parsed = JSON.parse(raw) as Record<string, string[]>\r\n return Object.fromEntries(Object.entries(parsed).map(([k, v]) => [k, new Set(v)]))\r\n } catch { return {} }\r\n })\r\n const [dateFilters, setDateFilters] = useState<Record<string, { from?: string; to?: string }>>(() => {\r\n if (!storageKey) return {}\r\n try {\r\n const raw = sessionStorage.getItem(`dt_datefilters_${storageKey}`)\r\n return raw ? (JSON.parse(raw) as Record<string, { from?: string; to?: string }>) : {}\r\n } catch { return {} }\r\n })\r\n /** Intervalos numéricos por coluna — o gémeo do `dateFilters` para números. */\r\n const [numFilters, setNumFilters] = useState<Record<string, { min?: string; max?: string }>>(() => {\r\n if (!storageKey) return {}\r\n try {\r\n const raw = sessionStorage.getItem(`dt_numfilters_${storageKey}`)\r\n return raw ? (JSON.parse(raw) as Record<string, { min?: string; max?: string }>) : {}\r\n } catch { return {} }\r\n })\r\n const [groupByKeys, setGroupByKeys] = useState<string[]>([])\r\n const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(new Set())\r\n const [internalPage, setInternalPage] = useState(1)\r\n const [openFilterCol, setOpenFilterCol] = useState<string | null>(null)\r\n /* Onde desenhar o popup: o rect do botão que o abriu. É `fixed` e vive no\r\n `<body>`, para o `overflow` da tabela não o cortar — era por ser filho da\r\n célula que a caixa da tabela tinha de perder o tecto de altura enquanto um\r\n filtro estivesse aberto, e a página saltava. */\r\n const [ancoraFiltro, setAncoraFiltro] = useState<DOMRect | null>(null)\r\n const [selectedKeys, setSelectedKeys] = useState<Set<string>>(new Set())\r\n\r\n const isGrouped = groupByKeys.length > 0\r\n\r\n useEffect(() => {\r\n if (!storageKey) return\r\n const serializable = Object.fromEntries(Object.entries(columnFilters).map(([k, v]) => [k, Array.from(v)]))\r\n sessionStorage.setItem(`dt_filters_${storageKey}`, JSON.stringify(serializable))\r\n sessionStorage.setItem(`dt_datefilters_${storageKey}`, JSON.stringify(dateFilters))\r\n sessionStorage.setItem(`dt_numfilters_${storageKey}`, JSON.stringify(numFilters))\r\n }, [columnFilters, dateFilters, numFilters, storageKey])\r\n\r\n /*\r\n O fechar-ao-clicar-fora e do `ColumnFilter`, nao daqui.\r\n\r\n Havia aqui um handler que media o clique contra a CELULA do cabecalho. Desde\r\n que o popup passou a viver no `<body>` (para o overflow da tabela nao o\r\n cortar), todo o clique dentro dele cai fora da celula -- e fechava a caixa\r\n ao primeiro visto. Quem sabe onde o popup esta e ele proprio.\r\n */\r\n\r\n const resolveValueFn = (colKey: string) => {\r\n const col = columns.find(c => c.key === colKey)\r\n if (col?.value) return col.value\r\n for (const c of columns) {\r\n const ef = c.extraFilters?.find(f => f.key === colKey)\r\n if (ef) return ef.value\r\n }\r\n return undefined\r\n }\r\n\r\n const getUniqueValues = (colKey: string): string[] => {\r\n const valueFn = resolveValueFn(colKey)\r\n if (!valueFn) return []\r\n let source = allData ?? data\r\n for (const [otherKey, selectedVals] of Object.entries(columnFilters)) {\r\n if (otherKey === colKey || !selectedVals || selectedVals.size === 0) continue\r\n const otherFn = resolveValueFn(otherKey)\r\n if (!otherFn) continue\r\n source = source.filter(row => { const v = otherFn(row); return selectedVals.has(v == null || v === '' ? '—' : String(v)) })\r\n }\r\n for (const [otherKey, range] of Object.entries(dateFilters)) {\r\n if (otherKey === colKey || !dateFilterActive(range)) continue\r\n const otherFn = resolveValueFn(otherKey)\r\n if (!otherFn) continue\r\n source = source.filter(row => { const d = asDay(otherFn(row)); if (!d) return false; if (range.from && d < range.from) return false; if (range.to && d > range.to) return false; return true })\r\n }\r\n const vals = new Set<string>()\r\n source.forEach(row => { const v = valueFn(row); vals.add(v == null || v === '' ? '—' : String(v)) })\r\n return Array.from(vals).sort((a, b) => a === '—' ? 1 : b === '—' ? -1 : a.localeCompare(b))\r\n }\r\n\r\n // Normaliza qualquer valor de data (ISO com/sem hora) para 'AAAA-MM-DD'\r\n const asDay = (v: unknown) => (v == null ? '' : String(v).substring(0, 10))\r\n const dateFilterActive = (r?: { from?: string; to?: string }) => !!(r && (r.from || r.to))\r\n const numFilterActive = (r?: { min?: string; max?: string }) => !!(r && (r.min !== undefined && r.min !== '' || r.max !== undefined && r.max !== ''))\r\n /** O número por trás do valor da célula. Vazio/nulo não é zero — é \"não sei\". */\r\n const asNum = (v: unknown) => {\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 const hasActiveFilters = useMemo(\r\n () => Object.values(columnFilters).some(s => s?.size > 0)\r\n || Object.values(dateFilters).some(dateFilterActive)\r\n || Object.values(numFilters).some(numFilterActive),\r\n [columnFilters, dateFilters, numFilters],\r\n )\r\n const isClientMode = !!allData && (alwaysClient || hasActiveFilters || !!sortCol || isGrouped)\r\n const effectiveData = isClientMode ? allData! : data\r\n\r\n // Outro tamanho de página também volta à primeira: ficar na 7.ª com 500 por página caía fora da lista.\r\n useEffect(() => { setInternalPage(1) }, [sortCol, sortDir, columnFilters, dateFilters, numFilters, groupByKeys, pageSize])\r\n useEffect(() => { if (clearSelectionTrigger === undefined) return; setSelectedKeys(new Set()) }, [clearSelectionTrigger])\r\n\r\n /**\r\n * Filtrar pelo cabeçalho também limpa a selecção.\r\n *\r\n * O que estava marcado era-o daquela lista: filtrar para outra e manter as\r\n * marcas deixava escolhidas linhas que já não se veem — e quem age sobre a\r\n * selecção (uma ação em massa, por exemplo) agia sobre elas na mesma.\r\n *\r\n * Ordenar não conta: são as mesmas linhas por outra ordem.\r\n */\r\n const chaveFiltrosCol = JSON.stringify(\r\n Object.entries(columnFilters).map(([k, v]) => [k, [...v].sort()]).sort(),\r\n )\r\n useEffect(() => {\r\n // AVISAR quem usa a tabela, e não só limpar por dentro: as caixas ficavam\r\n // vazias e um botão \"Aplicar a 250\" por cima continuava a contar com elas.\r\n // Quem manda na acção é o ecrã, logo tem de saber que a selecção caiu.\r\n setSelectedKeys(new Set())\r\n onSelectionChange?.(new Set())\r\n // `onSelectionChange` fora das dependências de propósito: é uma função do\r\n // ecrã, recriada a cada render, e segui-la limpava a selecção sozinha.\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [chaveFiltrosCol])\r\n\r\n /**\r\n * Filtros, ordenação e agrupamento são do lado do cliente: sem o dataset\r\n * completo filtram só a página e a tabela aparece vazia com o total a dizer\r\n * milhares. Pede-se sempre que faltar — não só no arranque: os filtros vêm do\r\n * sessionStorage, e quem alimenta a tabela pode largar o dataset a meio (ex:\r\n * ao mudar um filtro de servidor).\r\n */\r\n useEffect(() => {\r\n if (!allData && (hasActiveFilters || sortCol || isGrouped)) onDataNeeded?.()\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [allData, hasActiveFilters, sortCol, isGrouped])\r\n\r\n // Aliases para os valores por omissão de sortRows/filterRows (os parâmetros\r\n // têm os mesmos nomes que o estado e taparam-no).\r\n const sortColAtual = sortCol, sortDirAtual = sortDir\r\n const filtrosDeColuna = columnFilters, filtrosDeData = dateFilters, filtrosNumericos = numFilters\r\n // Ordenar e filtrar são funções sobre uma lista qualquer (não só sobre a\r\n // vista actual): é o que permite reaplicar a mesma vista ao dataset completo\r\n // — ver `viewRef`/`DataTableView`.\r\n const sortRows = (rows: T[], sortCol = sortColAtual, sortDir = sortDirAtual) => {\r\n if (!sortCol) return rows\r\n const col = columns.find(c => c.key === sortCol)\r\n if (!col?.value) return rows\r\n return [...rows].sort((a, b) => {\r\n const av = col.value!(a); const bv = col.value!(b)\r\n if (av == null && bv == null) return 0\r\n if (av == null) return 1; if (bv == null) return -1\r\n if (typeof av === 'number' && typeof bv === 'number') return sortDir === 'asc' ? av - bv : bv - av\r\n const cmp = comparador.compare(String(av), String(bv)); return sortDir === 'asc' ? cmp : -cmp\r\n })\r\n }\r\n\r\n const filterRows = (\r\n rows: T[],\r\n columnFilters: Record<string, ReadonlySet<string>> = filtrosDeColuna,\r\n dateFilters: Record<string, { from?: string; to?: string }> = filtrosDeData,\r\n numFilters: Record<string, { min?: string; max?: string }> = filtrosNumericos,\r\n ) => {\r\n let result = rows\r\n for (const [colKey, selectedVals] of Object.entries(columnFilters)) {\r\n if (!selectedVals || selectedVals.size === 0) continue\r\n const valueFn = resolveValueFn(colKey)\r\n if (!valueFn) continue\r\n result = result.filter(row => { const v = valueFn(row); return selectedVals.has(v == null || v === '' ? '—' : String(v)) })\r\n }\r\n for (const [colKey, range] of Object.entries(dateFilters)) {\r\n if (!dateFilterActive(range)) continue\r\n const valueFn = resolveValueFn(colKey)\r\n if (!valueFn) continue\r\n result = result.filter(row => { const d = asDay(valueFn(row)); if (!d) return false; if (range.from && d < range.from) return false; if (range.to && d > range.to) return false; return true })\r\n }\r\n for (const [colKey, range] of Object.entries(numFilters)) {\r\n if (!numFilterActive(range)) continue\r\n const valueFn = resolveValueFn(colKey)\r\n if (!valueFn) continue\r\n // Sem valor fica de FORA, como nas datas: \"entre 0 e 100\" não é uma\r\n // pergunta que uma linha sem valor nenhum responda.\r\n result = result.filter(row => {\r\n const n = asNum(valueFn(row))\r\n if (n == null) return false\r\n if (range.min !== undefined && range.min !== '' && n < Number(range.min)) return false\r\n if (range.max !== undefined && range.max !== '' && n > Number(range.max)) return false\r\n return true\r\n })\r\n }\r\n return result\r\n }\r\n\r\n // `colunasBase` e não `columns`: a ordem das colunas (e a pré-visualização de\r\n // um arrasto) não muda a ordenação, e com ela aqui cada troca reordenava tudo.\r\n const sortedData = useMemo(() => sortRows(effectiveData), [effectiveData, sortCol, sortDir, colunasBase])\r\n\r\n const filteredData = useMemo(() => filterRows(sortedData), [sortedData, columnFilters, dateFilters, numFilters])\r\n\r\n // Sem deps: o handle é lido de fora a pedido (ex: ao exportar), tem de estar\r\n // sempre coerente com o último render.\r\n useEffect(() => {\r\n if (!viewRef) return\r\n viewRef.current = {\r\n apply: rows => filterRows(sortRows(rows)),\r\n applyWith: (rows, e) => filterRows(\r\n sortRows(rows, e.sortCol ?? null, e.sortDir ?? 'asc'),\r\n Object.fromEntries(Object.entries(e.columnFilters ?? {}).map(([k, v]) => [k, new Set(v)])),\r\n e.dateFilters ?? {},\r\n e.numFilters ?? {},\r\n ),\r\n rows: filteredData,\r\n hasFilters: hasActiveFilters,\r\n needsAllData: hasActiveFilters || !!sortCol || isGrouped,\r\n getState: () => ({\r\n columnFilters: Object.fromEntries(\r\n Object.entries(columnFilters).filter(([, v]) => v?.size).map(([k, v]) => [k, [...v]]),\r\n ),\r\n dateFilters: Object.fromEntries(Object.entries(dateFilters).filter(([, r]) => dateFilterActive(r))),\r\n numFilters: Object.fromEntries(Object.entries(numFilters).filter(([, r]) => numFilterActive(r))),\r\n sortCol,\r\n sortDir,\r\n groupBy: groupByKeys,\r\n }),\r\n restore: e => {\r\n setColumnFilters(Object.fromEntries(Object.entries(e?.columnFilters ?? {}).map(([k, v]) => [k, new Set(v)])))\r\n setDateFilters(e?.dateFilters ?? {})\r\n setNumFilters(e?.numFilters ?? {})\r\n setSortCol(e?.sortCol ?? null)\r\n setSortDir(e?.sortDir ?? 'asc')\r\n setGroupByKeys(e?.groupBy ?? [])\r\n // Grupos recolhidos não se guardam: a vista diz por que se agrupa, não\r\n // o que estava aberto no momento em que foi gravada.\r\n setCollapsedGroups(new Set())\r\n // Filtrar, ordenar e agrupar são do lado do cliente: sem o dataset\r\n // completo a vista reposta só olharia para a página actual.\r\n const precisaTudo = !!e?.sortCol\r\n || !!e?.groupBy?.length\r\n || Object.keys(e?.columnFilters ?? {}).length > 0\r\n || Object.keys(e?.dateFilters ?? {}).length > 0\r\n if (precisaTudo && !allData) onDataNeeded?.()\r\n },\r\n }\r\n })\r\n\r\n // --- GroupBy logic ---\r\n const toggleGroup = (colKey: string) => {\r\n if (!allData) onDataNeeded?.()\r\n setGroupByKeys(prev =>\r\n prev.includes(colKey) ? prev.filter(k => k !== colKey) : [...prev, colKey]\r\n )\r\n setCollapsedGroups(new Set())\r\n }\r\n const removeGroup = (colKey: string) => { setGroupByKeys(prev => prev.filter(k => k !== colKey)); setCollapsedGroups(new Set()) }\r\n const clearAllGroups = () => { setGroupByKeys([]); setCollapsedGroups(new Set()) }\r\n const toggleCollapse = (path: string) => setCollapsedGroups(prev => { const n = new Set(prev); if (n.has(path)) n.delete(path); else n.add(path); return n })\r\n\r\n const buildGroups = (items: T[], keys: string[], depth: number, parentPath: string): GroupNode<T>[] => {\r\n if (depth >= keys.length) return []\r\n const valueFn = resolveValueFn(keys[depth])\r\n if (!valueFn) return []\r\n const map = new Map<string, T[]>()\r\n items.forEach(item => {\r\n const v = valueFn(item)\r\n const label = v == null || v === '' ? '—' : String(v)\r\n if (!map.has(label)) map.set(label, [])\r\n map.get(label)!.push(item)\r\n })\r\n return Array.from(map.entries())\r\n .sort(([a], [b]) => a === '—' ? 1 : b === '—' ? -1 : a.localeCompare(b))\r\n .map(([val, groupItems]) => {\r\n const path = parentPath ? `${parentPath}\\x00${val}` : val\r\n return { val, path, items: groupItems, children: buildGroups(groupItems, keys, depth + 1, path) }\r\n })\r\n }\r\n\r\n const groups = useMemo(() =>\r\n isGrouped ? buildGroups(filteredData, groupByKeys, 0, '') : [],\r\n [filteredData, groupByKeys, isGrouped]\r\n )\r\n\r\n const colCount = columns.length + (selectable ? 1 : 0)\r\n\r\n /*\r\n Congelar colunas precisa do `left` de cada uma em pixels, e as larguras\r\n aqui são automáticas (o conteúdo é que manda). Medem-se no cabeçalho, que\r\n tem exactamente as mesmas colunas, e recalcula-se quando ele muda de\r\n tamanho — mostrar/esconder uma coluna, mudar a janela, ou o conteúdo crescer\r\n ao chegar a página seguinte.\r\n */\r\n const nFixas = colunasFixas ? Math.min(colunasFixas + (selectable ? 1 : 0), colCount) : 0\r\n const cabecalhoRef = useRef<HTMLTableRowElement>(null)\r\n /** A raiz da tabela — onde se procuram as células de cada coluna para as animar. */\r\n const raizRef = useRef<HTMLDivElement>(null)\r\n /** Onde estava cada coluna (esquerda do cabeçalho, em px) no último desenho. */\r\n const posColunas = useRef<Map<string, number>>(new Map())\r\n /*\r\n Trocas animadas durante um arrasto, com uma MOLA por coluna.\r\n\r\n Cada coluna guarda onde está desenhada em relação ao sítio dela no DOM (`x`,\r\n em px), a que velocidade se mexe (`v`) e para onde vai (`destino`). Durante\r\n o arrasto o destino é o sítio que teria na ordem pré-visualizada; ao largar,\r\n o DOM passa a essa ordem, o `x` ganha a diferença (continua desenhada onde\r\n estava) e o destino volta a zero — sem salto nenhum.\r\n\r\n A velocidade NÃO se perde: arrastar de seguida por cinco colunas é um\r\n movimento só, que muda de destino a meio, em vez de cinco arranques e\r\n travagens. Mola criticamente amortecida (ver MOLA_RIGIDEZ). Só as células à\r\n vista (uma página), e o ciclo de frames pára quando todas assentam.\r\n */\r\n /** Chamado quando as molas todas assentam — ver `realcada`. */\r\n const aoAssentar = useRef<() => void>(() => {})\r\n /** Há uma coluna na mão (entre o `dragstart` e o fim do arrasto). */\r\n const emArrasto = useRef(false)\r\n aoAssentar.current = () => { if (!emArrasto.current) setRealcada(null) }\r\n const molas = useRef(new Map<string, { x: number; v: number; destino: number; parada: boolean; els: HTMLElement[] }>())\r\n /** As células de cada coluna, apanhadas ao começar o arrasto — o DOM não muda até largar. */\r\n const celulasArrasto = useRef(new Map<string, HTMLElement[]>())\r\n const frame = useRef<number | null>(null)\r\n const ultimoFrame = useRef(0)\r\n const animarMolas = useCallback((t: number) => {\r\n // Passo limitado: uma aba em segundo plano devolve saltos de segundos, e a\r\n // integração explodia.\r\n const dt = Math.min(0.032, (t - ultimoFrame.current) / 1000)\r\n ultimoFrame.current = t\r\n /* Em passos de no máximo 8 ms. Com o amortecimento desta mola, um passo\r\n acima de ~29 ms (2 / MOLA_AMORTECIMENTO) já diverge — e um frame lento\r\n chega lá: numa tabela com mais de mil linhas por medir, as\r\n colunas saíam disparadas para translateX(1e23px) e a tabela ficava em\r\n branco. */\r\n const passos = Math.max(1, Math.ceil(dt / 0.008))\r\n const h = dt / passos\r\n let aMexer = false\r\n let longe = false\r\n for (const [k, m] of molas.current) {\r\n if (m.parada) continue\r\n for (let i = 0; i < passos; i++) {\r\n m.v += (-MOLA_RIGIDEZ * (m.x - m.destino) - MOLA_AMORTECIMENTO * m.v) * h\r\n m.x += m.v * h\r\n }\r\n if (Math.abs(m.x - m.destino) < 0.3 && Math.abs(m.v) < 5) {\r\n m.x = m.destino\r\n m.v = 0\r\n m.parada = true\r\n if (!m.destino) {\r\n for (const el of m.els) el.style.transform = ''\r\n molas.current.delete(k)\r\n continue\r\n }\r\n } else {\r\n aMexer = true\r\n if (Math.abs(m.x - m.destino) > PERTO_DE_ASSENTAR) longe = true\r\n }\r\n const tr = `translateX(${m.x}px)`\r\n for (const el of m.els) el.style.transform = tr\r\n }\r\n frame.current = aMexer ? requestAnimationFrame(animarMolas) : null\r\n // O realce começa a esbater-se já perto do fim, não quando pára de todo:\r\n // a cauda da mola (décimos de píxel) arrastava-se e o esbater tardava.\r\n if (!longe) aoAssentar.current()\r\n }, [])\r\n useEffect(() => () => { if (frame.current !== null) cancelAnimationFrame(frame.current) }, [])\r\n const arrancarMolas = useCallback(() => {\r\n if (frame.current !== null) return\r\n ultimoFrame.current = performance.now()\r\n frame.current = requestAnimationFrame(animarMolas)\r\n }, [animarMolas])\r\n\r\n /** Aponta cada coluna para um destino (px a partir do sítio dela no DOM); zero por omissão. */\r\n const apontarMolas = (destinos: Map<string, number>) => {\r\n for (const [k, els] of celulasArrasto.current) {\r\n const destino = destinos.get(k) ?? 0\r\n const m = molas.current.get(k)\r\n if (!m && !destino) continue\r\n const mola = m ?? { x: 0, v: 0, destino: 0, parada: true, els }\r\n mola.destino = destino\r\n mola.parada = false\r\n mola.els = els\r\n molas.current.set(k, mola)\r\n }\r\n arrancarMolas()\r\n }\r\n\r\n /*\r\n A grelha pré-visualizada: a ordem do DOM com a arrastada tirada e posta\r\n antes de `alvo`, e a esquerda de cada coluna nessa ordem — das larguras de\r\n agora, sem contar com animação nenhuma.\r\n */\r\n const grelhaPrevista = (chave: string, alvo: string | null | undefined) => {\r\n const ths = (Array.from(cabecalhoRef.current?.children ?? []) as HTMLElement[]).filter(th => th.dataset.col)\r\n const ordem = ths.map(th => th.dataset.col!)\r\n if (alvo !== undefined) {\r\n const resto = ordem.filter(k => k !== chave)\r\n const onde = alvo === null ? resto.length : resto.indexOf(alvo)\r\n resto.splice(onde < 0 ? resto.length : onde, 0, chave)\r\n ordem.splice(0, ordem.length, ...resto)\r\n }\r\n const porChave = new Map(ths.map(th => [th.dataset.col!, th]))\r\n const esquerda = new Map<string, number>()\r\n let acc = ths[0]?.offsetLeft ?? 0\r\n for (const k of ordem) {\r\n esquerda.set(k, acc)\r\n acc += porChave.get(k)?.offsetWidth ?? 0\r\n }\r\n return { ordem, esquerda, porChave }\r\n }\r\n\r\n /*\r\n Onde cairia a arrastada, na grelha pré-visualizada (a que se está a ver).\r\n Com 1 2 3 e o 2 na mão, a troca dá-se a 75% da vizinha (ver FOLGA_TROCA),\r\n contados do lado de onde o rato vem: 2 1 3 quando o rato fica a 75% do\r\n INÍCIO do 1; 1 3 2 quando chega a 75% do FIM do 3. A folga nunca passa da\r\n largura da arrastada, para uma coluna estreita a passar por uma larga não\r\n ter de a atravessar quase toda.\r\n\r\n Não oscila: depois da troca, a vizinha passou para o outro lado da\r\n arrastada, e o ponto de troca dela está agora longe do rato — voltar pede\r\n recuar até ele.\r\n\r\n Vale em qualquer sítio da página: conta só a posição horizontal do rato,\r\n por isso subir ou descer para fora da tabela a arrastar não desfaz nada.\r\n */\r\n const arrastarPorCima = (clientX: number) => {\r\n if (!arrastada) return\r\n const tabela = cabecalhoRef.current?.closest('table')\r\n if (!tabela) return\r\n const fixas = new Set(columns.slice(0, colunasFixas).map(c => c.key))\r\n const arrastadaFixa = fixas.has(arrastada)\r\n /* As fixas não rolam: com a tabela rolada para o lado, estão onde sempre\r\n estiveram na caixa, e não onde a tabela (deslocada) diz. */\r\n const caixa = caixaCorpo ?? caixaSimples\r\n const x = clientX - tabela.getBoundingClientRect().left + (arrastadaFixa && caixa ? caixa.scrollLeft : 0)\r\n const { ordem, esquerda, porChave } = grelhaPrevista(arrastada, alvoArrasto.current)\r\n const larguraArrastada = porChave.get(arrastada)?.offsetWidth ?? 0\r\n let alvo: string | null = null\r\n let aEsquerda = true\r\n for (const k of ordem) {\r\n if (k === arrastada) { aEsquerda = false; continue }\r\n const largura = porChave.get(k)?.offsetWidth ?? 0\r\n const folga = Math.max(0, Math.min(largura * FOLGA_TROCA, larguraArrastada - 1))\r\n // À esquerda, a folga conta-se do início dela; à direita, do fim.\r\n const ponto = (esquerda.get(k) ?? 0) + (aEsquerda ? folga : largura - folga)\r\n if (ponto > x) { alvo = k; break }\r\n }\r\n /*\r\n Fixas e soltas não se misturam: uma fixa só troca com fixas, e uma solta\r\n com soltas. A parte fixa são as primeiras `frozenColumns` colunas, logo\r\n tirar uma de lá (ou meter outra) mudava QUAIS ficavam fixas.\r\n Fora do seu grupo, a arrastada fica na ponta dele mais perto do rato: a\r\n primeira das soltas é o fim das fixas e o início das soltas.\r\n */\r\n if (colunasFixas > 0) {\r\n const primeiraSolta = ordem.find(k => k !== arrastada && !fixas.has(k)) ?? null\r\n if (arrastadaFixa && (alvo === null || !fixas.has(alvo))) alvo = primeiraSolta\r\n else if (!arrastadaFixa && alvo !== null && fixas.has(alvo)) alvo = primeiraSolta\r\n }\r\n if (alvo === alvoArrasto.current) return\r\n alvoArrasto.current = alvo\r\n const prevista = grelhaPrevista(arrastada, alvo)\r\n apontarMolas(new Map([...prevista.porChave].map(([k, th]) => [k, (prevista.esquerda.get(k) ?? 0) - th.offsetLeft])))\r\n }\r\n\r\n /*\r\n Fim do arrasto. Largar em QUALQUER sítio da página grava a ordem que se\r\n está a ver. Só o Esc desfaz: as colunas deslizam de volta. Antes, largar\r\n fora da tabela também desfazia, e subir um pouco a mais ao arrastar perdia\r\n a troca.\r\n */\r\n const acabarArrasto = (gravar: boolean) => {\r\n const chave = arrastada\r\n const alvo = alvoArrasto.current\r\n emArrasto.current = false\r\n setArrastada(null)\r\n // Nada a deslizar (nem agora, nem depois de a ordem nova chegar ao DOM, no\r\n // frame a seguir): o realce apaga-se já. Havendo, é o fim das molas que o\r\n // apaga (`aoAssentar`).\r\n requestAnimationFrame(() => { if (frame.current === null) aoAssentar.current() })\r\n // Rede: se as molas não chegarem a assentar (frames parados com a aba\r\n // escondida, por exemplo), o realce apaga-se na mesma.\r\n setTimeout(() => aoAssentar.current(), 1000)\r\n alvoArrasto.current = undefined\r\n if (chave && gravar && alvo !== undefined && alvo !== chave) {\r\n // O DOM ainda está na ordem antiga: o efeito das posições converte o\r\n // translate de cada coluna para a ordem nova (ver mais abaixo).\r\n onMoverColuna?.(chave, alvo)\r\n } else {\r\n apontarMolas(new Map())\r\n }\r\n }\r\n /** Pega na coluna: realce, e as posições e células de partida. */\r\n const comecarArrasto = (chave: string) => {\r\n setArrastada(chave)\r\n setRealcada(chave)\r\n emArrasto.current = true\r\n alvoArrasto.current = undefined\r\n const ths = (Array.from(cabecalhoRef.current?.children ?? []) as HTMLElement[])\r\n .filter(th => th.dataset.col)\r\n // As posições de partida são as de AGORA: as larguras\r\n // podem ter mudado depois do último desenho.\r\n posColunas.current = new Map(ths.map(th => [th.dataset.col!, th.offsetLeft]))\r\n const raiz = raizRef.current\r\n celulasArrasto.current = new Map(ths.map(th => [th.dataset.col!,\r\n raiz ? Array.from(raiz.querySelectorAll<HTMLElement>(`[data-col=\"${CSS.escape(th.dataset.col!)}\"]`)) : []]))\r\n }\r\n\r\n /*\r\n Os ouvintes do arrasto são do documento — o rato pode sair da tabela — e\r\n leem as funções por ref: são postos uma vez por arrasto, e as funções mudam\r\n a cada render.\r\n */\r\n const aoComecar = useRef(comecarArrasto)\r\n aoComecar.current = comecarArrasto\r\n const aoPassar = useRef(arrastarPorCima)\r\n aoPassar.current = arrastarPorCima\r\n const aoAcabar = useRef(acabarArrasto)\r\n aoAcabar.current = acabarArrasto\r\n /** Tira os ouvintes de um arrasto a meio — para a tabela desaparecer a meio de um. */\r\n const largarOuvintes = useRef<() => void>(() => {})\r\n /*\r\n Acaba um arrasto que ficou a meio: largar o botão fora da janela não manda\r\n `pointerup`, e premir outro título só tirava os ouvintes — o arrasto nunca\r\n acabava e a coluna ficava realçada a azul para sempre.\r\n */\r\n const acabarPendente = useRef<() => void>(() => {})\r\n useEffect(() => () => {\r\n largarOuvintes.current()\r\n cursorDeArrasto(false)\r\n }, [])\r\n\r\n /*\r\n Premir um título. Só passa a arrasto depois de o rato andar LIMIAR_ARRASTO\r\n px com o botão em baixo: antes disso é um clique, e os botões do título\r\n (ordenar, filtrar, agrupar) têm de continuar a funcionar. Havendo arrasto,\r\n o clique que o browser manda ao soltar é engolido — senão soltar por cima\r\n do botão de ordenar ordenava.\r\n */\r\n const premirTitulo = (e: React.PointerEvent, chave: string) => {\r\n if (e.button !== 0 || !e.isPrimary) return\r\n if ((e.target as HTMLElement).closest('input, textarea, select')) return\r\n acabarPendente.current()\r\n largarOuvintes.current()\r\n const x0 = e.clientX\r\n const y0 = e.clientY\r\n let comecou = false\r\n const mover = (ev: PointerEvent) => {\r\n if (!comecou) {\r\n if (Math.hypot(ev.clientX - x0, ev.clientY - y0) < LIMIAR_ARRASTO) return\r\n comecou = true\r\n cursorDeArrasto(true)\r\n aoComecar.current(chave)\r\n }\r\n aoPassar.current(ev.clientX)\r\n }\r\n const acabar = (gravar: boolean) => {\r\n acabarPendente.current = () => {}\r\n largarOuvintes.current()\r\n if (!comecou) return\r\n cursorDeArrasto(false)\r\n aoAcabar.current(gravar)\r\n }\r\n const soltar = () => {\r\n if (comecou) {\r\n const engolir = (ev: MouseEvent) => { ev.stopPropagation(); ev.preventDefault() }\r\n document.addEventListener('click', engolir, { capture: true, once: true })\r\n setTimeout(() => document.removeEventListener('click', engolir, { capture: true }), 0)\r\n }\r\n acabar(true)\r\n }\r\n const cancelar = () => acabar(false)\r\n acabarPendente.current = () => acabar(true)\r\n const tecla = (ev: KeyboardEvent) => { if (ev.key === 'Escape') acabar(false) }\r\n document.addEventListener('pointermove', mover)\r\n document.addEventListener('pointerup', soltar)\r\n document.addEventListener('pointercancel', cancelar)\r\n document.addEventListener('keydown', tecla)\r\n largarOuvintes.current = () => {\r\n document.removeEventListener('pointermove', mover)\r\n document.removeEventListener('pointerup', soltar)\r\n document.removeEventListener('pointercancel', cancelar)\r\n document.removeEventListener('keydown', tecla)\r\n largarOuvintes.current = () => {}\r\n }\r\n }\r\n\r\n /*\r\n A ordem do DOM mudou (largou-se uma coluna, ou quem alimenta a tabela mudou a\r\n ordem): cada coluna continua desenhada onde estava — o `x` ganha a diferença\r\n entre a esquerda antiga e a nova — e a mola leva-a ao sítio (destino zero).\r\n Depois de um arrasto a diferença é praticamente o translate que a coluna já\r\n tinha, logo não se vê salto nenhum.\r\n */\r\n useLayoutEffect(() => {\r\n const ths = Array.from(cabecalhoRef.current?.children ?? []) as HTMLElement[]\r\n const agora = new Map<string, number>()\r\n for (const th of ths) {\r\n const k = th.dataset.col\r\n // `offsetLeft` e não o rect: relativo à tabela, rolar de lado não o mexe,\r\n // e o translate da animação também não.\r\n if (k) agora.set(k, th.offsetLeft)\r\n }\r\n const antes = posColunas.current\r\n posColunas.current = agora\r\n if (!onMoverColuna || !antes.size) return\r\n const raiz = raizRef.current\r\n if (!raiz) return\r\n let mexeu = false\r\n for (const [k, x] of agora) {\r\n const delta = (antes.get(k) ?? x) - x\r\n const m = molas.current.get(k)\r\n if (!delta && !m) continue\r\n const mola = m ?? { x: 0, v: 0, destino: 0, parada: false, els: [] }\r\n mola.x += delta\r\n mola.destino = 0\r\n mola.parada = false\r\n // As células de novo: mudar de página troca os elementos.\r\n mola.els = Array.from(raiz.querySelectorAll<HTMLElement>(`[data-col=\"${CSS.escape(k)}\"]`))\r\n // Já no sítio antigo ANTES de o browser desenhar — senão via-se um frame\r\n // com a coluna já no sítio novo.\r\n const tr = `translateX(${mola.x}px)`\r\n for (const el of mola.els) el.style.transform = tr\r\n molas.current.set(k, mola)\r\n mexeu = true\r\n }\r\n if (mexeu) arrancarMolas()\r\n }, [columns, onMoverColuna, arrancarMolas])\r\n const [esquerdas, setEsquerdas] = useState<number[]>([])\r\n useLayoutEffect(() => {\r\n if (!nFixas) { setEsquerdas(e => (e.length ? [] : e)); return }\r\n const medir = () => {\r\n const ths = Array.from(cabecalhoRef.current?.children ?? []) as HTMLElement[]\r\n let acc = 0\r\n const out: number[] = []\r\n for (let i = 0; i < nFixas; i++) { out.push(acc); acc += ths[i]?.offsetWidth ?? 0 }\r\n // Só grava se MUDOU: o ResizeObserver dispara com o que este efeito\r\n // escreve, e sem isto era um ciclo de render a alimentar-se a si próprio.\r\n setEsquerdas(prev => (prev.length === out.length && prev.every((v, i) => v === out[i]) ? prev : out))\r\n }\r\n medir()\r\n const ro = new ResizeObserver(medir)\r\n for (const th of Array.from(cabecalhoRef.current?.children ?? [])) ro.observe(th)\r\n return () => ro.disconnect()\r\n }, [nFixas, columns, data, esquerdas])\r\n\r\n /*\r\n A célula fixa é opaca, logo tem de repintar o que a linha pintava por baixo\r\n dela: o turquesa da linha escolhida, e o cinzento do hover (esse pelo\r\n `group-hover`, porque o `hover:` da linha não chega a uma célula que traz\r\n fundo próprio). O turquesa é o `bg-proef-turquoise/5` já resolvido sobre\r\n branco — a mesma cor, sem transparência.\r\n */\r\n const fundoLinha = (k: string) =>\r\n `${selectable && selectedKeys.has(k) ? 'bg-[#f2fdf9]' : 'bg-white'} group-hover/linha:bg-slate-50`\r\n\r\n /** No cabeçalho o z tem de bater as duas: a linha sticky do topo e as células\r\n * fixas do corpo, senão o canto passava por baixo de uma delas. */\r\n const cabecaFixa = (i: number) => {\r\n // Opaca, tapava o filete de baixo da <tr> do cabeçalho: leva o seu.\r\n const realcadaAqui = realcada !== null && realcada === chaveDoIndice(i)\r\n const linhaDeBaixo = bordasSeparadas && !fundoNosTitulos\r\n const f = fixa(\r\n i,\r\n realcadaAqui ? 'bg-[color-mix(in_srgb,var(--color-proef-blue)_15%,var(--color-slate-50))]' : 'bg-slate-50',\r\n realcadaAqui\r\n ? linhaDeBaixo\r\n ? 'shadow-[inset_0_-2px_0_0_var(--color-slate-200),inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)]'\r\n : 'shadow-[inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)]'\r\n : linhaDeBaixo ? 'shadow-[inset_0_-2px_0_0_var(--color-slate-200)]' : '',\r\n )\r\n return { className: f.className, style: f.style ? { ...f.style, zIndex: 30 } : undefined }\r\n }\r\n\r\n /** Estilo da célula i — só as fixas, e só depois de medidas. */\r\n /*\r\n `filete`: com bordas separadas, os divisores entre linhas são uma sombra da\r\n <tr>, e a célula fixa (opaca) tapava-os: sem ele, a coluna fixa ficava sem\r\n as linhas entre as filas e parecia de outra tabela.\r\n */\r\n const filetesFixos = bordasSeparadas ? '[tr+tr>&]:shadow-[inset_0_1px_0_0_var(--color-slate-100)]' : ''\r\n /* A coluna arrastada (realçada), numa célula fixa do corpo: o azul do realce\r\n já resolvido sobre branco (opaco, como a célula tem de ser), e os filetes\r\n dos lados juntos com o divisor da linha, que senão se tapavam um ao outro. */\r\n const fundoRealceFixa = 'bg-[color-mix(in_srgb,var(--color-proef-blue)_5%,white)]'\r\n const filetesRealceFixa = bordasSeparadas\r\n ? 'shadow-[inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)] [tr+tr>&]:shadow-[inset_0_1px_0_0_var(--color-slate-100),inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)]'\r\n : 'shadow-[inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)]'\r\n /** A chave da coluna na posição i (contando a caixa de seleção, quando existe). */\r\n const chaveDoIndice = (i: number) => columns[i - (selectable ? 1 : 0)]?.key\r\n /** A coluna está fixa e já medida (é então a `fixa` que lhe pinta o realce). */\r\n const fixaMedida = (chave: string) => {\r\n const i = columns.findIndex(c => c.key === chave) + (selectable ? 1 : 0)\r\n return i < nFixas && esquerdas.length === nFixas\r\n }\r\n const fixa = (i: number, fundo: string, filete = filetesFixos) => {\r\n // No corpo (o filete por omissão), a coluna realçada troca o fundo e os filetes.\r\n if (filete === filetesFixos && realcada !== null && realcada === chaveDoIndice(i)) {\r\n fundo = fundoRealceFixa\r\n filete = filetesRealceFixa\r\n }\r\n return i < nFixas && esquerdas.length === nFixas\r\n ? {\r\n style: { position: 'sticky' as const, left: esquerdas[i], zIndex: 10 },\r\n // Opaca de propósito: por baixo passa o resto da tabela a rolar.\r\n // A borda marca onde acaba o bloco congelado, e só aparece quando\r\n // há mesmo colunas a passar por baixo (rolado para o lado): parada,\r\n // era uma linha a mais sem razão à vista.\r\n className: `${fundo} ${filete} ${i === nFixas - 1 && roladoLado ? 'border-r border-slate-200' : ''}`,\r\n }\r\n : { style: undefined, className: '' }\r\n }\r\n\r\n const renderGroupNodes = (nodes: GroupNode<T>[], depth: number): React.ReactNode => {\r\n return nodes.map(node => {\r\n const isCollapsed = collapsedGroups.has(node.path)\r\n const hasChildren = node.children.length > 0\r\n return (\r\n <Fragment key={node.path}>\r\n <tr className=\"bg-slate-50/80 cursor-pointer select-none\" onClick={() => toggleCollapse(node.path)}>\r\n <td colSpan={colCount} className=\"px-4 py-1.5 border-b border-t border-slate-100\">\r\n <div className=\"flex items-center gap-1.5\" style={{ paddingLeft: depth * 16 }}>\r\n <ChevronRightIcon\r\n size={11}\r\n className={`text-proef-blue/60 transition-transform flex-shrink-0 ${isCollapsed ? '' : 'rotate-90'}`}\r\n />\r\n <span className=\"text-micro font-black uppercase tracking-[0.15em] text-proef-blue/70\">{node.val}</span>\r\n <span className=\"text-micro text-slate-400 ml-1\">({node.items.length})</span>\r\n </div>\r\n </td>\r\n </tr>\r\n {!isCollapsed && (\r\n hasChildren\r\n ? renderGroupNodes(node.children, depth + 1)\r\n : node.items.map(row => (\r\n <tr key={rowKey(row)} onClick={() => onRowClick?.(row)} onDoubleClick={() => onRowDoubleClick?.(row)}\r\n className={`group/linha hover:bg-slate-50 transition-colors ${onRowClick || onRowDoubleClick ? 'cursor-pointer' : ''} ${selectable && selectedKeys.has(rowKey(row)) ? 'bg-proef-turquoise/5' : ''} ${rowClassName?.(row) ?? ''}`}>\r\n {selectable && (\r\n <td style={fixa(0, fundoLinha(rowKey(row))).style} className={`px-4 py-3 ${fixa(0, fundoLinha(rowKey(row))).className}`} onClick={e => { e.stopPropagation(); toggleRow(rowKey(row)) }}>\r\n <div className={`w-4 h-4 flex items-center justify-center border transition-colors ${selectedKeys.has(rowKey(row)) ? 'bg-primary border-primary' : 'border-slate-300 hover:border-slate-400'}`}>\r\n {selectedKeys.has(rowKey(row)) && <CheckIcon size={9} strokeWidth={3} className=\"text-white\" />}\r\n </div>\r\n </td>\r\n )}\r\n {columns.map((col, i) => {\r\n const f = fixa(i + (selectable ? 1 : 0), fundoLinha(rowKey(row)))\r\n return (\r\n <td key={col.key} style={f.style} className={`px-3 py-1.5 ${col.cellClassName ?? ''} ${f.className} ${recuoFim(i)} ${realce(col.key)} ${transicaoRealce}`} data-col={col.key}>{col.render(row)}</td>\r\n )\r\n })}\r\n </tr>\r\n ))\r\n )}\r\n </Fragment>\r\n )\r\n })\r\n }\r\n\r\n /*\r\n Os dois estados em que a tabela não tem linhas para mostrar.\r\n\r\n Calculados aqui porque são lidos em dois sítios: a `tbody`, que nestes casos\r\n não desenha linha nenhuma, e o aviso por baixo da tabela, que os anuncia.\r\n\r\n A carregar: enquanto o dataset completo não chega, filtrar/ordenar/agrupar só\r\n olharia para a página — melhor esperar do que mostrar uma lista vazia (ou\r\n pior, uma lista errada) por baixo de um total nos milhares.\r\n */\r\n const aCarregar = isLoading\r\n || ((isAllDataLoading || !allData) && (hasActiveFilters || !!sortCol || isGrouped))\r\n\r\n // --- Pagination (disabled when grouped) ---\r\n const internalTotalPages = pageSize && isClientMode && !isGrouped ? Math.max(1, Math.ceil(filteredData.length / pageSize)) : 1\r\n // Clamp da página quando o total encolhe (ex: mudar filtro de dados externo)\r\n useEffect(() => { setInternalPage(p => Math.min(Math.max(1, p), internalTotalPages)) }, [internalTotalPages])\r\n const paginatedData = pageSize && isClientMode && !isGrouped ? filteredData.slice((internalPage - 1) * pageSize, internalPage * pageSize) : filteredData\r\n\r\n /*\r\n Avisar por fora quantas linhas ficaram.\r\n\r\n A função vai numa ref e fica FORA das dependências: quem nos usa passa quase\r\n sempre uma arrow nova a cada render, e com ela nas dependências o efeito\r\n corria sempre — a escrever estado lá fora, que nos fazia render outra vez.\r\n */\r\n const onVistaRef = useRef(onVista)\r\n onVistaRef.current = onVista\r\n useEffect(() => {\r\n onVistaRef.current?.({\r\n visible: filteredData.length,\r\n filtered: isClientMode && hasActiveFilters,\r\n selfPaginated: isClientMode,\r\n })\r\n }, [filteredData.length, isClientMode, hasActiveFilters])\r\n\r\n /** Não há linhas para desenhar: ou está a carregar, ou não sobrou nada. */\r\n const semLinhas = aCarregar || (isGrouped ? groups.length === 0 : paginatedData.length === 0)\r\n\r\n const setDateFilter = (colKey: string, part: 'from' | 'to', val: string) => {\r\n if (!allData) onDataNeeded?.()\r\n setDateFilters(prev => {\r\n const cur = { ...(prev[colKey] ?? {}) }\r\n if (val) cur[part] = val; else delete cur[part]\r\n const next = { ...prev }\r\n if (!cur.from && !cur.to) delete next[colKey]; else next[colKey] = cur\r\n return next\r\n })\r\n }\r\n const clearColumnFilter = (colKey: string) => {\r\n setColumnFilters(prev => { const n = { ...prev }; delete n[colKey]; return n })\r\n setDateFilters(prev => { const n = { ...prev }; delete n[colKey]; return n })\r\n setNumFilters(prev => { const n = { ...prev }; delete n[colKey]; return n })\r\n }\r\n const clearAllFilters = () => { setColumnFilters({}); setDateFilters({}); setNumFilters({}) }\r\n /*\r\n Numa coluna de números o filtro é Mín/Máx OU a lista de valores, nunca os\r\n dois: aplicar um larga o outro. Com os dois activos, o popup só mostra um\r\n deles e o que não se vê continuava a esconder linhas.\r\n */\r\n const setNumFilter = (colKey: string, min: string, max: string) => {\r\n if (!allData) onDataNeeded?.()\r\n setColumnFilters(prev => { if (!(colKey in prev)) return prev; const n = { ...prev }; delete n[colKey]; return n })\r\n setNumFilters(prev => {\r\n const n = { ...prev }\r\n if (min === '' && max === '') delete n[colKey]\r\n else n[colKey] = { ...(min !== '' ? { min } : {}), ...(max !== '' ? { max } : {}) }\r\n return n\r\n })\r\n }\r\n /**\r\n * Escreve a escolha inteira de uma coluna, de uma vez.\r\n *\r\n * O filtro deixou de se aplicar a cada clique: escolhe-se tudo no popup e só\r\n * o \"Aplicar\" mexe na tabela. Com a aplicação imediata, cada visto refazia a\r\n * lista por baixo — a tabela mudava de tamanho e de conteúdo a meio da\r\n * escolha, que é o que tornava isto confuso de usar.\r\n *\r\n * Selecção vazia = sem filtro, a mesma regra de sempre (o filtro conta-se por\r\n * `size > 0`): desmarcar tudo é o mesmo que limpar.\r\n */\r\n const aplicarValores = (colKey: string, vals: Set<string>) => {\r\n if (!allData) onDataNeeded?.()\r\n setNumFilters(prev => { if (!(colKey in prev)) return prev; const n = { ...prev }; delete n[colKey]; return n })\r\n setColumnFilters(prev => {\r\n const n = { ...prev }\r\n if (vals.size) n[colKey] = vals\r\n else delete n[colKey]\r\n return n\r\n })\r\n }\r\n const hasActiveFilter = (colKey: string) =>\r\n (columnFilters[colKey]?.size ?? 0) > 0 || dateFilterActive(dateFilters[colKey]) || numFilterActive(numFilters[colKey])\r\n const totalActiveFilters = Object.values(columnFilters).filter(s => s?.size > 0).length\r\n + Object.values(dateFilters).filter(dateFilterActive).length\r\n + Object.values(numFilters).filter(numFilterActive).length\r\n\r\n const visibleKeys = useMemo(() => paginatedData.map(row => rowKey(row)), [paginatedData, rowKey])\r\n const toggleRow = (key: string) => setSelectedKeys(prev => { const next = new Set(prev); if (next.has(key)) next.delete(key); else next.add(key); onSelectionChange?.(next); return next })\r\n const toggleAll = () => setSelectedKeys(prev => {\r\n const allSelected = visibleKeys.every(k => prev.has(k)); const next = new Set(prev)\r\n if (allSelected) visibleKeys.forEach(k => next.delete(k)); else visibleKeys.forEach(k => next.add(k))\r\n onSelectionChange?.(next); return next\r\n })\r\n const allVisibleSelected = visibleKeys.length > 0 && visibleKeys.every(k => selectedKeys.has(k))\r\n const someVisibleSelected = visibleKeys.some(k => selectedKeys.has(k)) && !allVisibleSelected\r\n\r\n /*\r\n O popup vive FORA deste componente (`ColumnFilter`, no seu ficheiro).\r\n\r\n Estava aqui dentro, e por isso era uma função nova a cada render: o React\r\n desmontava-o e remontava-o a cada tecla e a cada clique numa opção. Era isso\r\n que punha a lista de valores de volta no topo a meio de uma escolha.\r\n */\r\n const fechaFiltro = () => { setOpenFilterCol(null); setAncoraFiltro(null) }\r\n\r\n\r\n\r\n /*\r\n Larguras das colunas em pixels, medidas uma vez por CONJUNTO de colunas.\r\n\r\n O cabeçalho vive numa tabela à parte da do corpo (ver o `return`), e duas\r\n tabelas com larguras automáticas nunca dão as mesmas colunas: cada uma mede\r\n o SEU conteúdo. Ou se declaram larguras — é o que as grelhas deste projecto\r\n fazem, com um `gridTemplateColumns` partilhado — ou se medem. Mede-se, para\r\n a tabela continuar a ajustar-se ao que tem dentro.\r\n\r\n Uma vez por conjunto de colunas e não a cada página: a medida sai do que\r\n está à frente, e remedi-la a cada página fazia as colunas saltar de largura\r\n ao passar de uma para a outra. Mostrar ou esconder uma coluna repõe tudo.\r\n */\r\n /* Sem ordem: as larguras são por CHAVE, logo mudar a ordem (e a\r\n pré-visualização de um arrasto) leva cada largura com a sua coluna, sem\r\n medir outra vez. Só mostrar/esconder uma coluna mede. */\r\n const chaveColunas = `${columns.map(c => c.key).sort().join('|')}|${selectable ? 1 : 0}`\r\n /** A chave da coluna da caixa de selecção, nas larguras. */\r\n const SEL = '\\u0000sel'\r\n const chavesVista = [...(selectable ? [SEL] : []), ...columns.map(c => c.key)]\r\n const [larguras, setLarguras] = useState<Record<string, number> | null>(null)\r\n const corpoRef = useRef<HTMLTableElement>(null)\r\n const medidaRef = useRef<HTMLTableElement>(null)\r\n const peloConjunto = preencheAltura && larguraPeloConjunto\r\n // No modo pelo conjunto, outro dataset (ex: outro dia) é outra medida.\r\n useLayoutEffect(() => { setLarguras(null) }, [chaveColunas, peloConjunto ? allData : null])\r\n\r\n /*\r\n Um exemplar de cada valor distinto, por coluna — é o que a tabela de medida\r\n desenha. Valores iguais dão a mesma largura, e em 850 linhas pode haver\r\n 20 valores distintos numa coluna: medir as 850 era desenhar o mesmo 40 vezes.\r\n */\r\n const exemplares = useMemo(() => {\r\n if (!peloConjunto || larguras || !allData?.length) return null\r\n const porColuna = columns.map(col => {\r\n const vistos = new Map<string, T>()\r\n for (const row of allData) {\r\n const k = String(col.value ? col.value(row) ?? '' : '')\r\n if (!vistos.has(k)) vistos.set(k, row)\r\n }\r\n return [...vistos.values()]\r\n })\r\n const n = Math.max(...porColuna.map(l => l.length))\r\n return { porColuna, n }\r\n }, [peloConjunto, larguras, allData, chaveColunas])\r\n\r\n useLayoutEffect(() => {\r\n // Sem o modo de página o cabeçalho não se separa e não há nada a medir.\r\n if (!preencheAltura || larguras || isGrouped) return\r\n // As linhas-esqueleto não têm conteúdo: medi-las prendia as colunas à\r\n // largura dos títulos. Mede-se quando chegam as linhas de verdade.\r\n if (aCarregar && esqueletoAoCarregar) return\r\n const ths = Array.from(cabecalhoRef.current?.children ?? []) as HTMLElement[]\r\n /* Pelo conjunto, mede-se a tabela escondida: numa tabela automática a\r\n coluna vale o que vale a célula mais larga dela, logo a primeira linha\r\n já traz o máximo de todas. */\r\n const fonte = peloConjunto ? medidaRef.current : corpoRef.current\r\n const tds = Array.from(fonte?.rows?.[0]?.cells ?? []) as HTMLElement[]\r\n // Sem linhas ainda: espera-se por elas, senão as colunas ficavam do tamanho\r\n // dos títulos e apertavam mal chegasse conteúdo.\r\n if (!ths.length || !tds.length) return\r\n const novas = Object.fromEntries(ths.map((th, i) => [chavesVista[i] ?? String(i),\r\n Math.ceil(Math.max(th.getBoundingClientRect().width, tds[i]?.getBoundingClientRect().width ?? 0))]))\r\n setLarguras(novas)\r\n if (esqueletoAoCarregar && storageKey) {\r\n try { localStorage.setItem(`dt_larguras_${storageKey}`, JSON.stringify({ colunas: chaveColunas, larguras: novas })) } catch { /* sem armazenamento: o esqueleto usa as larguras dos títulos */ }\r\n }\r\n }, [preencheAltura, larguras, isGrouped, chaveColunas, paginatedData, exemplares, aCarregar, esqueletoAoCarregar])\r\n\r\n /*\r\n O esqueleto com as colunas da última vez que a tabela carregou (mesmo\r\n conjunto de colunas), para as barras ficarem onde vão ficar os dados. Na\r\n primeira vez de sempre não há medida e as colunas são as dos títulos.\r\n */\r\n const largurasGuardadas = useMemo(() => {\r\n if (!esqueletoAoCarregar || !storageKey) return null\r\n try {\r\n const g = JSON.parse(localStorage.getItem(`dt_larguras_${storageKey}`) ?? 'null')\r\n return g?.colunas === chaveColunas ? (g.larguras as Record<string, number>) : null\r\n } catch { return null }\r\n }, [esqueletoAoCarregar, storageKey, chaveColunas])\r\n /* Sem medida guardada, as colunas do esqueleto são as dos títulos — medidas\r\n daqui, porque o cabeçalho é outra tabela e por si só não as alinhava. */\r\n const [largurasTitulos, setLargurasTitulos] = useState<Record<string, number> | null>(null)\r\n const esqueletoSemMedida = preencheAltura && !isGrouped && aCarregar && esqueletoAoCarregar && !larguras && !largurasGuardadas\r\n useLayoutEffect(() => {\r\n if (!esqueletoSemMedida) { setLargurasTitulos(null); return }\r\n const ths = Array.from(cabecalhoRef.current?.children ?? []) as HTMLElement[]\r\n if (!ths.length) return\r\n setLargurasTitulos(Object.fromEntries(ths.map((th, i) => [chavesVista[i] ?? String(i), Math.ceil(th.getBoundingClientRect().width)])))\r\n }, [esqueletoSemMedida, chaveColunas])\r\n const largurasVista = larguras ?? (aCarregar && esqueletoAoCarregar ? largurasGuardadas ?? largurasTitulos : null)\r\n\r\n /*\r\n A barra de scroll vertical do corpo estreita-o, e o cabeçalho — que não tem\r\n barra nenhuma — ficava mais largo e desalinhado no extremo direito. Reserva-se\r\n do lado do cabeçalho a mesma largura que a barra ocupa.\r\n */\r\n const caixaCorpoRef = useRef<HTMLDivElement>(null)\r\n /* A barra sobreposta precisa do elemento em estado (liga-se a ele num\r\n efeito); o ref sozinho não faz render quando a caixa aparece. */\r\n const [caixaCorpo, setCaixaCorpo] = useState<HTMLDivElement | null>(null)\r\n const refCaixaCorpo = useCallback((el: HTMLDivElement | null) => {\r\n caixaCorpoRef.current = el\r\n setCaixaCorpo(el)\r\n }, [])\r\n const caixaCabecalhoRef = useRef<HTMLDivElement>(null)\r\n /* Há colunas por ver à direita? Revisto ao rolar e quando a caixa ou a\r\n tabela mudam de tamanho (colunas mostradas/escondidas, dados a chegar). */\r\n const [restaDireita, setRestaDireita] = useState(false)\r\n /* Rolado para o lado: há colunas a passar por baixo das congeladas, e só\r\n então a borda delas aparece (ver `fixa`). */\r\n const [roladoLado, setRoladoLado] = useState(false)\r\n /** A caixa que rola sem `fillHeight` (com ele é a `caixaCorpo`). */\r\n const [caixaSimples, setCaixaSimples] = useState<HTMLDivElement | null>(null)\r\n useEffect(() => {\r\n const c = caixaCorpo ?? caixaSimples\r\n if (!nFixas || !c) return\r\n const ver = () => {\r\n const rolado = c.scrollLeft > 0\r\n setRoladoLado(prev => (prev === rolado ? prev : rolado))\r\n }\r\n ver()\r\n c.addEventListener('scroll', ver, { passive: true })\r\n return () => c.removeEventListener('scroll', ver)\r\n }, [nFixas, caixaCorpo, caixaSimples])\r\n useEffect(() => {\r\n const c = caixaCorpo\r\n if (!esbaterDireita || !c) return\r\n const ver = () => {\r\n const resta = c.scrollLeft + c.clientWidth < c.scrollWidth - 1\r\n setRestaDireita(prev => (prev === resta ? prev : resta))\r\n }\r\n ver()\r\n c.addEventListener('scroll', ver, { passive: true })\r\n const ro = new ResizeObserver(ver)\r\n ro.observe(c)\r\n if (c.firstElementChild) ro.observe(c.firstElementChild)\r\n return () => { c.removeEventListener('scroll', ver); ro.disconnect() }\r\n }, [esbaterDireita, caixaCorpo])\r\n const mascaraDireita = 'linear-gradient(to right, #000 calc(100% - 48px), transparent)'\r\n const [barra, setBarra] = useState(0)\r\n useLayoutEffect(() => {\r\n const medir = () => {\r\n const c = caixaCorpoRef.current\r\n if (!c) return\r\n const w = c.offsetWidth - c.clientWidth\r\n setBarra(prev => (prev === w ? prev : w))\r\n }\r\n medir()\r\n const c = caixaCorpoRef.current\r\n if (!c) return\r\n const ro = new ResizeObserver(medir)\r\n ro.observe(c)\r\n return () => ro.disconnect()\r\n }, [preencheAltura, paginatedData])\r\n\r\n const grupoColunas = largurasVista ? (\r\n <colgroup>{chavesVista.map(k => <col key={k} style={{ width: largurasVista[k] }} />)}</colgroup>\r\n ) : null\r\n\r\n /*\r\n Medidas: largura fixa e igual nas duas tabelas. Por medir: automática, como\r\n sempre foi — é desse render que saem as medidas.\r\n\r\n `minWidth: '100%'` para o caso de as colunas somarem menos do que a caixa:\r\n sem ele ficava uma faixa vazia à direita da tabela.\r\n\r\n A medir, nada de `100%`: os títulos e as células têm de dar a SUA largura,\r\n não a de uma fatia da caixa. Esticadas, o cabeçalho e o corpo (duas tabelas)\r\n repartiam a sobra cada um à sua maneira, e o maior dos dois em cada coluna\r\n somava mais do que a caixa: havia sempre scroll para o lado, mesmo com tudo\r\n a caber. Com medidas, o `minWidth` volta: as larguras medidas são o mínimo,\r\n e o espaço que sobrar reparte-se por elas.\r\n */\r\n const estiloTabela: React.CSSProperties = largurasVista\r\n ? { tableLayout: 'fixed', width: chavesVista.reduce((a, k) => a + (largurasVista[k] ?? 0), 0), minWidth: '100%' }\r\n : { width: 'max-content' }\r\n\r\n const cabecalho = (fixoNoTopo: boolean) => (\r\n <thead className={fixoNoTopo ? 'sticky top-0 z-20' : undefined}>\r\n <tr ref={cabecalhoRef} className={`text-micro font-black uppercase text-slate-400 tracking-[0.15em] ${\r\n !bordasSeparadas ? 'border-b-2 border-slate-200 bg-slate-50'\r\n : fundoNosTitulos ? '[&>th]:border-b-2 [&>th]:border-slate-200'\r\n : 'shadow-[inset_0_-2px_0_0_var(--color-slate-200)]'}`}>\r\n {selectable && (\r\n <th style={cabecaFixa(0).style} className={`px-4 py-3 w-10 ${fundoNosTitulos ? 'bg-slate-50' : ''} ${cabecaFixa(0).className}`}>\r\n <button onClick={toggleAll} className={`w-4 h-4 flex items-center justify-center border transition-colors ${allVisibleSelected ? 'bg-primary border-primary' : someVisibleSelected ? 'bg-slate-300 border-slate-300' : 'border-slate-300 hover:border-slate-400'}`}>\r\n {(allVisibleSelected || someVisibleSelected) && <CheckIcon size={9} strokeWidth={3} className=\"text-white\" />}\r\n </button>\r\n </th>\r\n )}\r\n {columns.map((col, i) => {\r\n const canSort = col.sortable !== false && !!col.value\r\n const canFilter = col.filterable !== false && !!col.value\r\n const canGroup = col.groupable === true && !!col.value\r\n const isSortActive = sortCol === col.key\r\n const isFiltered = hasActiveFilter(col.key)\r\n const isFilterOpen = openFilterCol === col.key\r\n const isColGrouped = groupByKeys.includes(col.key)\r\n /* Com o filtro aberto não se arrasta: o popup vive dentro\r\n deste <th>, e arrastar nas caixas dele (para escolher\r\n texto, por exemplo) levava a coluna atrás. */\r\n const arrastavel = !!onMoverColuna && !isFilterOpen\r\n return (\r\n <th key={col.key} style={cabecaFixa(i + (selectable ? 1 : 0)).style}\r\n onPointerDown={arrastavel ? e => premirTitulo(e, col.key) : undefined}\r\n className={`px-4 py-3 ${col.headerClassName ?? ''} ${cabecaFixa(i + (selectable ? 1 : 0)).className} ${\r\n arrastavel ? 'cursor-grab' : ''\r\n } ${realce(col.key, true)} ${transicaoRealce}`}\r\n data-col={col.key}>\r\n <div className=\"flex items-center gap-1.5 group/hdr whitespace-nowrap select-none\">\r\n {canSort ? (\r\n <button onClick={() => { if (!allData) onDataNeeded?.(); if (sortCol === col.key) setSortDir(d => d === 'asc' ? 'desc' : 'asc'); else { setSortCol(col.key); setSortDir('asc') } }}\r\n className={`flex items-center gap-0.5 transition-colors hover:text-slate-700 ${isSortActive ? 'text-proef-blue' : ''}`}>\r\n <span>{col.label}</span>\r\n {isSortActive && sortDir === 'asc' ? <ChevronUpIcon size={11} /> : isSortActive && sortDir === 'desc' ? <ChevronDownIcon size={11} /> : <ChevronsUpDownIcon size={11} className=\"opacity-50 group-hover/hdr:opacity-100\" />}\r\n </button>\r\n ) : <span>{col.label}</span>}\r\n\r\n {canGroup && (\r\n <button onClick={() => toggleGroup(col.key)}\r\n title={isColGrouped ? L.ungroupBy(col.label) : L.groupBy(col.label)} aria-label={isColGrouped ? L.ungroupBy(col.label) : L.groupBy(col.label)} aria-pressed={isColGrouped}\r\n className={`p-0.5 rounded transition-colors ${isColGrouped ? 'text-violet-600 bg-violet-100 opacity-100' : 'text-slate-400 opacity-50 group-hover/hdr:opacity-100 hover:text-slate-600'}`}>\r\n <LayersIcon size={10} />\r\n </button>\r\n )}\r\n\r\n {canFilter && (\r\n <div className=\"relative\">\r\n <button onClick={e => {\r\n // O rect lê-se JÁ: o React anula o `currentTarget`\r\n // assim que o handler devolve.\r\n const r = e.currentTarget.getBoundingClientRect()\r\n if (isFilterOpen) { fechaFiltro() }\r\n else { if (!allData) onDataNeeded?.(); setAncoraFiltro(r); setOpenFilterCol(col.key) }\r\n }}\r\n title={L.filterBy(col.label)} aria-label={L.filterBy(col.label)} aria-expanded={isFilterOpen}\r\n className={`p-0.5 transition-colors ${isFiltered || isFilterOpen ? 'text-proef-blue opacity-100' : 'text-slate-400 opacity-50 group-hover/hdr:opacity-100 hover:text-slate-600'}`}>\r\n <FilterIcon size={10} />\r\n </button>\r\n {isFilterOpen && ancoraFiltro && (\r\n <ColumnFilter\r\n labels={L}\r\n canSort={canSort}\r\n ancora={ancoraFiltro}\r\n tipo={col.filterType === 'date' ? 'data' : col.filterType === 'number' ? 'numero' : 'texto'}\r\n valores={col.filterType === 'date' ? [] : getUniqueValues(col.key)}\r\n seleccionados={columnFilters[col.key] ?? new Set()}\r\n intervalo={dateFilters[col.key] ?? {}}\r\n numero={numFilters[col.key] ?? {}}\r\n ordenadaPor={sortCol === col.key ? sortDir : null}\r\n aCarregar={!allData && !!isAllDataLoading}\r\n onOrdenar={dir => { setSortCol(col.key); setSortDir(dir) }}\r\n onAplicar={vals => { aplicarValores(col.key, vals); fechaFiltro() }}\r\n onAplicarDatas={(de, ate) => { setDateFilter(col.key, 'from', de); setDateFilter(col.key, 'to', ate); fechaFiltro() }}\r\n onAplicarNumeros={(min, max) => { setNumFilter(col.key, min, max); fechaFiltro() }}\r\n onLimpar={() => { clearColumnFilter(col.key); fechaFiltro() }}\r\n onFechar={fechaFiltro}\r\n />\r\n )}\r\n </div>\r\n )}\r\n\r\n {col.extraFilters?.map(sf => {\r\n const isEfFiltered = hasActiveFilter(sf.key)\r\n const isEfOpen = openFilterCol === sf.key\r\n return (\r\n <div key={sf.key} className=\"relative\">\r\n <button onClick={e => {\r\n const r = e.currentTarget.getBoundingClientRect()\r\n if (isEfOpen) { fechaFiltro() }\r\n else { setAncoraFiltro(r); setOpenFilterCol(sf.key) }\r\n }}\r\n title={L.filterBy(sf.label)} aria-label={L.filterBy(sf.label)} aria-expanded={isEfOpen}\r\n className={`p-0.5 transition-colors ${isEfFiltered || isEfOpen ? 'text-violet-600 opacity-100' : 'text-slate-300 opacity-40 group-hover/hdr:opacity-90 hover:text-slate-500'}`}>\r\n <FilterIcon size={9} />\r\n </button>\r\n {isEfOpen && ancoraFiltro && (\r\n <ColumnFilter\r\n labels={L}\r\n label={sf.label}\r\n ancora={ancoraFiltro}\r\n tipo={sf.filterType === 'date' ? 'data' : sf.filterType === 'number' ? 'numero' : 'texto'}\r\n valores={sf.filterType === 'date' ? [] : getUniqueValues(sf.key)}\r\n seleccionados={columnFilters[sf.key] ?? new Set()}\r\n intervalo={dateFilters[sf.key] ?? {}}\r\n numero={numFilters[sf.key] ?? {}}\r\n ordenadaPor={null}\r\n aCarregar={!allData && !!isAllDataLoading}\r\n onAplicar={vals => { aplicarValores(sf.key, vals); fechaFiltro() }}\r\n onAplicarDatas={(de, ate) => { setDateFilter(sf.key, 'from', de); setDateFilter(sf.key, 'to', ate); fechaFiltro() }}\r\n onAplicarNumeros={(min, max) => { setNumFilter(sf.key, min, max); fechaFiltro() }}\r\n onLimpar={() => { clearColumnFilter(sf.key); fechaFiltro() }}\r\n onFechar={fechaFiltro}\r\n />\r\n )}\r\n </div>\r\n )\r\n })}\r\n </div>\r\n {col.headerExtra && <div className=\"mt-0.5 normal-case font-normal tracking-normal\">{col.headerExtra(filteredData)}</div>}\r\n </th>\r\n )\r\n })}\r\n </tr>\r\n </thead>\r\n )\r\n\r\n /** Larguras das barras do esqueleto, a variar por linha e coluna para não parecer uma grelha. */\r\n const LARGURAS_ESQUELETO = ['w-3/4', 'w-1/2', 'w-2/3', 'w-5/6', 'w-2/5']\r\n const linhasEsqueleto = Array.from({ length: 20 }, (_, r) => (\r\n <tr key={`esqueleto-${r}`} aria-hidden className=\"animate-pulse motion-reduce:animate-none\">\r\n {selectable && (\r\n <td style={fixa(0, 'bg-white').style} className={`px-4 py-3 ${fixa(0, 'bg-white').className}`}>\r\n <div className=\"w-4 h-4 border border-slate-200 bg-slate-50\" />\r\n </td>\r\n )}\r\n {columns.map((col, i) => {\r\n const f = fixa(i + (selectable ? 1 : 0), 'bg-white')\r\n return (\r\n <td key={col.key} style={f.style} className={`px-3 py-2.5 ${f.className} ${recuoFim(i)}`}>\r\n {/* Encostada como o valor que vai lá ficar: à direita nos números, ao centro nos centrados. */}\r\n <div className={`h-2 bg-slate-200 ${LARGURAS_ESQUELETO[(r + i) % LARGURAS_ESQUELETO.length]} ${\r\n /text-right/.test(col.cellClassName ?? '') ? 'ml-auto' : /text-center/.test(col.cellClassName ?? '') ? 'mx-auto' : ''}`} />\r\n </td>\r\n )\r\n })}\r\n </tr>\r\n ))\r\n\r\n const corpo = (\r\n <tbody className={bordasSeparadas ? '[&>tr+tr]:shadow-[inset_0_1px_0_0_var(--color-slate-100)]' : 'divide-y divide-slate-100'}>\r\n {/* Sem linhas — a carregar ou sem resultados — a `tbody` fica vazia e\r\n quem fala é o aviso logo a seguir à tabela. Ver lá porquê. */}\r\n {aCarregar ? (esqueletoAoCarregar ? linhasEsqueleto : null) : isGrouped ? (\r\n <>{renderGroupNodes(groups, 0)}</>\r\n ) : paginatedData.map(row => (\r\n <tr key={rowKey(row)} onClick={() => onRowClick?.(row)} onDoubleClick={() => onRowDoubleClick?.(row)}\r\n className={`group/linha hover:bg-slate-50 transition-colors ${onRowClick || onRowDoubleClick ? 'cursor-pointer' : ''} ${selectable && selectedKeys.has(rowKey(row)) ? 'bg-proef-turquoise/5' : ''} ${rowClassName?.(row) ?? ''}`}>\r\n {selectable && (\r\n <td style={fixa(0, fundoLinha(rowKey(row))).style} className={`px-4 py-3 ${fixa(0, fundoLinha(rowKey(row))).className}`} onClick={e => { e.stopPropagation(); toggleRow(rowKey(row)) }}>\r\n <div className={`w-4 h-4 flex items-center justify-center border transition-colors ${selectedKeys.has(rowKey(row)) ? 'bg-primary border-primary' : 'border-slate-300 hover:border-slate-400'}`}>\r\n {selectedKeys.has(rowKey(row)) && <CheckIcon size={9} strokeWidth={3} className=\"text-white\" />}\r\n </div>\r\n </td>\r\n )}\r\n {columns.map((col, i) => {\r\n const f = fixa(i + (selectable ? 1 : 0), fundoLinha(rowKey(row)))\r\n return (\r\n <td key={col.key} style={f.style} className={`px-3 py-1.5 ${col.cellClassName ?? ''} ${f.className} ${recuoFim(i)} ${realce(col.key)} ${transicaoRealce}`} data-col={col.key}>{col.render(row)}</td>\r\n )\r\n })}\r\n </tr>\r\n ))}\r\n </tbody>\r\n )\r\n\r\n\r\n {/*\r\n Os avisos de \"a carregar\" e \"sem resultados\" vivem AQUI, fora da\r\n tabela.\r\n\r\n Dentro, eram um `<td colSpan>` — e um `td` desses é tão largo como a\r\n tabela, que nestes ecrãs passa dos 40 colunas e é muito mais larga do\r\n que o que se vê. Centrar nele é centrar numa largura invisível: com a\r\n tabela rolada, o spinner aparecia encostado a um lado ou fora do ecrã.\r\n\r\n Como bloco irmão da tabela, a largura passa a ser a da CAIXA (um filho\r\n de bloco de um contentor com `overflow` mede a parte visível, não a\r\n rolável), e o `sticky left-0` prende-o ao bordo esquerdo do que se vê\r\n enquanto se rola na horizontal. O centro é sempre o centro do que está\r\n à frente de quem espera.\r\n */}\r\n const aviso = aCarregar && esqueletoAoCarregar ? (\r\n // O esqueleto já diz que está a carregar; o texto fica para leitores de ecrã.\r\n loadingLabel ? <span role=\"status\" className=\"sr-only\">{loadingLabel}</span> : null\r\n ) : semLinhas ? (\r\n <div className=\"sticky left-0 w-full flex-1 py-10 flex flex-col items-center justify-center gap-3 text-center\">\r\n {aCarregar ? (\r\n <>\r\n <span aria-hidden className=\"inline-block h-7 w-7 animate-spin rounded-full border-2 border-current border-t-transparent text-proef-turquoise\" />\r\n {loadingLabel && (\r\n <span className=\"text-xs font-bold uppercase tracking-widest text-slate-400\">{loadingLabel}</span>\r\n )}\r\n </>\r\n ) : (\r\n <>\r\n <p className=\"text-slate-600 font-bold text-sm\">{vazio}</p>\r\n {emptySubLabel && <p className=\"text-slate-400 text-xs -mt-1\">{emptySubLabel}</p>}\r\n </>\r\n )}\r\n </div>\r\n ) : null\r\n\r\n // A troca de páginas do fundo só aparece em modo cliente e com mais de uma\r\n // página. Sem ela (quando quem alimenta a tabela pagina por fora), a horizontal centrada\r\n // na aresta saía metade para fora da caixa e um `overflow-hidden` à volta cortava-a.\r\n const temRodape = !paginacaoNoTopo && isClientMode && !isGrouped && !!pageSize && internalTotalPages > 1\r\n\r\n /*\r\n A barra de cima (`PaginatedTable`). Mostra sempre a paginação que está a\r\n valer: a do servidor (a página que a app dá), ou a da própria tabela quando\r\n ela se pagina a si mesma (filtros, ordenação, agrupamento com o conjunto\r\n completo). Dois paginadores à vista, um deles sem efeito, baralhava.\r\n */\r\n const topo = paginacaoNoTopo\r\n const peloServidor = !!topo?.onPageChange && topo.page !== undefined && !isClientMode\r\n const paginaTopo = peloServidor ? topo!.page! : internalPage\r\n const totalPaginasTopo = peloServidor\r\n ? Math.max(1, Math.ceil((topo!.total ?? data.length) / (pageSize || data.length || 1)))\r\n : internalTotalPages\r\n const irParaPagina = (p: number) => (peloServidor ? topo!.onPageChange!(p) : setInternalPage(p))\r\n /* A contagem: o total do servidor (ou do conjunto). Filtrada pelo cabeçalho,\r\n as que sobraram DE quantas: \"1 de 120\" diz que o filtro está a esconder o\r\n resto, e \"1 ordem\" sozinho parecia que a lista só tinha uma. */\r\n const totalTopo = topo?.total ?? (allData ?? data).length\r\n const filtradaTopo = isClientMode && hasActiveFilters\r\n const contagem = filtradaTopo ? filteredData.length : totalTopo\r\n /* A carregar pela primeira vez, \"0 linhas\" era falso: esqueletos no lugar\r\n dos números, e a paginação já lá, desligada, para não aparecer do nada. */\r\n const topoACarregar = !!isLoading && data.length === 0\r\n /*\r\n Os números de página: a primeira e a última sempre à vista, e \"…\" no que\r\n fica no meio, para se poder saltar para o fim sem andar de 7 em 7. Sete\r\n lugares no total, para a barra não mudar de largura ao mudar de página.\r\n Sem Anterior/Seguinte: os números já levam à página ao lado.\r\n */\r\n const numerosPagina: (number | '…')[] =\r\n totalPaginasTopo <= 7 ? Array.from({ length: totalPaginasTopo }, (_, i) => i + 1)\r\n : paginaTopo <= 4 ? [1, 2, 3, 4, 5, '…', totalPaginasTopo]\r\n : paginaTopo >= totalPaginasTopo - 3\r\n ? [1, '…', ...Array.from({ length: 5 }, (_, i) => totalPaginasTopo - 4 + i)]\r\n : [1, '…', paginaTopo - 1, paginaTopo, paginaTopo + 1, '…', totalPaginasTopo]\r\n const esqueletoTopo = <span className=\"inline-block h-2 w-8 rounded-sm bg-slate-200 animate-pulse motion-reduce:animate-none\" aria-hidden />\r\n /* Os chips do que está agrupado e filtrado no cabeçalho, com o × de cada um\r\n e o \"limpar\". Na `Table` ficam numa faixa por cima das linhas; no\r\n `PaginatedTable` dentro da barra de cima, para a tabela não descer quando\r\n aparecem (a faixa nova empurrava tudo). */\r\n const nomeDoFiltro = (colKey: string) =>\r\n columns.find(c => c.key === colKey)?.label\r\n ?? columns.flatMap(c => c.extraFilters ?? []).find(f => f.key === colKey)?.label\r\n ?? colKey\r\n /*\r\n Os chips na barra de cima (PaginatedTable): um plano para quando são muitos.\r\n Cabem os que cabem numa linha; os outros vão para um \"+N\" que abre uma lista\r\n com eles. O \"Limpar\" fica sempre no mesmo sítio, encostado à direita da zona\r\n dos chips, e a barra nunca muda de altura: filtrar não empurra nada.\r\n */\r\n /* Cada chip diz a coluna (rótulo, discreto) e o valor (a cheio), para se ler\r\n o filtro de relance; o `texto` junta os dois para o × e leitores de ecrã. */\r\n interface ItemChip { chave: string; tipo: 'grupo' | 'filtro'; rotulo: string; valor: string; texto: string; remover: () => void }\r\n const itemChip = (chave: string, tipo: ItemChip['tipo'], rotulo: string, valor: string, remover: () => void): ItemChip =>\r\n ({ chave, tipo, rotulo, valor, remover, texto: tipo === 'grupo' ? `${rotulo} ${valor}` : `${rotulo}: ${valor}` })\r\n const textoData = (r: { from?: string; to?: string }) =>\r\n r.from && r.to ? `${r.from} → ${r.to}` : r.from ? `≥ ${r.from}` : `≤ ${r.to}`\r\n const textoNum = (r: { min?: string; max?: string }) => {\r\n const temMin = r.min !== undefined && r.min !== ''\r\n const temMax = r.max !== undefined && r.max !== ''\r\n return temMin && temMax ? `${r.min} – ${r.max}` : temMin ? `≥ ${r.min}` : `≤ ${r.max}`\r\n }\r\n const itensChips: ItemChip[] = [\r\n ...groupByKeys.map(k => itemChip(`g-${k}`, 'grupo', L.groupedBy, columns.find(c => c.key === k)?.label ?? k, () => removeGroup(k))),\r\n ...Object.entries(columnFilters).filter(([, v]) => v && v.size > 0).map(([k, v]) => {\r\n const arr = Array.from(v)\r\n return itemChip(`v-${k}`, 'filtro', nomeDoFiltro(k), arr.length > 2 ? L.selectedCount(arr.length) : arr.join(', '), () => clearColumnFilter(k))\r\n }),\r\n ...Object.entries(dateFilters).filter(([, r]) => dateFilterActive(r))\r\n .map(([k, r]) => itemChip(`d-${k}`, 'filtro', nomeDoFiltro(k), textoData(r), () => clearColumnFilter(k))),\r\n // Os intervalos Mín/Máx também levam chip: sem ele, um filtro de números\r\n // escondia linhas sem nada à vista que o dissesse.\r\n ...Object.entries(numFilters).filter(([, r]) => numFilterActive(r))\r\n .map(([k, r]) => itemChip(`n-${k}`, 'filtro', nomeDoFiltro(k), textoNum(r), () => clearColumnFilter(k))),\r\n ]\r\n // Neutros, com a altura e o canto do seletor de linhas por página: a cor fica\r\n // para o que é preciso ver (a página atual, os filtros ativos no cabeçalho).\r\n const chip = (it: ItemChip, focavel = true) => (\r\n <div key={it.chave} className=\"shrink-0 whitespace-nowrap h-7 flex items-center gap-1.5 pl-2.5 pr-1 rounded-md border border-slate-200 bg-white text-caption\">\r\n {it.tipo === 'grupo' && <LayersIcon size={12} className=\"text-slate-400\" />}\r\n <span className=\"text-slate-500\">{it.rotulo}</span>\r\n <span className=\"font-semibold text-slate-800\">{it.valor}</span>\r\n <button type=\"button\" tabIndex={focavel ? undefined : -1} aria-label={L.removeChip(it.texto)} onClick={it.remover}\r\n className=\"h-5 w-5 flex items-center justify-center rounded text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700\">\r\n <CloseIcon size={10} />\r\n </button>\r\n </div>\r\n )\r\n const classeLimpar = 'shrink-0 whitespace-nowrap text-caption font-medium text-slate-500 hover:text-red-600 transition-colors'\r\n const chipsGrupo = isGrouped ? (\r\n <>\r\n {itensChips.filter(i => i.tipo === 'grupo').map(i => chip(i))}\r\n <button type=\"button\" onClick={clearAllGroups} className={classeLimpar}>{L.clearGroups}</button>\r\n </>\r\n ) : null\r\n const chipsFiltro = totalActiveFilters > 0 ? (\r\n <>\r\n {itensChips.filter(i => i.tipo === 'filtro').map(i => chip(i))}\r\n <button type=\"button\" onClick={clearAllFilters} className={classeLimpar}>{L.clearAll}</button>\r\n </>\r\n ) : null\r\n const classeMais = 'shrink-0 whitespace-nowrap h-7 px-2 rounded-md border border-slate-200 bg-slate-50 text-caption font-semibold text-slate-600 hover:bg-slate-100 transition-colors'\r\n const meioRef = useRef<HTMLDivElement>(null)\r\n const medidaChipsRef = useRef<HTMLDivElement>(null)\r\n const limparRef = useRef<HTMLButtonElement>(null)\r\n const maisRef = useRef<HTMLDivElement>(null)\r\n const [chipsQueCabem, setChipsQueCabem] = useState(Number.POSITIVE_INFINITY)\r\n const [maisAberto, setMaisAberto] = useState(false)\r\n const chaveChips = itensChips.map(i => `${i.chave}=${i.texto}`).join('|')\r\n useLayoutEffect(() => {\r\n const meio = meioRef.current\r\n const medida = medidaChipsRef.current\r\n if (!topo || !meio || !medida) return\r\n // Quantos chips cabem, a contar com o \"+N\" (o último da linha de medida) se sobrarem.\r\n const calcular = () => {\r\n const larguras = Array.from(medida.children, c => (c as HTMLElement).getBoundingClientRect().width)\r\n const mais = larguras.pop() ?? 0\r\n const ESPACO = 6\r\n const limpar = limparRef.current?.getBoundingClientRect().width ?? 0\r\n const disponivel = meio.clientWidth - (limpar ? limpar + ESPACO * 2 : 0)\r\n let usado = 0\r\n let k = 0\r\n for (; k < larguras.length; k++) {\r\n const proximo = usado + (k ? ESPACO : 0) + larguras[k]\r\n const sobram = larguras.length - k - 1\r\n if (proximo + (sobram > 0 ? ESPACO + mais : 0) > disponivel) break\r\n usado = proximo\r\n }\r\n setChipsQueCabem(prev => (prev === k ? prev : k))\r\n }\r\n calcular()\r\n if (typeof ResizeObserver === 'undefined') return\r\n const ro = new ResizeObserver(calcular)\r\n ro.observe(meio)\r\n return () => ro.disconnect()\r\n }, [topo, chaveChips])\r\n const chipsVisiveis = itensChips.slice(0, chipsQueCabem)\r\n const chipsEscondidos = itensChips.slice(chipsQueCabem)\r\n // A lista do \"+N\" fecha ao clicar fora, com o Esc, ou quando já não esconde nada.\r\n useEffect(() => {\r\n if (!maisAberto) return\r\n const fora = (e: MouseEvent) => { if (!maisRef.current?.contains(e.target as Node)) setMaisAberto(false) }\r\n const tecla = (e: KeyboardEvent) => { if (e.key === 'Escape') setMaisAberto(false) }\r\n document.addEventListener('mousedown', fora)\r\n document.addEventListener('keydown', tecla)\r\n return () => {\r\n document.removeEventListener('mousedown', fora)\r\n document.removeEventListener('keydown', tecla)\r\n }\r\n }, [maisAberto])\r\n useEffect(() => { if (!chipsEscondidos.length) setMaisAberto(false) }, [chipsEscondidos.length])\r\n\r\n const barraTopo = topo ? (\r\n <div className=\"px-4 py-2 bg-white border-b border-slate-200 flex items-center justify-between gap-3 text-caption text-slate-500 shrink-0\">\r\n {/* À esquerda o que a lista é (quantas linhas, de quantas em quantas);\r\n à direita as páginas. */}\r\n <div className=\"shrink-0 flex items-center gap-3\">\r\n <span className=\"flex items-center gap-1\">\r\n {topoACarregar ? esqueletoTopo : <span className=\"font-semibold text-slate-800 tabular-nums\">{contagem}</span>}\r\n {filtradaTopo && !topoACarregar && <>{L.of} <span className=\"tabular-nums\">{totalTopo}</span></>}\r\n {L.rowsNoun(filtradaTopo ? totalTopo : contagem)}\r\n </span>\r\n {topo.pageSizeOptions && topo.onPageSizeChange && (\r\n <span className=\"relative inline-flex items-center\">\r\n <select\r\n value={pageSize}\r\n onChange={e => topo.onPageSizeChange!(Number(e.target.value))}\r\n aria-label={L.pageSize}\r\n className=\"h-7 appearance-none rounded-md border border-slate-200 bg-white pl-2.5 pr-7 text-caption font-medium text-slate-600 cursor-pointer transition-colors hover:border-slate-300 focus:outline-none focus-visible:border-proef-blue focus-visible:ring-2 focus-visible:ring-proef-blue/15\"\r\n >\r\n {topo.pageSizeOptions.map(n => <option key={n} value={n}>{L.perPage(n)}</option>)}\r\n </select>\r\n <ChevronDownIcon size={12} className=\"pointer-events-none absolute right-2 text-slate-400\" />\r\n </span>\r\n )}\r\n </div>\r\n {/* Agrupamentos e filtros: os que cabem numa linha, o \"+N\" com os\r\n outros, e o \"Limpar\" sempre no mesmo sítio, à direita. */}\r\n <div ref={meioRef} className=\"relative flex-1 min-w-0 flex items-center gap-1.5\">\r\n {/* Linha invisível com todos os chips (e um \"+99\"), só para os medir. */}\r\n <div className=\"absolute inset-0 overflow-hidden pointer-events-none\" aria-hidden>\r\n <div ref={medidaChipsRef} className=\"invisible flex w-max gap-1.5\">\r\n {itensChips.map(i => chip(i, false))}\r\n <span className={`flex items-center ${classeMais}`}>+99</span>\r\n </div>\r\n </div>\r\n <div className=\"min-w-0 flex items-center gap-1.5 overflow-hidden\">\r\n {chipsVisiveis.map(i => chip(i))}\r\n </div>\r\n {chipsEscondidos.length > 0 && (\r\n <div ref={maisRef} className=\"relative shrink-0\">\r\n <button type=\"button\" aria-expanded={maisAberto} aria-label={L.moreChips(chipsEscondidos.length)}\r\n onClick={() => setMaisAberto(a => !a)} className={classeMais}>\r\n +{chipsEscondidos.length}\r\n </button>\r\n {maisAberto && (\r\n <div className=\"absolute left-0 top-full mt-1.5 z-40 w-max max-w-[22rem] p-2 flex flex-wrap gap-1.5 bg-white border border-slate-200 shadow-popover\">\r\n {chipsEscondidos.map(i => chip(i))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n {itensChips.length > 0 && (\r\n <button ref={limparRef} type=\"button\" onClick={() => { clearAllFilters(); clearAllGroups() }}\r\n className={`ml-auto ${classeLimpar}`}>\r\n {L.clearAll}\r\n </button>\r\n )}\r\n </div>\r\n {/* As páginas à direita, sempre com o mesmo espaço guardado (7 números),\r\n mesmo com uma página só: senão, ao filtrar até sobrar uma página, a\r\n zona dos chips alargava e o \"Limpar\" saltava para a direita. */}\r\n <div className=\"shrink-0 min-w-[220px] flex justify-end\">\r\n {topoACarregar ? (\r\n <div className=\"shrink-0 flex items-center gap-1\" aria-hidden>\r\n {Array.from({ length: 7 }, (_, i) => (\r\n <span key={i} className=\"h-7 min-w-7 flex items-center justify-center\"><span className=\"h-2 w-3 rounded-sm bg-slate-200 animate-pulse motion-reduce:animate-none\" /></span>\r\n ))}\r\n </div>\r\n ) : totalPaginasTopo > 1 && !isGrouped && (\r\n <nav aria-label={L.pagination} className=\"shrink-0 flex items-center gap-1\">\r\n {/* \"Página 3 de 203\" só para leitores de ecrã: à vista, o número\r\n realçado e o último já o dizem. */}\r\n <span className=\"sr-only\">{L.page} {paginaTopo} / {totalPaginasTopo}</span>\r\n {numerosPagina.map((p, i) => p === '…' ? (\r\n <span key={`r${i}`} aria-hidden className=\"h-7 min-w-5 flex items-center justify-center text-slate-300\">…</span>\r\n ) : (\r\n <button\r\n key={p}\r\n type=\"button\"\r\n onClick={() => irParaPagina(p)}\r\n aria-current={p === paginaTopo ? 'page' : undefined}\r\n className={`h-7 min-w-7 px-1.5 rounded-md text-caption font-semibold tabular-nums transition-colors ${\r\n p === paginaTopo ? 'bg-primary text-white cursor-default' : 'text-slate-500 hover:bg-slate-100 hover:text-slate-800'}`}\r\n >\r\n {p}\r\n </button>\r\n ))}\r\n </nav>\r\n )}\r\n </div>\r\n </div>\r\n ) : null\r\n\r\n return (\r\n /* A coluna só existe a preencher: as barras de chips e o rodapé são irmãos\r\n da caixa de scroll, e é a coluna que lhes dá topo e fundo fixos com o\r\n scroll pelo meio. */\r\n <div ref={raizRef} className={`v1-reset text-control text-slate-800 ${preencheAltura ? 'h-full min-h-0 flex flex-col' : ''}`}>\r\n {barraTopo}\r\n {/* Agrupamentos e filtros do cabeçalho: numa faixa por cima da tabela.\r\n Com a barra de cima (PaginatedTable) vão dentro dela, ver `barraTopo`. */}\r\n {!topo && isGrouped && (\r\n <div className=\"px-4 py-2 bg-slate-50 border-b border-slate-200 flex items-center gap-1.5 flex-wrap\">{chipsGrupo}</div>\r\n )}\r\n {!topo && totalActiveFilters > 0 && (\r\n <div className=\"px-4 py-2 bg-slate-50 border-b border-slate-200 flex items-center gap-1.5 flex-wrap\">{chipsFiltro}</div>\r\n )}\r\n\r\n {/* A tabela rola dentro de uma caixa e não com a página: com 28 colunas,\r\n a barra horizontal ficava no fundo do documento e era preciso descer a\r\n página inteira para lá chegar. Assim vive no fundo da caixa, sempre à\r\n vista.\r\n A caixa não muda de tamanho com um filtro aberto: o popup vive no\r\n `<body>` (ver `ColumnFilter`), logo já não é cortado pelo overflow e a\r\n caixa não tem de crescer para o mostrar. Antes crescia, e abrir um\r\n filtro empurrava a página inteira. */}\r\n {/*\r\n O cabeçalho vive FORA da caixa que rola na vertical.\r\n\r\n Estava lá dentro, `sticky top-0`, e uma barra de scroll ocupa sempre a\r\n altura toda do que rola — logo passava por cima dos títulos das colunas.\r\n Nenhum CSS a encolhe: para ela começar debaixo do cabeçalho, o cabeçalho\r\n tem de sair da caixa.\r\n\r\n São duas tabelas, então, com as MESMAS larguras (ver `larguras`), e o\r\n `scrollLeft` de uma segue o da outra para as colunas andarem juntas na\r\n horizontal. Só no modo de página: numa tabela pequena dentro de uma\r\n caixa não há barra vertical que incomode ninguém, e lá fica a tabela\r\n inteira numa só.\r\n\r\n Com a barra sobreposta, porém, o cabeçalho volta para DENTRO da caixa,\r\n colado ao topo. Copiar o `scrollLeft` no `onScroll` chega sempre um\r\n frame atrasado — o browser rola o corpo fora da thread principal e só\r\n depois avisa — e na horizontal os títulos ficavam a arrastar atrás das\r\n colunas. Na mesma caixa rolam juntos, e a barra desenhada por cima já\r\n começa abaixo dele (`data-barra-cabecalho`): o problema era só a nativa.\r\n */}\r\n {preencheAltura ? (\r\n <>\r\n {!barraSobreposta && (\r\n <div\r\n ref={caixaCabecalhoRef}\r\n // Não rola por si: acompanha o corpo. E reserva o sítio da barra\r\n // dele, senão as colunas desencontravam-se no extremo direito.\r\n className={`overflow-x-hidden shrink-0 ${bordasSeparadas ? classeCabecalho : ''}`}\r\n style={{ paddingRight: barra }}\r\n >\r\n <table className={classeTabela} style={estiloTabela}>\r\n {grupoColunas}\r\n {cabecalho(false)}\r\n </table>\r\n </div>\r\n )}\r\n\r\n {/* `relative` para a barra sobreposta se pousar por cima da caixa. */}\r\n <div className={`relative flex-1 min-h-0 flex flex-col ${barraSobreposta && barraHorizontalFora ? 'pb-3' : ''}`}>\r\n <div\r\n ref={refCaixaCorpo}\r\n onScroll={e => {\r\n const cab = caixaCabecalhoRef.current\r\n if (cab) cab.scrollLeft = e.currentTarget.scrollLeft\r\n }}\r\n className={`overflow-auto flex-1 min-h-0 ${barraSobreposta ? 'scrollbar-none' : ''}`}\r\n style={esbaterDireita && restaDireita ? { maskImage: mascaraDireita, WebkitMaskImage: mascaraDireita } : undefined}\r\n >\r\n {/* Sem linhas, a tabela é só o cabeçalho e o aviso tem de ocupar o resto\r\n da caixa para poder ficar no MEIO dela — senão encostava-se à\r\n primeira linha, logo por baixo dos títulos das colunas. O\r\n `min-h-full` mede a parte visível (é o que uma percentagem vale\r\n dentro de um contentor com `overflow`) e o `flex-1` do aviso come o\r\n que o cabeçalho deixar.\r\n\r\n Só neste estado: com linhas não há vazio para centrar, e uma coluna\r\n flex à volta de uma tabela de 40 colunas é mexer no que já rola bem\r\n na horizontal. */}\r\n <div className={semLinhas ? 'min-h-full flex flex-col' : undefined}>\r\n {/* `w-max min-w-full`: o fundo acompanha a tabela até ao fim, não\r\n só a largura visível da caixa. */}\r\n {barraSobreposta && (\r\n <div data-barra-cabecalho className={`sticky top-0 z-20 w-max min-w-full ${bordasSeparadas ? classeCabecalho : ''}`}>\r\n <table className={classeTabela} style={estiloTabela}>\r\n {grupoColunas}\r\n {cabecalho(false)}\r\n </table>\r\n </div>\r\n )}\r\n <table ref={corpoRef} className={classeTabela} style={estiloTabela}>\r\n {grupoColunas}\r\n {corpo}\r\n </table>\r\n {aviso}\r\n </div>\r\n </div>\r\n {/* Com a horizontal fora (na faixa de baixo), as duas já não se cruzam\r\n no canto: cada uma usa o comprimento todo. */}\r\n {barraSobreposta && <OverlayScrollbar alvo={caixaCorpo} borda={0} canto={!barraHorizontalFora} />}\r\n {barraSobreposta && <OverlayScrollbar alvo={caixaCorpo} eixo=\"horizontal\" borda={0} canto={!barraHorizontalFora} naBorda={!barraHorizontalFora && barraNaBorda && temRodape} />}\r\n </div>\r\n\r\n {/* A tabela de medida do modo pelo conjunto: só existe até haver\r\n medidas, fora do ecrã e invisível. Linha i = o i-ésimo exemplar de\r\n cada coluna, com as mesmas classes das células de verdade. */}\r\n {exemplares && (\r\n <table ref={medidaRef} aria-hidden className={classeTabela}\r\n style={{ position: 'fixed', left: -100000, top: 0, visibility: 'hidden', width: 'max-content' }}>\r\n <tbody>\r\n {Array.from({ length: exemplares.n }, (_, r) => (\r\n <tr key={r}>\r\n {selectable && <td className=\"px-4 py-3 w-10\"><div className=\"w-4 h-4\" /></td>}\r\n {columns.map((col, i) => {\r\n const row = exemplares.porColuna[i]![r]\r\n return (\r\n <td key={col.key} className={`px-3 py-1.5 ${col.cellClassName ?? ''} ${recuoFim(i)}`}>\r\n {row !== undefined ? col.render(row) : null}\r\n </td>\r\n )\r\n })}\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n )}\r\n </>\r\n ) : (\r\n <div ref={setCaixaSimples} className=\"overflow-auto\" style={{ maxHeight }}>\r\n {/* Sem linhas, a tabela é só o cabeçalho e o aviso tem de ocupar o\r\n resto da caixa para poder ficar no MEIO dela — senão encostava-se à\r\n primeira linha, logo por baixo dos títulos das colunas. O\r\n `min-h-full` mede a parte visível (é o que uma percentagem vale\r\n dentro de um contentor com `overflow`) e o `flex-1` do aviso come o\r\n que o cabeçalho deixar. */}\r\n <div className={semLinhas ? 'min-h-full flex flex-col' : undefined}>\r\n <table className=\"w-full text-left\">\r\n {cabecalho(true)}\r\n {corpo}\r\n </table>\r\n {aviso}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* A contagem saiu daqui: quem a dá é a barra de cima de cada ecrã, que\r\n é onde já estava a de quem alimenta a tabela — duas contagens, uma em\r\n cada ponta e a discordar entre si, era o que baralhava. Fica a troca de\r\n páginas, e só quando há mais do que uma. */}\r\n {temRodape && (\r\n <div className=\"px-4 py-3 bg-slate-50 border-t border-slate-100 flex items-center justify-between\">\r\n <span className=\"text-micro font-black uppercase text-slate-400 tracking-wider\">\r\n {L.page} {internalPage} / {internalTotalPages}\r\n </span>\r\n <div className=\"flex items-center gap-1\">\r\n <button disabled={internalPage <= 1} onClick={() => setInternalPage(p => p - 1)}\r\n className=\"flex items-center gap-1 px-3 py-1.5 text-micro font-black uppercase tracking-widest bg-white border border-slate-200 disabled:opacity-30 hover:enabled:border-proef-blue hover:enabled:text-proef-blue transition-colors\">\r\n <ChevronLeftIcon size={12} />{L.prev}\r\n </button>\r\n <button disabled={internalPage >= internalTotalPages} onClick={() => setInternalPage(p => p + 1)}\r\n className=\"flex items-center gap-1 px-3 py-1.5 text-micro font-black uppercase tracking-widest bg-white border border-slate-200 disabled:opacity-30 hover:enabled:border-proef-blue hover:enabled:text-proef-blue transition-colors\">\r\n {L.next}<ChevronRightIcon size={12} />\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n )\r\n}\r\n\r\n/**\r\n * Tabela com ordenação, filtros por coluna, agrupamento, seleção e colunas que\r\n * se arrastam para mudar a ordem. Com o conjunto completo (`allData`) pagina-se\r\n * a si mesma, com a troca de páginas no fundo.\r\n *\r\n * Para a paginação EM CIMA, com a contagem e o tamanho de página (uma lista de\r\n * página inteira), ver o `PaginatedTable`.\r\n */\r\nexport default function Table<T>(props: TableProps<T>) {\r\n return <TableBase {...props} />\r\n}\r\n"],"names":["cabecalho","sortCol","sortDir","columnFilters","dateFilters","numFilters","Fragment","c","larguras"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const DEFAULT_TABLE_LABELS = {
|
|
2
|
+
empty: "Sem dados",
|
|
3
|
+
page: "Página",
|
|
4
|
+
pagination: "Páginas",
|
|
5
|
+
rowsNoun: (count) => count === 1 ? "linha" : "linhas",
|
|
6
|
+
of: "de",
|
|
7
|
+
perPage: (size) => `${size} por página`,
|
|
8
|
+
pageSize: "Linhas por página",
|
|
9
|
+
prev: "Anterior",
|
|
10
|
+
next: "Seguinte",
|
|
11
|
+
apply: "Aplicar",
|
|
12
|
+
cancel: "Cancelar",
|
|
13
|
+
search: "Pesquisar…",
|
|
14
|
+
noResults: "Sem resultados",
|
|
15
|
+
clearFilter: "Limpar filtro",
|
|
16
|
+
clearAll: "Limpar todos",
|
|
17
|
+
clearGroups: "Limpar agrupamentos",
|
|
18
|
+
moreChips: (count) => `Mais ${count} ${count === 1 ? "filtro" : "filtros"}`,
|
|
19
|
+
removeChip: (chip) => `Remover ${chip}`,
|
|
20
|
+
groupedBy: "Agrupado por",
|
|
21
|
+
selectAll: "Selecionar tudo",
|
|
22
|
+
selectAllFound: (count) => `Selecionar os ${count} encontrados`,
|
|
23
|
+
selectedCount: (count) => `${count} sel.`,
|
|
24
|
+
loadingOptions: "A carregar opções de todas as páginas…",
|
|
25
|
+
filterBy: (column) => `Filtrar ${column}`,
|
|
26
|
+
groupBy: (column) => `Agrupar por ${column}`,
|
|
27
|
+
ungroupBy: (column) => `Remover agrupamento por ${column}`,
|
|
28
|
+
sortAsc: "Ordenar A→Z",
|
|
29
|
+
sortDesc: "Ordenar Z→A",
|
|
30
|
+
sortDateAsc: "Ordenar antigo → recente",
|
|
31
|
+
sortDateDesc: "Ordenar recente → antigo",
|
|
32
|
+
sortNumAsc: "Ordenar menor → maior",
|
|
33
|
+
sortNumDesc: "Ordenar maior → menor",
|
|
34
|
+
dateFrom: "De",
|
|
35
|
+
dateTo: "Até",
|
|
36
|
+
min: "Mínimo",
|
|
37
|
+
max: "Máximo",
|
|
38
|
+
showList: "Lista de valores",
|
|
39
|
+
showRange: "Mín/Máx"
|
|
40
|
+
};
|
|
41
|
+
export {
|
|
42
|
+
DEFAULT_TABLE_LABELS
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.js","sources":["../../../../../../src/v1/components/tables/Table/labels.ts"],"sourcesContent":["/** Os textos da tabela e dos filtros. Por omissão em português; a app troca os que quiser (ex: noutra língua). */\r\nexport interface TableLabels {\r\n /** Sem linhas para mostrar (quando não há `emptyLabel`). */\r\n empty: string\r\n page: string\r\n /** Nome acessível da navegação entre páginas. */\r\n pagination: string\r\n /** O nome das linhas na contagem (`PaginatedTable`), ex: \"linhas\", \"ordens\". */\r\n rowsNoun: (count: number) => string\r\n /** Na contagem filtrada (`PaginatedTable`): \"1 de 120 ordens\". */\r\n of: string\r\n /** Cada opção do tamanho de página (`PaginatedTable`). */\r\n perPage: (size: number) => string\r\n /** Nome acessível da escolha do tamanho de página. */\r\n pageSize: string\r\n prev: string\r\n next: string\r\n apply: string\r\n cancel: string\r\n search: string\r\n noResults: string\r\n clearFilter: string\r\n clearAll: string\r\n clearGroups: string\r\n /** O \"+N\" dos chips que não cabem na barra (`PaginatedTable`), para leitores de ecrã. */\r\n moreChips: (count: number) => string\r\n /** O × de um chip de filtro ou agrupamento. */\r\n removeChip: (chip: string) => string\r\n /** O rótulo do chip de um agrupamento, antes do nome da coluna. */\r\n groupedBy: string\r\n selectAll: string\r\n selectAllFound: (count: number) => string\r\n /** Num chip de filtro com mais de dois valores escolhidos. */\r\n selectedCount: (count: number) => string\r\n loadingOptions: string\r\n filterBy: (column: string) => string\r\n groupBy: (column: string) => string\r\n ungroupBy: (column: string) => string\r\n sortAsc: string\r\n sortDesc: string\r\n sortDateAsc: string\r\n sortDateDesc: string\r\n sortNumAsc: string\r\n sortNumDesc: string\r\n dateFrom: string\r\n dateTo: string\r\n min: string\r\n max: string\r\n /** Numa coluna de números: passar do intervalo para a lista de valores. */\r\n showList: string\r\n /** Numa coluna de números: passar da lista de valores para o intervalo. */\r\n showRange: string\r\n}\r\n\r\nexport const DEFAULT_TABLE_LABELS: TableLabels = {\r\n empty: 'Sem dados',\r\n page: 'Página',\r\n pagination: 'Páginas',\r\n rowsNoun: (count) => (count === 1 ? 'linha' : 'linhas'),\r\n of: 'de',\r\n perPage: (size) => `${size} por página`,\r\n pageSize: 'Linhas por página',\r\n prev: 'Anterior',\r\n next: 'Seguinte',\r\n apply: 'Aplicar',\r\n cancel: 'Cancelar',\r\n search: 'Pesquisar…',\r\n noResults: 'Sem resultados',\r\n clearFilter: 'Limpar filtro',\r\n clearAll: 'Limpar todos',\r\n clearGroups: 'Limpar agrupamentos',\r\n moreChips: (count) => `Mais ${count} ${count === 1 ? 'filtro' : 'filtros'}`,\r\n removeChip: (chip) => `Remover ${chip}`,\r\n groupedBy: 'Agrupado por',\r\n selectAll: 'Selecionar tudo',\r\n selectAllFound: (count) => `Selecionar os ${count} encontrados`,\r\n selectedCount: (count) => `${count} sel.`,\r\n loadingOptions: 'A carregar opções de todas as páginas…',\r\n filterBy: (column) => `Filtrar ${column}`,\r\n groupBy: (column) => `Agrupar por ${column}`,\r\n ungroupBy: (column) => `Remover agrupamento por ${column}`,\r\n sortAsc: 'Ordenar A→Z',\r\n sortDesc: 'Ordenar Z→A',\r\n sortDateAsc: 'Ordenar antigo → recente',\r\n sortDateDesc: 'Ordenar recente → antigo',\r\n sortNumAsc: 'Ordenar menor → maior',\r\n sortNumDesc: 'Ordenar maior → menor',\r\n dateFrom: 'De',\r\n dateTo: 'Até',\r\n min: 'Mínimo',\r\n max: 'Máximo',\r\n showList: 'Lista de valores',\r\n showRange: 'Mín/Máx',\r\n}\r\n"],"names":[],"mappings":"AAsDO,MAAM,uBAAoC;AAAA,EAC/C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,UAAU,CAAC,UAAW,UAAU,IAAI,UAAU;AAAA,EAC9C,IAAI;AAAA,EACJ,SAAS,CAAC,SAAS,GAAG,IAAI;AAAA,EAC1B,UAAU;AAAA,EACV,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,aAAa;AAAA,EACb,UAAU;AAAA,EACV,aAAa;AAAA,EACb,WAAW,CAAC,UAAU,QAAQ,KAAK,IAAI,UAAU,IAAI,WAAW,SAAS;AAAA,EACzE,YAAY,CAAC,SAAS,WAAW,IAAI;AAAA,EACrC,WAAW;AAAA,EACX,WAAW;AAAA,EACX,gBAAgB,CAAC,UAAU,iBAAiB,KAAK;AAAA,EACjD,eAAe,CAAC,UAAU,GAAG,KAAK;AAAA,EAClC,gBAAgB;AAAA,EAChB,UAAU,CAAC,WAAW,WAAW,MAAM;AAAA,EACvC,SAAS,CAAC,WAAW,eAAe,MAAM;AAAA,EAC1C,WAAW,CAAC,WAAW,2BAA2B,MAAM;AAAA,EACxD,SAAS;AAAA,EACT,UAAU;AAAA,EACV,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,KAAK;AAAA,EACL,UAAU;AAAA,EACV,WAAW;AACb;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
function Svg({ size = 16, className, children, fill = "none" }) {
|
|
2
|
+
function Svg({ size = 16, className, strokeWidth = 1.8, children, fill = "none" }) {
|
|
3
3
|
return /* @__PURE__ */ jsx(
|
|
4
4
|
"svg",
|
|
5
5
|
{
|
|
@@ -8,7 +8,7 @@ function Svg({ size = 16, className, children, fill = "none" }) {
|
|
|
8
8
|
viewBox: "0 0 24 24",
|
|
9
9
|
fill,
|
|
10
10
|
stroke: fill === "none" ? "currentColor" : "none",
|
|
11
|
-
strokeWidth
|
|
11
|
+
strokeWidth,
|
|
12
12
|
strokeLinecap: "round",
|
|
13
13
|
strokeLinejoin: "round",
|
|
14
14
|
className,
|
|
@@ -63,14 +63,57 @@ function CheckIcon(props) {
|
|
|
63
63
|
function ChevronDownIcon(props) {
|
|
64
64
|
return /* @__PURE__ */ jsx(Svg, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M6 9.5l6 6 6-6" }) });
|
|
65
65
|
}
|
|
66
|
+
function ChevronUpIcon(props) {
|
|
67
|
+
return /* @__PURE__ */ jsx(Svg, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M6 14.5l6-6 6 6" }) });
|
|
68
|
+
}
|
|
69
|
+
function ChevronLeftIcon(props) {
|
|
70
|
+
return /* @__PURE__ */ jsx(Svg, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M14.5 6l-6 6 6 6" }) });
|
|
71
|
+
}
|
|
72
|
+
function ChevronRightIcon(props) {
|
|
73
|
+
return /* @__PURE__ */ jsx(Svg, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M9.5 6l6 6-6 6" }) });
|
|
74
|
+
}
|
|
75
|
+
function ChevronsUpDownIcon(props) {
|
|
76
|
+
return /* @__PURE__ */ jsx(Svg, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M7.5 9.5L12 5l4.5 4.5M7.5 14.5L12 19l4.5-4.5" }) });
|
|
77
|
+
}
|
|
78
|
+
function FilterIcon(props) {
|
|
79
|
+
return /* @__PURE__ */ jsx(Svg, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 5h16l-6.2 7.6v5.6l-3.6 1.8v-7.4z" }) });
|
|
80
|
+
}
|
|
81
|
+
function CloseIcon(props) {
|
|
82
|
+
return /* @__PURE__ */ jsx(Svg, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M6.5 6.5l11 11M17.5 6.5l-11 11" }) });
|
|
83
|
+
}
|
|
84
|
+
function LayersIcon(props) {
|
|
85
|
+
return /* @__PURE__ */ jsxs(Svg, { ...props, children: [
|
|
86
|
+
/* @__PURE__ */ jsx("path", { d: "M12 3.5l8.5 4.5-8.5 4.5L3.5 8z" }),
|
|
87
|
+
/* @__PURE__ */ jsx("path", { d: "M3.5 12l8.5 4.5 8.5-4.5M3.5 16l8.5 4.5 8.5-4.5" })
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
function ListIcon(props) {
|
|
91
|
+
return /* @__PURE__ */ jsx(Svg, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M9 6.5h11M9 12h11M9 17.5h11M4.5 6.5h.01M4.5 12h.01M4.5 17.5h.01" }) });
|
|
92
|
+
}
|
|
93
|
+
function SlidersIcon(props) {
|
|
94
|
+
return /* @__PURE__ */ jsxs(Svg, { ...props, children: [
|
|
95
|
+
/* @__PURE__ */ jsx("path", { d: "M4 7h10M18 7h2M4 17h2M10 17h10" }),
|
|
96
|
+
/* @__PURE__ */ jsx("circle", { cx: "16", cy: "7", r: "2" }),
|
|
97
|
+
/* @__PURE__ */ jsx("circle", { cx: "8", cy: "17", r: "2" })
|
|
98
|
+
] });
|
|
99
|
+
}
|
|
66
100
|
export {
|
|
67
101
|
CheckIcon,
|
|
68
102
|
ChevronDownIcon,
|
|
103
|
+
ChevronLeftIcon,
|
|
104
|
+
ChevronRightIcon,
|
|
105
|
+
ChevronUpIcon,
|
|
106
|
+
ChevronsUpDownIcon,
|
|
107
|
+
CloseIcon,
|
|
108
|
+
FilterIcon,
|
|
69
109
|
InfoIcon,
|
|
110
|
+
LayersIcon,
|
|
111
|
+
ListIcon,
|
|
70
112
|
LockIcon,
|
|
71
113
|
PrefilledIcon,
|
|
72
114
|
QrCodeIcon,
|
|
73
115
|
SearchIcon,
|
|
116
|
+
SlidersIcon,
|
|
74
117
|
SparklesIcon
|
|
75
118
|
};
|
|
76
119
|
//# sourceMappingURL=icons.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icons.js","sources":["../../../../../src/v1/foundations/icons/icons.tsx"],"sourcesContent":["import React from 'react'\r\n\r\n/**\r\n * Conjunto de ícones do V1: traço de 1,7 a 1,9 em grelha de 24, cor do texto\r\n * (`currentColor`), sem preenchimento. Decorativos por omissão (`aria-hidden`):\r\n * quem os usa dá o nome acessível ao botão ou etiqueta à volta.\r\n */\r\nexport interface IconProps {\r\n /** Lado em px. */\r\n size?: number\r\n className?: string\r\n}\r\n\r\nfunction Svg({ size = 16, className, children, fill = 'none' }: IconProps & { children: React.ReactNode; fill?: string }) {\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox=\"0 0 24 24\"\r\n fill={fill}\r\n stroke={fill === 'none' ? 'currentColor' : 'none'}\r\n strokeWidth
|
|
1
|
+
{"version":3,"file":"icons.js","sources":["../../../../../src/v1/foundations/icons/icons.tsx"],"sourcesContent":["import React from 'react'\r\n\r\n/**\r\n * Conjunto de ícones do V1: traço de 1,7 a 1,9 em grelha de 24, cor do texto\r\n * (`currentColor`), sem preenchimento. Decorativos por omissão (`aria-hidden`):\r\n * quem os usa dá o nome acessível ao botão ou etiqueta à volta.\r\n */\r\nexport interface IconProps {\r\n /** Lado em px. */\r\n size?: number\r\n className?: string\r\n /** Espessura do traço. Por omissão 1,8; mais grosso em ícones muito pequenos (ex: o visto de uma caixa). */\r\n strokeWidth?: number\r\n}\r\n\r\nfunction Svg({ size = 16, className, strokeWidth = 1.8, children, fill = 'none' }: IconProps & { children: React.ReactNode; fill?: string }) {\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox=\"0 0 24 24\"\r\n fill={fill}\r\n stroke={fill === 'none' ? 'currentColor' : 'none'}\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n aria-hidden\r\n >\r\n {children}\r\n </svg>\r\n )\r\n}\r\n\r\n/** Lido de um QR code. */\r\nexport function QrCodeIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <rect x=\"3.5\" y=\"3.5\" width=\"6.5\" height=\"6.5\" rx=\"1.3\" />\r\n <rect x=\"14\" y=\"3.5\" width=\"6.5\" height=\"6.5\" rx=\"1.3\" />\r\n <rect x=\"3.5\" y=\"14\" width=\"6.5\" height=\"6.5\" rx=\"1.3\" />\r\n <path d=\"M14 14h3.3v3.3M20.5 14v.01M14 20.5h.01M17.3 20.5h3.2v-3.2\" />\r\n </Svg>\r\n )\r\n}\r\n\r\n/** Identificado automaticamente (IA). */\r\nexport function SparklesIcon(props: IconProps) {\r\n return (\r\n <Svg {...props} fill=\"currentColor\">\r\n <path d=\"M12 2.5l1.7 4.6 4.6 1.7-4.6 1.7L12 15.1l-1.7-4.6L5.7 8.8l4.6-1.7z\" />\r\n <path d=\"M18.5 13.5l.85 2.35 2.35.85-2.35.85-.85 2.35-.85-2.35-2.35-.85 2.35-.85z\" />\r\n </Svg>\r\n )\r\n}\r\n\r\n/** Pré-preenchido a partir de outro registo (ex: linha de um extrato). */\r\nexport function PrefilledIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <rect x=\"4\" y=\"3.5\" width=\"16\" height=\"17\" rx=\"2\" />\r\n <path d=\"M7.5 8.5h9M7.5 12h9M7.5 15.5h5.5\" />\r\n </Svg>\r\n )\r\n}\r\n\r\n/** Bloqueado: o valor não se pode alterar. */\r\nexport function LockIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <rect x=\"5\" y=\"10.5\" width=\"14\" height=\"10\" rx=\"2\" />\r\n <path d=\"M8.5 10.5V7.5a3.5 3.5 0 0 1 7 0v3\" />\r\n <circle cx=\"12\" cy=\"15.5\" r=\"1.1\" fill=\"currentColor\" stroke=\"none\" />\r\n </Svg>\r\n )\r\n}\r\n\r\n/** Mais informação. */\r\nexport function InfoIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <circle cx=\"12\" cy=\"12\" r=\"9.5\" />\r\n <path d=\"M12 11v5.5\" />\r\n <circle cx=\"12\" cy=\"7.8\" r=\"1.1\" fill=\"currentColor\" stroke=\"none\" />\r\n </Svg>\r\n )\r\n}\r\n\r\nexport function SearchIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <circle cx=\"10.5\" cy=\"10.5\" r=\"6.5\" />\r\n <path d=\"M15.5 15.5L20 20\" />\r\n </Svg>\r\n )\r\n}\r\n\r\nexport function CheckIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M4.5 12.5l5 5 10-11\" />\r\n </Svg>\r\n )\r\n}\r\n\r\nexport function ChevronDownIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M6 9.5l6 6 6-6\" />\r\n </Svg>\r\n )\r\n}\r\n\r\nexport function ChevronUpIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M6 14.5l6-6 6 6\" />\r\n </Svg>\r\n )\r\n}\r\n\r\nexport function ChevronLeftIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M14.5 6l-6 6 6 6\" />\r\n </Svg>\r\n )\r\n}\r\n\r\nexport function ChevronRightIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M9.5 6l6 6-6 6\" />\r\n </Svg>\r\n )\r\n}\r\n\r\n/** Ordenável: ainda sem ordem escolhida. */\r\nexport function ChevronsUpDownIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M7.5 9.5L12 5l4.5 4.5M7.5 14.5L12 19l4.5-4.5\" />\r\n </Svg>\r\n )\r\n}\r\n\r\n/** Filtro (funil). */\r\nexport function FilterIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M4 5h16l-6.2 7.6v5.6l-3.6 1.8v-7.4z\" />\r\n </Svg>\r\n )\r\n}\r\n\r\n/** Fechar, remover (×). */\r\nexport function CloseIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M6.5 6.5l11 11M17.5 6.5l-11 11\" />\r\n </Svg>\r\n )\r\n}\r\n\r\n/** Agrupar (camadas). */\r\nexport function LayersIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M12 3.5l8.5 4.5-8.5 4.5L3.5 8z\" />\r\n <path d=\"M3.5 12l8.5 4.5 8.5-4.5M3.5 16l8.5 4.5 8.5-4.5\" />\r\n </Svg>\r\n )\r\n}\r\n\r\n/** Lista de valores. */\r\nexport function ListIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M9 6.5h11M9 12h11M9 17.5h11M4.5 6.5h.01M4.5 12h.01M4.5 17.5h.01\" />\r\n </Svg>\r\n )\r\n}\r\n\r\n/** Intervalo (mínimo e máximo). */\r\nexport function SlidersIcon(props: IconProps) {\r\n return (\r\n <Svg {...props}>\r\n <path d=\"M4 7h10M18 7h2M4 17h2M10 17h10\" />\r\n <circle cx=\"16\" cy=\"7\" r=\"2\" />\r\n <circle cx=\"8\" cy=\"17\" r=\"2\" />\r\n </Svg>\r\n )\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { CheckIcon } from "../../../foundations/icons/icons.js";
|
|
4
|
+
import { useField } from "../field.js";
|
|
5
|
+
const Checkbox = forwardRef(function Checkbox2({ invalid, className = "", id, required, ...props }, ref) {
|
|
6
|
+
const field = useField();
|
|
7
|
+
return /* @__PURE__ */ jsxs("span", { className: `relative inline-flex size-4 shrink-0 ${className}`, children: [
|
|
8
|
+
/* @__PURE__ */ jsx(
|
|
9
|
+
"input",
|
|
10
|
+
{
|
|
11
|
+
ref,
|
|
12
|
+
type: "checkbox",
|
|
13
|
+
id: id ?? field.id,
|
|
14
|
+
required: required ?? field.required,
|
|
15
|
+
"aria-invalid": invalid || void 0,
|
|
16
|
+
className: "peer absolute inset-0 m-0 size-full cursor-pointer appearance-none rounded-sm border border-border bg-card outline-none transition-[background-color,border-color,box-shadow] duration-150 checked:border-primary checked:bg-primary focus-visible:ring-3 focus-visible:ring-primary/20 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/15 disabled:cursor-not-allowed disabled:bg-muted disabled:checked:border-border disabled:checked:bg-muted",
|
|
17
|
+
...props
|
|
18
|
+
}
|
|
19
|
+
),
|
|
20
|
+
/* @__PURE__ */ jsx(
|
|
21
|
+
CheckIcon,
|
|
22
|
+
{
|
|
23
|
+
size: 12,
|
|
24
|
+
className: "pointer-events-none absolute inset-0 m-auto hidden text-primary-foreground peer-checked:block peer-disabled:text-muted-foreground"
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
] });
|
|
28
|
+
});
|
|
29
|
+
export {
|
|
30
|
+
Checkbox as default
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=Checkbox.js.map
|