@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.
Files changed (53) hide show
  1. package/dist/esm/assets/imagem-6ee08a37d9.png +0 -0
  2. package/dist/esm/assets/imagem-6fcae1b87b.png +0 -0
  3. package/dist/esm/index.js +142 -119
  4. package/dist/esm/index.js.map +1 -1
  5. package/dist/esm/legacy/components/layout/Header/Header.css +1 -1
  6. package/dist/esm/legacy/components/molecules/PhotoAvatar/PhotoAvatar.js +9 -4
  7. package/dist/esm/legacy/components/molecules/PhotoAvatar/PhotoAvatar.js.map +1 -1
  8. package/dist/esm/legacy/components/molecules/Sidebar/Sidebar.css +1 -1
  9. package/dist/esm/legacy/components/organisms/RoleGuard/RoleGuard.js +14 -3
  10. package/dist/esm/legacy/components/organisms/RoleGuard/RoleGuard.js.map +1 -1
  11. package/dist/esm/legacy/pages/Error/ErrorPage.css +1 -1
  12. package/dist/esm/legacy/pages/Loading/Loading.css +2 -2
  13. package/dist/esm/legacy/pages/NotFound/NotFound.css +1 -1
  14. package/dist/esm/v1/components/lists/ListFinder/ListFinder.js +214 -0
  15. package/dist/esm/v1/components/lists/ListFinder/ListFinder.js.map +1 -0
  16. package/dist/esm/v1/components/lists/ListFinder/labels.js +18 -0
  17. package/dist/esm/v1/components/lists/ListFinder/labels.js.map +1 -0
  18. package/dist/esm/v1/components/tables/PaginatedTable/PaginatedTable.js +50 -0
  19. package/dist/esm/v1/components/tables/PaginatedTable/PaginatedTable.js.map +1 -0
  20. package/dist/esm/v1/components/tables/Table/ColumnFilter.js +292 -0
  21. package/dist/esm/v1/components/tables/Table/ColumnFilter.js.map +1 -0
  22. package/dist/esm/v1/components/tables/Table/OverlayScrollbar.js +129 -0
  23. package/dist/esm/v1/components/tables/Table/OverlayScrollbar.js.map +1 -0
  24. package/dist/esm/v1/components/tables/Table/Table.js +1410 -0
  25. package/dist/esm/v1/components/tables/Table/Table.js.map +1 -0
  26. package/dist/esm/v1/components/tables/Table/labels.js +44 -0
  27. package/dist/esm/v1/components/tables/Table/labels.js.map +1 -0
  28. package/dist/esm/v1/foundations/icons/icons.js +45 -2
  29. package/dist/esm/v1/foundations/icons/icons.js.map +1 -1
  30. package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js +32 -0
  31. package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js.map +1 -0
  32. package/dist/esm/v1/primitives/lists/ListItem/ListCheckbox.js +28 -0
  33. package/dist/esm/v1/primitives/lists/ListItem/ListCheckbox.js.map +1 -0
  34. package/dist/esm/v1/primitives/lists/ListItem/ListItem.js +39 -0
  35. package/dist/esm/v1/primitives/lists/ListItem/ListItem.js.map +1 -0
  36. package/dist/style.components.css +1 -1
  37. package/dist/style.css +1 -1
  38. package/dist/style.layered.css +1 -1
  39. package/dist/theme.css +256 -0
  40. package/dist/types/legacy/components/molecules/PhotoAvatar/PhotoAvatar.d.ts +2 -0
  41. package/dist/types/v1/components/lists/ListFinder/ListFinder.d.ts +60 -0
  42. package/dist/types/v1/components/lists/ListFinder/labels.d.ts +24 -0
  43. package/dist/types/v1/components/tables/PaginatedTable/PaginatedTable.d.ts +41 -0
  44. package/dist/types/v1/components/tables/Table/ColumnFilter.d.ts +48 -0
  45. package/dist/types/v1/components/tables/Table/OverlayScrollbar.d.ts +34 -0
  46. package/dist/types/v1/components/tables/Table/Table.d.ts +250 -0
  47. package/dist/types/v1/components/tables/Table/labels.d.ts +54 -0
  48. package/dist/types/v1/foundations/icons/icons.d.ts +17 -0
  49. package/dist/types/v1/index.d.ts +15 -1
  50. package/dist/types/v1/primitives/forms/Checkbox/Checkbox.d.ts +18 -0
  51. package/dist/types/v1/primitives/lists/ListItem/ListCheckbox.d.ts +14 -0
  52. package/dist/types/v1/primitives/lists/ListItem/ListItem.d.ts +35 -0
  53. package/package.json +2 -2
@@ -0,0 +1,214 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { useState, useMemo, useEffect } from "react";
3
+ import { ChevronLeftIcon, SearchIcon } from "../../../foundations/icons/icons.js";
4
+ import ListItem from "../../../primitives/lists/ListItem/ListItem.js";
5
+ import { ListCheckbox } from "../../../primitives/lists/ListItem/ListCheckbox.js";
6
+ import { OverlayScrollbar } from "../../tables/Table/OverlayScrollbar.js";
7
+ import { DEFAULT_LIST_FINDER_LABELS } from "./labels.js";
8
+ const semAcentos = (s) => s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();
9
+ function numerosPagina(atual, total) {
10
+ if (total <= 5) return Array.from({ length: total }, (_, i) => i + 1);
11
+ if (atual <= 2) return [1, 2, 3, "…", total];
12
+ if (atual >= total - 1) return [1, "…", total - 2, total - 1, total];
13
+ return [1, "…", atual, "…", total];
14
+ }
15
+ function ListFinder({
16
+ items,
17
+ itemKey,
18
+ itemContent,
19
+ activeKey,
20
+ onItemClick,
21
+ selectedKeys,
22
+ onSelectionChange,
23
+ filters,
24
+ onBack,
25
+ search: pesquisaDeFora,
26
+ onSearchChange,
27
+ searchText,
28
+ total,
29
+ page,
30
+ onPageChange,
31
+ pageSize = 50,
32
+ loading = false,
33
+ labels,
34
+ className = ""
35
+ }) {
36
+ const L = { ...DEFAULT_LIST_FINDER_LABELS, ...labels };
37
+ const [pesquisaPropria, setPesquisaPropria] = useState("");
38
+ const pesquisa = pesquisaDeFora ?? pesquisaPropria;
39
+ const pesquisar = (s) => {
40
+ setPesquisaPropria(s);
41
+ onSearchChange?.(s);
42
+ };
43
+ const colar = (e) => {
44
+ const texto = e.clipboardData.getData("text");
45
+ if (!/\r?\n/.test(texto.trim())) return;
46
+ e.preventDefault();
47
+ const lista = texto.split(/\r?\n/).map((t) => t.trim()).filter(Boolean).join(", ");
48
+ const el = e.currentTarget;
49
+ pesquisar(el.value.slice(0, el.selectionStart ?? el.value.length) + lista + el.value.slice(el.selectionEnd ?? el.value.length));
50
+ };
51
+ const filtradas = useMemo(() => {
52
+ if (!searchText || !pesquisa.trim()) return items;
53
+ const termos = pesquisa.split(/[\n,;\t]+/).map((t) => semAcentos(t.trim())).filter(Boolean);
54
+ return items.filter((it) => {
55
+ const texto = semAcentos(searchText(it));
56
+ return termos.some((t) => texto.includes(t));
57
+ });
58
+ }, [items, pesquisa, searchText]);
59
+ const peloServidor = total !== void 0;
60
+ const [paginaPropria, setPaginaPropria] = useState(1);
61
+ const totalLinhas = peloServidor ? total : filtradas.length;
62
+ const totalPaginas = Math.max(1, Math.ceil(totalLinhas / pageSize));
63
+ const pagina = Math.min(peloServidor ? page ?? 1 : paginaPropria, totalPaginas);
64
+ useEffect(() => {
65
+ if (!peloServidor) setPaginaPropria(1);
66
+ }, [pesquisa, peloServidor]);
67
+ const irPara = (p) => {
68
+ if (peloServidor) onPageChange?.(p);
69
+ else setPaginaPropria(p);
70
+ };
71
+ const visiveis = peloServidor ? filtradas : filtradas.slice((pagina - 1) * pageSize, pagina * pageSize);
72
+ const [caixa, setCaixa] = useState(null);
73
+ useEffect(() => {
74
+ caixa?.scrollTo?.({ top: 0 });
75
+ }, [pagina, caixa]);
76
+ const marcadas = selectedKeys ?? /* @__PURE__ */ new Set();
77
+ const marcaveis = !!onSelectionChange;
78
+ const nMarcadasVisiveis = visiveis.filter((it) => marcadas.has(itemKey(it))).length;
79
+ const todasMarcadas = visiveis.length > 0 && nMarcadasVisiveis === visiveis.length;
80
+ const marcar = (key, sim) => {
81
+ const n = new Set(marcadas);
82
+ if (sim) n.add(key);
83
+ else n.delete(key);
84
+ onSelectionChange?.(n);
85
+ };
86
+ const marcarVisiveis = () => {
87
+ const n = new Set(marcadas);
88
+ for (const it of visiveis) {
89
+ if (todasMarcadas) n.delete(itemKey(it));
90
+ else n.add(itemKey(it));
91
+ }
92
+ onSelectionChange?.(n);
93
+ };
94
+ const aCarregar = loading && visiveis.length === 0;
95
+ const esqueleto = /* @__PURE__ */ jsx("span", { className: "inline-block h-2 w-20 rounded-sm bg-slate-200 animate-pulse motion-reduce:animate-none", "aria-hidden": true });
96
+ return /* @__PURE__ */ jsxs("div", { className: `v1-reset flex h-full min-h-0 flex-col border border-slate-200 bg-white text-control text-slate-800 ${className}`, children: [
97
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 border-b border-slate-100 px-3 py-2.5", children: [
98
+ (onBack || filters) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
99
+ onBack && /* @__PURE__ */ jsx(
100
+ "button",
101
+ {
102
+ type: "button",
103
+ onClick: onBack,
104
+ "aria-label": L.back,
105
+ title: L.back,
106
+ className: "-ml-1 flex h-7 w-6 shrink-0 items-center justify-center rounded text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700",
107
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, { size: 14 })
108
+ }
109
+ ),
110
+ /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center gap-1.5", children: filters })
111
+ ] }),
112
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
113
+ /* @__PURE__ */ jsx(SearchIcon, { size: 13, className: "pointer-events-none absolute top-1/2 left-2.5 -translate-y-1/2 text-slate-400" }),
114
+ /* @__PURE__ */ jsx(
115
+ "input",
116
+ {
117
+ type: "search",
118
+ value: pesquisa,
119
+ onChange: (e) => pesquisar(e.target.value),
120
+ onPaste: colar,
121
+ placeholder: L.searchPlaceholder,
122
+ "aria-label": L.search,
123
+ className: "block h-control w-full min-w-0 rounded-lg border border-border bg-card pr-2.5 pl-8 text-control text-foreground outline-none transition-[border-color,box-shadow] duration-150 placeholder:text-muted-foreground/70 focus:border-primary/40 focus:ring-3 focus:ring-primary/10"
124
+ }
125
+ )
126
+ ] })
127
+ ] }),
128
+ marcaveis && visiveis.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 border-b border-slate-100 bg-slate-50 px-3 py-1.5 text-caption text-slate-500", children: [
129
+ /* @__PURE__ */ jsx(
130
+ ListCheckbox,
131
+ {
132
+ checked: todasMarcadas,
133
+ indeterminate: nMarcadasVisiveis > 0,
134
+ onChange: marcarVisiveis,
135
+ label: L.selectVisible(visiveis.length)
136
+ }
137
+ ),
138
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: nMarcadasVisiveis > 0 ? L.selectedCount(nMarcadasVisiveis, visiveis.length) : L.selectVisible(visiveis.length) }),
139
+ marcadas.size > 0 && /* @__PURE__ */ jsx(
140
+ "button",
141
+ {
142
+ type: "button",
143
+ onClick: () => onSelectionChange?.(/* @__PURE__ */ new Set()),
144
+ className: "ml-auto font-medium text-proef-blue hover:underline",
145
+ children: L.clearSelection
146
+ }
147
+ )
148
+ ] }),
149
+ /* @__PURE__ */ jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [
150
+ /* @__PURE__ */ jsx("div", { ref: setCaixa, className: "min-h-0 flex-1 overflow-y-auto scrollbar-none", children: aCarregar ? (
151
+ // A forma das linhas já diz que vem ali a lista. Mais do que cabem,
152
+ // cortadas pela caixa: chega ao fundo em qualquer altura.
153
+ /* @__PURE__ */ jsxs("div", { role: "status", "aria-busy": "true", className: "h-full overflow-hidden", children: [
154
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: L.loading }),
155
+ ["w-11/12", "w-3/4", "w-5/6", "w-2/3", "w-4/5", "w-7/12"].flatMap((l) => [l, l, l, l]).map((largura, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2.5 border-b border-slate-100 px-3 py-2.5 animate-pulse motion-reduce:animate-none", children: [
156
+ marcaveis && /* @__PURE__ */ jsx("div", { className: "mt-0.5 h-4 w-4 shrink-0 border border-slate-200 bg-slate-100" }),
157
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1.5", children: [
158
+ /* @__PURE__ */ jsx("div", { className: "h-3 w-12 bg-slate-200" }),
159
+ /* @__PURE__ */ jsx("div", { className: "h-1.5 w-16 bg-slate-100" }),
160
+ /* @__PURE__ */ jsx("div", { className: `h-2.5 ${largura} bg-slate-200` }),
161
+ /* @__PURE__ */ jsx("div", { className: "h-1.5 w-1/3 bg-slate-100" })
162
+ ] })
163
+ ] }, i))
164
+ ] })
165
+ ) : visiveis.length === 0 ? /* @__PURE__ */ jsx("p", { className: "m-0 px-3 py-6 text-center text-caption text-slate-400", children: L.empty }) : /* @__PURE__ */ jsx("ul", { className: "m-0 list-none p-0", children: visiveis.map((it) => {
166
+ const key = itemKey(it);
167
+ return /* @__PURE__ */ jsx(
168
+ ListItem,
169
+ {
170
+ ...itemContent(it),
171
+ active: activeKey === key,
172
+ onClick: onItemClick ? () => onItemClick(it) : void 0,
173
+ checked: marcadas.has(key),
174
+ onCheckedChange: marcaveis ? (sim) => marcar(key, sim) : void 0,
175
+ checkboxLabel: L.checkItem(key)
176
+ },
177
+ key
178
+ );
179
+ }) }) }),
180
+ /* @__PURE__ */ jsx(OverlayScrollbar, { alvo: caixa, borda: 0 })
181
+ ] }),
182
+ /* @__PURE__ */ jsxs("div", { className: "flex h-11 shrink-0 items-center justify-between gap-2 border-t border-slate-100 bg-slate-50 px-3 text-caption text-slate-500", children: [
183
+ /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: aCarregar ? esqueleto : /* @__PURE__ */ jsxs(Fragment, { children: [
184
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-slate-800 tabular-nums", children: totalLinhas.toLocaleString("pt-PT") }),
185
+ " ",
186
+ L.itemsNoun(totalLinhas)
187
+ ] }) }),
188
+ !aCarregar && totalPaginas > 1 && /* @__PURE__ */ jsxs("nav", { "aria-label": L.pagination, className: "flex items-center gap-0.5", children: [
189
+ /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
190
+ L.page,
191
+ " ",
192
+ pagina,
193
+ " / ",
194
+ totalPaginas
195
+ ] }),
196
+ numerosPagina(pagina, totalPaginas).map((p, i) => p === "…" ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "flex h-7 min-w-4 items-center justify-center text-slate-300", children: "…" }, `r${i}`) : /* @__PURE__ */ jsx(
197
+ "button",
198
+ {
199
+ type: "button",
200
+ onClick: () => irPara(p),
201
+ "aria-current": p === pagina ? "page" : void 0,
202
+ className: `h-7 min-w-7 rounded-md px-1.5 font-semibold tabular-nums transition-colors ${p === pagina ? "cursor-default bg-primary text-white" : "text-slate-500 hover:bg-slate-200/70 hover:text-slate-800"}`,
203
+ children: p.toLocaleString("pt-PT")
204
+ },
205
+ p
206
+ ))
207
+ ] })
208
+ ] })
209
+ ] });
210
+ }
211
+ export {
212
+ ListFinder as default
213
+ };
214
+ //# sourceMappingURL=ListFinder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListFinder.js","sources":["../../../../../../src/v1/components/lists/ListFinder/ListFinder.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useState } from 'react'\r\nimport { ChevronLeftIcon, SearchIcon } from '../../../foundations/icons/icons'\r\nimport ListItem, { type ListItemContent } from '../../../primitives/lists/ListItem/ListItem'\r\nimport { ListCheckbox } from '../../../primitives/lists/ListItem/ListCheckbox'\r\nimport { OverlayScrollbar } from '../../tables/Table/OverlayScrollbar'\r\nimport { DEFAULT_LIST_FINDER_LABELS, type ListFinderLabels } from './labels'\r\n\r\nexport interface ListFinderProps<T> {\r\n /** As linhas: todas, ou só a página atual quando o servidor pagina (com `total`). */\r\n items: T[]\r\n /** Uma chave única por linha (ex: o id). */\r\n itemKey: (item: T) => string\r\n /** O que cada linha mostra: as partes do [ListItem](?path=/docs/v1-primitives-lists-listitem--docs). */\r\n itemContent: (item: T) => ListItemContent\r\n /** A linha aberta (fica realçada). */\r\n activeKey?: string | null\r\n /** Ao clicar numa linha: normalmente, abri-la ao lado. */\r\n onItemClick?: (item: T) => void\r\n /** As marcadas. Só há caixas de marcar com `onSelectionChange`. */\r\n selectedKeys?: ReadonlySet<string>\r\n onSelectionChange?: (keys: Set<string>) => void\r\n /** Filtros ao lado do voltar, por cima da pesquisa (ex: um ou dois SelectInput). */\r\n filters?: React.ReactNode\r\n /** Com isto aparece um ‹ à esquerda, para fechar ou esconder a lista. */\r\n onBack?: () => void\r\n /** O texto da pesquisa. Sem ele, a pesquisa guarda o seu. */\r\n search?: string\r\n onSearchChange?: (search: string) => void\r\n /**\r\n * O texto onde a pesquisa procura, em cada linha. Com isto, a lista filtra-se\r\n * sozinha (sem acentos nem maiúsculas); sem isto, quem filtra é a app (ex: o\r\n * servidor, com `onSearchChange`). Uma lista colada (uma por linha, ou\r\n * separadas por vírgulas) mostra as que tiverem qualquer uma delas.\r\n */\r\n searchText?: (item: T) => string\r\n /** O servidor pagina: quantas linhas há lá ao todo. `items` é só a página atual. */\r\n total?: number\r\n /** A página atual (1, 2, ...), quando o servidor pagina. */\r\n page?: number\r\n onPageChange?: (page: number) => void\r\n /** Quantas linhas por página. Com o servidor a paginar, quantas ele manda. */\r\n pageSize?: number\r\n /** A carregar: sem linhas ainda, mostra o esqueleto delas. */\r\n loading?: boolean\r\n labels?: Partial<ListFinderLabels>\r\n className?: string\r\n}\r\n\r\nconst semAcentos = (s: string) => s.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase()\r\n\r\n/** Os números das páginas numa coluna estreita: no máximo cinco lugares. */\r\nfunction numerosPagina(atual: number, total: number): (number | '…')[] {\r\n if (total <= 5) return Array.from({ length: total }, (_, i) => i + 1)\r\n if (atual <= 2) return [1, 2, 3, '…', total]\r\n if (atual >= total - 1) return [1, '…', total - 2, total - 1, total]\r\n return [1, '…', atual, '…', total]\r\n}\r\n\r\n/**\r\n * Uma lista para encontrar e escolher: filtros e pesquisa em cima, as linhas\r\n * ([ListItem](?path=/docs/v1-primitives-lists-listitem--docs)) a rolar no meio e\r\n * as páginas em baixo. Pensada para a coluna ao lado do que se abre (a lista à\r\n * esquerda, o detalhe da linha escolhida à direita).\r\n *\r\n * Enche a altura do pai. O topo, a barra de \"selecionar todos\" e o rodapé\r\n * ficam sempre no sítio: só as linhas rolam.\r\n *\r\n * - **Pesquisa**: com `searchText` filtra sozinha; sem ele, a app filtra\r\n * (`search`/`onSearchChange`).\r\n * - **Páginas**: pagina sozinha (`pageSize`), ou é o servidor (`total`, `page`,\r\n * `onPageChange`).\r\n * - **Marcar vários**: com `onSelectionChange`. O \"selecionar todos\" só marca\r\n * as linhas à vista, nunca as que não se veem.\r\n */\r\nexport default function ListFinder<T>({\r\n items, itemKey, itemContent, activeKey, onItemClick, selectedKeys, onSelectionChange, filters, onBack,\r\n search: pesquisaDeFora, onSearchChange, searchText, total, page, onPageChange, pageSize = 50, loading = false,\r\n labels, className = '',\r\n}: ListFinderProps<T>) {\r\n const L = { ...DEFAULT_LIST_FINDER_LABELS, ...labels }\r\n const [pesquisaPropria, setPesquisaPropria] = useState('')\r\n const pesquisa = pesquisaDeFora ?? pesquisaPropria\r\n const pesquisar = (s: string) => { setPesquisaPropria(s); onSearchChange?.(s) }\r\n // Uma caixa de uma linha deita fora as quebras de linha: uma coluna colada\r\n // de uma folha de cálculo chegava como um número só, colado. Passam a vírgulas.\r\n const colar = (e: React.ClipboardEvent<HTMLInputElement>) => {\r\n const texto = e.clipboardData.getData('text')\r\n if (!/\\r?\\n/.test(texto.trim())) return\r\n e.preventDefault()\r\n const lista = texto.split(/\\r?\\n/).map(t => t.trim()).filter(Boolean).join(', ')\r\n const el = e.currentTarget\r\n pesquisar(el.value.slice(0, el.selectionStart ?? el.value.length) + lista + el.value.slice(el.selectionEnd ?? el.value.length))\r\n }\r\n\r\n const filtradas = useMemo(() => {\r\n if (!searchText || !pesquisa.trim()) return items\r\n const termos = pesquisa.split(/[\\n,;\\t]+/).map(t => semAcentos(t.trim())).filter(Boolean)\r\n return items.filter(it => {\r\n const texto = semAcentos(searchText(it))\r\n return termos.some(t => texto.includes(t))\r\n })\r\n }, [items, pesquisa, searchText])\r\n\r\n // Paginação: do servidor (com `total`), ou feita aqui.\r\n const peloServidor = total !== undefined\r\n const [paginaPropria, setPaginaPropria] = useState(1)\r\n const totalLinhas = peloServidor ? total : filtradas.length\r\n const totalPaginas = Math.max(1, Math.ceil(totalLinhas / pageSize))\r\n const pagina = Math.min(peloServidor ? (page ?? 1) : paginaPropria, totalPaginas)\r\n // Uma pesquisa nova volta à primeira página: a terceira de antes já não é a mesma lista.\r\n useEffect(() => { if (!peloServidor) setPaginaPropria(1) }, [pesquisa, peloServidor])\r\n const irPara = (p: number) => { if (peloServidor) onPageChange?.(p); else setPaginaPropria(p) }\r\n const visiveis = peloServidor ? filtradas : filtradas.slice((pagina - 1) * pageSize, pagina * pageSize)\r\n\r\n // Ao mudar de página, a lista volta ao topo.\r\n const [caixa, setCaixa] = useState<HTMLDivElement | null>(null)\r\n useEffect(() => { caixa?.scrollTo?.({ top: 0 }) }, [pagina, caixa])\r\n\r\n const marcadas = selectedKeys ?? new Set<string>()\r\n const marcaveis = !!onSelectionChange\r\n const nMarcadasVisiveis = visiveis.filter(it => marcadas.has(itemKey(it))).length\r\n const todasMarcadas = visiveis.length > 0 && nMarcadasVisiveis === visiveis.length\r\n const marcar = (key: string, sim: boolean) => {\r\n const n = new Set(marcadas)\r\n if (sim) n.add(key); else n.delete(key)\r\n onSelectionChange?.(n)\r\n }\r\n const marcarVisiveis = () => {\r\n const n = new Set(marcadas)\r\n for (const it of visiveis) { if (todasMarcadas) n.delete(itemKey(it)); else n.add(itemKey(it)) }\r\n onSelectionChange?.(n)\r\n }\r\n\r\n const aCarregar = loading && visiveis.length === 0\r\n const esqueleto = <span className=\"inline-block h-2 w-20 rounded-sm bg-slate-200 animate-pulse motion-reduce:animate-none\" aria-hidden />\r\n\r\n return (\r\n <div className={`v1-reset flex h-full min-h-0 flex-col border border-slate-200 bg-white text-control text-slate-800 ${className}`}>\r\n <div className=\"space-y-2 border-b border-slate-100 px-3 py-2.5\">\r\n {(onBack || filters) && (\r\n <div className=\"flex items-center gap-1.5\">\r\n {onBack && (\r\n <button type=\"button\" onClick={onBack} aria-label={L.back} title={L.back}\r\n className=\"-ml-1 flex h-7 w-6 shrink-0 items-center justify-center rounded text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700\">\r\n <ChevronLeftIcon size={14} />\r\n </button>\r\n )}\r\n <div className=\"flex min-w-0 flex-1 items-center gap-1.5\">{filters}</div>\r\n </div>\r\n )}\r\n <div className=\"relative\">\r\n <SearchIcon size={13} className=\"pointer-events-none absolute top-1/2 left-2.5 -translate-y-1/2 text-slate-400\" />\r\n <input\r\n type=\"search\"\r\n value={pesquisa}\r\n onChange={e => pesquisar(e.target.value)}\r\n onPaste={colar}\r\n placeholder={L.searchPlaceholder}\r\n aria-label={L.search}\r\n className=\"block h-control w-full min-w-0 rounded-lg border border-border bg-card pr-2.5 pl-8 text-control text-foreground outline-none transition-[border-color,box-shadow] duration-150 placeholder:text-muted-foreground/70 focus:border-primary/40 focus:ring-3 focus:ring-primary/10\"\r\n />\r\n </div>\r\n </div>\r\n\r\n {/* Fora da área que rola: é a cabeça da lista, e é a descer a lista que\r\n se decide marcá-la toda. */}\r\n {marcaveis && visiveis.length > 0 && (\r\n <div className=\"flex items-center gap-2.5 border-b border-slate-100 bg-slate-50 px-3 py-1.5 text-caption text-slate-500\">\r\n <ListCheckbox\r\n checked={todasMarcadas}\r\n indeterminate={nMarcadasVisiveis > 0}\r\n onChange={marcarVisiveis}\r\n label={L.selectVisible(visiveis.length)}\r\n />\r\n <span aria-hidden>{nMarcadasVisiveis > 0 ? L.selectedCount(nMarcadasVisiveis, visiveis.length) : L.selectVisible(visiveis.length)}</span>\r\n {marcadas.size > 0 && (\r\n <button type=\"button\" onClick={() => onSelectionChange?.(new Set())}\r\n className=\"ml-auto font-medium text-proef-blue hover:underline\">\r\n {L.clearSelection}\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className=\"relative flex min-h-0 flex-1 flex-col\">\r\n <div ref={setCaixa} className=\"min-h-0 flex-1 overflow-y-auto scrollbar-none\">\r\n {aCarregar ? (\r\n // A forma das linhas já diz que vem ali a lista. Mais do que cabem,\r\n // cortadas pela caixa: chega ao fundo em qualquer altura.\r\n <div role=\"status\" aria-busy=\"true\" className=\"h-full overflow-hidden\">\r\n <span className=\"sr-only\">{L.loading}</span>\r\n {['w-11/12', 'w-3/4', 'w-5/6', 'w-2/3', 'w-4/5', 'w-7/12'].flatMap(l => [l, l, l, l]).map((largura, i) => (\r\n <div key={i} className=\"flex items-start gap-2.5 border-b border-slate-100 px-3 py-2.5 animate-pulse motion-reduce:animate-none\">\r\n {marcaveis && <div className=\"mt-0.5 h-4 w-4 shrink-0 border border-slate-200 bg-slate-100\" />}\r\n <div className=\"min-w-0 flex-1 space-y-1.5\">\r\n <div className=\"h-3 w-12 bg-slate-200\" />\r\n <div className=\"h-1.5 w-16 bg-slate-100\" />\r\n <div className={`h-2.5 ${largura} bg-slate-200`} />\r\n <div className=\"h-1.5 w-1/3 bg-slate-100\" />\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n ) : visiveis.length === 0 ? (\r\n <p className=\"m-0 px-3 py-6 text-center text-caption text-slate-400\">{L.empty}</p>\r\n ) : (\r\n <ul className=\"m-0 list-none p-0\">\r\n {visiveis.map(it => {\r\n const key = itemKey(it)\r\n return (\r\n <ListItem\r\n key={key}\r\n {...itemContent(it)}\r\n active={activeKey === key}\r\n onClick={onItemClick ? () => onItemClick(it) : undefined}\r\n checked={marcadas.has(key)}\r\n onCheckedChange={marcaveis ? sim => marcar(key, sim) : undefined}\r\n checkboxLabel={L.checkItem(key)}\r\n />\r\n )\r\n })}\r\n </ul>\r\n )}\r\n </div>\r\n <OverlayScrollbar alvo={caixa} borda={0} />\r\n </div>\r\n\r\n {/* Sempre à vista e com a mesma altura, carregada ou não: aparecer do\r\n nada fazia saltar o fundo do painel. */}\r\n <div className=\"flex h-11 shrink-0 items-center justify-between gap-2 border-t border-slate-100 bg-slate-50 px-3 text-caption text-slate-500\">\r\n <span className=\"whitespace-nowrap\">\r\n {aCarregar ? esqueleto : <><span className=\"font-semibold text-slate-800 tabular-nums\">{totalLinhas.toLocaleString('pt-PT')}</span> {L.itemsNoun(totalLinhas)}</>}\r\n </span>\r\n {!aCarregar && totalPaginas > 1 && (\r\n <nav aria-label={L.pagination} className=\"flex items-center gap-0.5\">\r\n <span className=\"sr-only\">{L.page} {pagina} / {totalPaginas}</span>\r\n {numerosPagina(pagina, totalPaginas).map((p, i) => p === '…' ? (\r\n <span key={`r${i}`} aria-hidden className=\"flex h-7 min-w-4 items-center justify-center text-slate-300\">…</span>\r\n ) : (\r\n <button\r\n key={p}\r\n type=\"button\"\r\n onClick={() => irPara(p)}\r\n aria-current={p === pagina ? 'page' : undefined}\r\n className={`h-7 min-w-7 rounded-md px-1.5 font-semibold tabular-nums transition-colors ${\r\n p === pagina ? 'cursor-default bg-primary text-white' : 'text-slate-500 hover:bg-slate-200/70 hover:text-slate-800'}`}\r\n >\r\n {p.toLocaleString('pt-PT')}\r\n </button>\r\n ))}\r\n </nav>\r\n )}\r\n </div>\r\n </div>\r\n )\r\n}\r\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ const DEFAULT_LIST_FINDER_LABELS = {
2
+ searchPlaceholder: "Pesquisar",
3
+ search: "Pesquisar",
4
+ back: "Fechar a lista",
5
+ itemsNoun: (count) => count === 1 ? "item" : "itens",
6
+ selectVisible: (count) => `Selecionar ${count === 1 ? "o" : `os ${count}`} à vista`,
7
+ selectedCount: (selected, visible) => `${selected} de ${visible} marcados`,
8
+ clearSelection: "Limpar",
9
+ checkItem: (key) => `Marcar ${key}`,
10
+ empty: "Sem resultados",
11
+ loading: "A carregar",
12
+ pagination: "Páginas",
13
+ page: "Página"
14
+ };
15
+ export {
16
+ DEFAULT_LIST_FINDER_LABELS
17
+ };
18
+ //# sourceMappingURL=labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.js","sources":["../../../../../../src/v1/components/lists/ListFinder/labels.ts"],"sourcesContent":["/** Os textos do ListFinder. A app troca os que quiser pela prop `labels`. */\r\nexport interface ListFinderLabels {\r\n /** Dentro da caixa de pesquisa. */\r\n searchPlaceholder: string\r\n /** O nome da caixa de pesquisa, para leitores de ecrã. */\r\n search: string\r\n /** O botão de voltar (só com `onBack`). */\r\n back: string\r\n /** O nome do que a lista tem, no singular ou plural (ex: \"1 ordem\", \"20 ordens\"). */\r\n itemsNoun: (count: number) => string\r\n /** A caixa de cima, sem nenhuma marcada. */\r\n selectVisible: (count: number) => string\r\n /** A caixa de cima, com algumas marcadas. */\r\n selectedCount: (selected: number, visible: number) => string\r\n clearSelection: string\r\n /** A caixa de marcar de cada linha (ex: \"Marcar P-020000\"). */\r\n checkItem: (key: string) => string\r\n /** Sem nada para mostrar. */\r\n empty: string\r\n loading: string\r\n pagination: string\r\n page: string\r\n}\r\n\r\nexport const DEFAULT_LIST_FINDER_LABELS: ListFinderLabels = {\r\n searchPlaceholder: 'Pesquisar',\r\n search: 'Pesquisar',\r\n back: 'Fechar a lista',\r\n itemsNoun: (count) => (count === 1 ? 'item' : 'itens'),\r\n selectVisible: (count) => `Selecionar ${count === 1 ? 'o' : `os ${count}`} à vista`,\r\n selectedCount: (selected, visible) => `${selected} de ${visible} marcados`,\r\n clearSelection: 'Limpar',\r\n checkItem: (key) => `Marcar ${key}`,\r\n empty: 'Sem resultados',\r\n loading: 'A carregar',\r\n pagination: 'Páginas',\r\n page: 'Página',\r\n}\r\n"],"names":[],"mappings":"AAwBO,MAAM,6BAA+C;AAAA,EAC1D,mBAAmB;AAAA,EACnB,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,WAAW,CAAC,UAAW,UAAU,IAAI,SAAS;AAAA,EAC9C,eAAe,CAAC,UAAU,cAAc,UAAU,IAAI,MAAM,MAAM,KAAK,EAAE;AAAA,EACzE,eAAe,CAAC,UAAU,YAAY,GAAG,QAAQ,OAAO,OAAO;AAAA,EAC/D,gBAAgB;AAAA,EAChB,WAAW,CAAC,QAAQ,UAAU,GAAG;AAAA,EACjC,OAAO;AAAA,EACP,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,MAAM;AACR;"}
@@ -0,0 +1,50 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { TableBase } from "../Table/Table.js";
4
+ function PaginatedTable({
5
+ total,
6
+ page,
7
+ onPageChange,
8
+ pageSizeOptions,
9
+ onPageSizeChange,
10
+ pageSize,
11
+ data,
12
+ allData,
13
+ alwaysClient,
14
+ fillHeight = true,
15
+ overlayScrollbars = true,
16
+ horizontalScrollbarBelow = true,
17
+ skeleton = true,
18
+ fadeRight = true,
19
+ ...resto
20
+ }) {
21
+ const [tamanhoProprio, setTamanhoProprio] = useState(pageSize ?? pageSizeOptions?.[0] ?? 50);
22
+ const tamanho = onPageSizeChange ? pageSize ?? pageSizeOptions?.[0] ?? 50 : tamanhoProprio;
23
+ const peloServidor = !!onPageChange && page !== void 0;
24
+ return /* @__PURE__ */ jsx(
25
+ TableBase,
26
+ {
27
+ ...resto,
28
+ data,
29
+ allData: peloServidor ? allData : allData ?? data,
30
+ alwaysClient: peloServidor ? alwaysClient : true,
31
+ pageSize: tamanho,
32
+ fillHeight,
33
+ overlayScrollbars,
34
+ horizontalScrollbarBelow,
35
+ skeleton,
36
+ fadeRight,
37
+ paginacaoNoTopo: {
38
+ total,
39
+ page,
40
+ onPageChange,
41
+ pageSizeOptions,
42
+ onPageSizeChange: onPageSizeChange ?? (pageSizeOptions ? setTamanhoProprio : void 0)
43
+ }
44
+ }
45
+ );
46
+ }
47
+ export {
48
+ PaginatedTable as default
49
+ };
50
+ //# sourceMappingURL=PaginatedTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaginatedTable.js","sources":["../../../../../../src/v1/components/tables/PaginatedTable/PaginatedTable.tsx"],"sourcesContent":["import React, { useState } from 'react'\r\nimport { TableBase, type TableProps } from '../Table/Table'\r\n\r\nexport interface PaginatedTableProps<T> extends TableProps<T> {\r\n /**\r\n * Total de linhas no servidor, quando é ele que pagina (`page` e\r\n * `onPageChange`). É o número da contagem e dá o número de páginas.\r\n */\r\n total?: number\r\n /**\r\n * Página atual (a contar de 1), quando é o servidor que pagina: a app pede a\r\n * página e dá-a em `data`. Sem isto, a tabela pagina-se a si mesma com todas\r\n * as linhas de `data`.\r\n */\r\n page?: number\r\n onPageChange?: (page: number) => void\r\n /** Tamanhos de página à escolha (ex: `[60, 120, 250, 500]`). Sem isto não há escolha. */\r\n pageSizeOptions?: number[]\r\n /**\r\n * A pessoa escolheu outro tamanho de página. Quando é o servidor que pagina,\r\n * a app volta à página 1 (ficar na 7.ª com 500 por página caía fora da lista).\r\n * Sem isto, a tabela guarda a escolha ela própria.\r\n */\r\n onPageSizeChange?: (pageSize: number) => void\r\n}\r\n\r\n/**\r\n * A `Table` para listas de página inteira: a paginação fica EM CIMA, numa\r\n * barra com a contagem de linhas, o tamanho de página e os números de página,\r\n * em vez de no fundo.\r\n *\r\n * Funciona de duas maneiras:\r\n * - **O servidor pagina** (`page`, `onPageChange`, `total`): `data` é a\r\n * página atual. Com filtros, ordenação ou agrupamento no cabeçalho, a tabela\r\n * passa a paginar o conjunto completo (`allData`) e a barra mostra as\r\n * páginas dela.\r\n * - **Todas as linhas de uma vez** (só `data`): a tabela pagina-se a si mesma.\r\n *\r\n * Por omissão ocupa a altura do pai (`fillHeight`), com as barras de scroll\r\n * por cima das linhas, linhas-esqueleto a carregar e a aresta direita\r\n * esbatida. Qualquer uma pode ser desligada.\r\n */\r\nexport default function PaginatedTable<T>({\r\n total,\r\n page,\r\n onPageChange,\r\n pageSizeOptions,\r\n onPageSizeChange,\r\n pageSize,\r\n data,\r\n allData,\r\n alwaysClient,\r\n fillHeight = true,\r\n overlayScrollbars = true,\r\n horizontalScrollbarBelow = true,\r\n skeleton = true,\r\n fadeRight = true,\r\n ...resto\r\n}: PaginatedTableProps<T>) {\r\n const [tamanhoProprio, setTamanhoProprio] = useState(pageSize ?? pageSizeOptions?.[0] ?? 50)\r\n const tamanho = onPageSizeChange ? (pageSize ?? pageSizeOptions?.[0] ?? 50) : tamanhoProprio\r\n // Sem paginação do servidor, todas as linhas são o conjunto completo e a tabela pagina-as.\r\n const peloServidor = !!onPageChange && page !== undefined\r\n return (\r\n <TableBase\r\n {...resto}\r\n data={data}\r\n allData={peloServidor ? allData : (allData ?? data)}\r\n alwaysClient={peloServidor ? alwaysClient : true}\r\n pageSize={tamanho}\r\n fillHeight={fillHeight}\r\n overlayScrollbars={overlayScrollbars}\r\n horizontalScrollbarBelow={horizontalScrollbarBelow}\r\n skeleton={skeleton}\r\n fadeRight={fadeRight}\r\n paginacaoNoTopo={{\r\n total,\r\n page,\r\n onPageChange,\r\n pageSizeOptions,\r\n onPageSizeChange: onPageSizeChange ?? (pageSizeOptions ? setTamanhoProprio : undefined),\r\n }}\r\n />\r\n )\r\n}\r\n"],"names":[],"mappings":";;;AA0CA,SAAwB,eAAkB;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,2BAA2B;AAAA,EAC3B,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,GAAG;AACL,GAA2B;AACzB,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,YAAY,kBAAkB,CAAC,KAAK,EAAE;AAC3F,QAAM,UAAU,mBAAoB,YAAY,kBAAkB,CAAC,KAAK,KAAM;AAE9E,QAAM,eAAe,CAAC,CAAC,gBAAgB,SAAS;AAChD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,SAAS,eAAe,UAAW,WAAW;AAAA,MAC9C,cAAc,eAAe,eAAe;AAAA,MAC5C,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,kBAAkB,qBAAqB,kBAAkB,oBAAoB;AAAA,MAAA;AAAA,IAC/E;AAAA,EAAA;AAGN;"}
@@ -0,0 +1,292 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { useRef, useId, useState, useMemo, useEffect } from "react";
3
+ import { createPortal } from "react-dom";
4
+ import { SlidersIcon, ListIcon, ChevronUpIcon, ChevronDownIcon, CheckIcon } from "../../../foundations/icons/icons.js";
5
+ const ALTURA = 420;
6
+ const LARGURA = 320;
7
+ function ColumnFilter({
8
+ labels: L,
9
+ label,
10
+ canSort,
11
+ tipo,
12
+ valores,
13
+ seleccionados,
14
+ intervalo,
15
+ numero,
16
+ ordenadaPor,
17
+ aCarregar,
18
+ ancora,
19
+ onOrdenar,
20
+ onAplicar,
21
+ onAplicarDatas,
22
+ onAplicarNumeros,
23
+ onLimpar,
24
+ onFechar
25
+ }) {
26
+ const caixa = useRef(null);
27
+ const idMin = useId();
28
+ const [busca, setBusca] = useState("");
29
+ const [rascunho, setRascunho] = useState(() => new Set(seleccionados));
30
+ const [de, setDe] = useState(intervalo.from ?? "");
31
+ const [ate, setAte] = useState(intervalo.to ?? "");
32
+ const [min, setMin] = useState(numero?.min ?? "");
33
+ const [max, setMax] = useState(numero?.max ?? "");
34
+ const [modoLista, setModoLista] = useState(tipo === "numero" && !numero?.min && !numero?.max);
35
+ const lista = tipo === "texto" || tipo === "numero" && modoLista;
36
+ const visiveis = useMemo(() => {
37
+ const achados = valores.filter((v) => v.toLowerCase().includes(busca.toLowerCase()));
38
+ if (tipo !== "numero") return achados;
39
+ return [...achados].sort((a, b) => {
40
+ const na = Number(a), nb = Number(b);
41
+ const va = a !== "—" && Number.isFinite(na), vb = b !== "—" && Number.isFinite(nb);
42
+ if (va && vb) return na - nb;
43
+ return va ? -1 : vb ? 1 : a.localeCompare(b);
44
+ });
45
+ }, [valores, busca, tipo]);
46
+ const todosVisiveis = visiveis.length > 0 && visiveis.every((v) => rascunho.has(v));
47
+ const algunsVisiveis = visiveis.some((v) => rascunho.has(v)) && !todosVisiveis;
48
+ const alternarTodos = () => setRascunho((prev) => {
49
+ const n = new Set(prev);
50
+ if (todosVisiveis) for (const v of visiveis) n.delete(v);
51
+ else for (const v of visiveis) n.add(v);
52
+ return n;
53
+ });
54
+ const alternar = (v) => setRascunho((prev) => {
55
+ const n = new Set(prev);
56
+ if (n.has(v)) n.delete(v);
57
+ else n.add(v);
58
+ return n;
59
+ });
60
+ const mesmoConjunto = (a, b) => a.size === b.size && [...a].every((v) => b.has(v));
61
+ const sujo = tipo === "data" ? de !== (intervalo.from ?? "") || ate !== (intervalo.to ?? "") : tipo === "numero" && !modoLista ? min !== (numero?.min ?? "") || max !== (numero?.max ?? "") : !mesmoConjunto(rascunho, seleccionados);
62
+ const temFiltro = seleccionados.size > 0 || !!intervalo.from || !!intervalo.to || !!numero?.min || !!numero?.max;
63
+ useEffect(() => {
64
+ const fora = (e) => {
65
+ if (caixa.current && !caixa.current.contains(e.target)) onFechar();
66
+ };
67
+ const tecla = (e) => {
68
+ if (e.key === "Escape") onFechar();
69
+ };
70
+ const aoRolar = (e) => {
71
+ if (caixa.current && e.target instanceof Node && caixa.current.contains(e.target)) return;
72
+ onFechar();
73
+ };
74
+ document.addEventListener("mousedown", fora);
75
+ document.addEventListener("keydown", tecla);
76
+ window.addEventListener("scroll", aoRolar, true);
77
+ window.addEventListener("resize", onFechar);
78
+ return () => {
79
+ document.removeEventListener("mousedown", fora);
80
+ document.removeEventListener("keydown", tecla);
81
+ window.removeEventListener("scroll", aoRolar, true);
82
+ window.removeEventListener("resize", onFechar);
83
+ };
84
+ }, [onFechar]);
85
+ const botaoModo = tipo === "numero" && /* @__PURE__ */ jsxs(
86
+ "button",
87
+ {
88
+ type: "button",
89
+ onClick: (e) => {
90
+ e.preventDefault();
91
+ setModoLista((m) => !m);
92
+ },
93
+ title: modoLista ? L.showRange : L.showList,
94
+ className: "inline-flex items-center gap-1 text-[9px] font-black uppercase tracking-widest text-slate-400 hover:text-proef-blue flex-shrink-0 whitespace-nowrap",
95
+ children: [
96
+ modoLista ? /* @__PURE__ */ jsx(SlidersIcon, { size: 10 }) : /* @__PURE__ */ jsx(ListIcon, { size: 10 }),
97
+ modoLista ? L.showRange : L.showList
98
+ ]
99
+ }
100
+ );
101
+ const paraCima = window.innerHeight - ancora.bottom < ALTURA && ancora.top > ALTURA;
102
+ return createPortal(
103
+ /* @__PURE__ */ jsxs(
104
+ "div",
105
+ {
106
+ ref: caixa,
107
+ style: {
108
+ position: "fixed",
109
+ left: Math.max(4, Math.min(ancora.left, window.innerWidth - LARGURA - 4)),
110
+ ...paraCima ? { bottom: window.innerHeight - ancora.top + 2 } : { top: ancora.bottom + 2 },
111
+ width: LARGURA,
112
+ maxHeight: ALTURA
113
+ },
114
+ className: "v1-reset z-[250] flex flex-col bg-white border border-slate-200 shadow-lg",
115
+ children: [
116
+ label && /* @__PURE__ */ jsx("div", { className: "px-3 pt-2.5 pb-2 border-b border-slate-100 flex-shrink-0", children: /* @__PURE__ */ jsx("span", { className: "text-[9px] font-black uppercase tracking-widest text-proef-blue", children: label }) }),
117
+ aCarregar && /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 bg-amber-50 border-b border-amber-100 flex items-center gap-1.5 text-micro text-amber-700 flex-shrink-0", children: [
118
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "inline-block h-2.5 w-2.5 animate-spin rounded-full border-2 border-current border-t-transparent " }),
119
+ L.loadingOptions
120
+ ] }),
121
+ canSort && onOrdenar && /* @__PURE__ */ jsxs("div", { className: "border-b border-slate-100 p-1.5 space-y-0.5 flex-shrink-0", children: [
122
+ /* @__PURE__ */ jsxs(
123
+ "button",
124
+ {
125
+ onClick: () => onOrdenar("asc"),
126
+ className: `w-full flex items-center gap-2 px-2.5 py-1.5 text-caption font-semibold text-left hover:bg-slate-50 transition-colors ${ordenadaPor === "asc" ? "text-proef-blue bg-slate-50" : "text-slate-600"}`,
127
+ children: [
128
+ /* @__PURE__ */ jsx(ChevronUpIcon, { size: 11 }),
129
+ " ",
130
+ tipo === "data" ? L.sortDateAsc : tipo === "numero" ? L.sortNumAsc : L.sortAsc
131
+ ]
132
+ }
133
+ ),
134
+ /* @__PURE__ */ jsxs(
135
+ "button",
136
+ {
137
+ onClick: () => onOrdenar("desc"),
138
+ className: `w-full flex items-center gap-2 px-2.5 py-1.5 text-caption font-semibold text-left hover:bg-slate-50 transition-colors ${ordenadaPor === "desc" ? "text-proef-blue bg-slate-50" : "text-slate-600"}`,
139
+ children: [
140
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 11 }),
141
+ " ",
142
+ tipo === "data" ? L.sortDateDesc : tipo === "numero" ? L.sortNumDesc : L.sortDesc
143
+ ]
144
+ }
145
+ )
146
+ ] }),
147
+ tipo === "data" ? /* @__PURE__ */ jsxs("div", { className: "p-3 space-y-2", children: [
148
+ /* @__PURE__ */ jsxs("label", { className: "block", children: [
149
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] font-black uppercase tracking-widest text-slate-400", children: L.dateFrom }),
150
+ /* @__PURE__ */ jsx(
151
+ "input",
152
+ {
153
+ type: "date",
154
+ value: de,
155
+ onChange: (e) => setDe(e.target.value),
156
+ onKeyDown: (e) => {
157
+ if (e.key === "Enter") onAplicarDatas?.(de, ate);
158
+ },
159
+ className: "w-full mt-0.5 bg-slate-50 border border-slate-100 px-2.5 py-1.5 text-xs outline-none focus:border-proef-blue"
160
+ }
161
+ )
162
+ ] }),
163
+ /* @__PURE__ */ jsxs("label", { className: "block", children: [
164
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] font-black uppercase tracking-widest text-slate-400", children: L.dateTo }),
165
+ /* @__PURE__ */ jsx(
166
+ "input",
167
+ {
168
+ type: "date",
169
+ value: ate,
170
+ onChange: (e) => setAte(e.target.value),
171
+ onKeyDown: (e) => {
172
+ if (e.key === "Enter") onAplicarDatas?.(de, ate);
173
+ },
174
+ className: "w-full mt-0.5 bg-slate-50 border border-slate-100 px-2.5 py-1.5 text-xs outline-none focus:border-proef-blue"
175
+ }
176
+ )
177
+ ] })
178
+ ] }) : !lista ? (
179
+ /* Mín/Máx em vez da lista: numa coluna de dinheiro ou de contagem há
180
+ tantos valores distintos quantas as linhas, e ninguém procura "10.04".
181
+ Vazio de um dos lados vale "sem limite desse lado". */
182
+ /* @__PURE__ */ jsxs("div", { className: "p-3 space-y-2", children: [
183
+ /* @__PURE__ */ jsxs("div", { children: [
184
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center justify-between", children: [
185
+ /* @__PURE__ */ jsx("label", { htmlFor: idMin, className: "text-[9px] font-black uppercase tracking-widest text-slate-400", children: L.min }),
186
+ botaoModo
187
+ ] }),
188
+ /* @__PURE__ */ jsx(
189
+ "input",
190
+ {
191
+ id: idMin,
192
+ type: "number",
193
+ value: min,
194
+ onChange: (e) => setMin(e.target.value),
195
+ onKeyDown: (e) => {
196
+ if (e.key === "Enter") onAplicarNumeros?.(min, max);
197
+ },
198
+ className: "w-full mt-0.5 bg-slate-50 border border-slate-100 px-2.5 py-1.5 text-xs outline-none focus:border-proef-blue"
199
+ }
200
+ )
201
+ ] }),
202
+ /* @__PURE__ */ jsxs("label", { className: "block", children: [
203
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] font-black uppercase tracking-widest text-slate-400", children: L.max }),
204
+ /* @__PURE__ */ jsx(
205
+ "input",
206
+ {
207
+ type: "number",
208
+ value: max,
209
+ onChange: (e) => setMax(e.target.value),
210
+ onKeyDown: (e) => {
211
+ if (e.key === "Enter") onAplicarNumeros?.(min, max);
212
+ },
213
+ className: "w-full mt-0.5 bg-slate-50 border border-slate-100 px-2.5 py-1.5 text-xs outline-none focus:border-proef-blue"
214
+ }
215
+ )
216
+ ] })
217
+ ] })
218
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
219
+ /* @__PURE__ */ jsxs("div", { className: "p-1.5 flex-shrink-0 flex items-center gap-2", children: [
220
+ /* @__PURE__ */ jsx(
221
+ "input",
222
+ {
223
+ autoFocus: true,
224
+ type: "text",
225
+ value: busca,
226
+ onChange: (e) => setBusca(e.target.value),
227
+ placeholder: L.search,
228
+ className: "flex-1 min-w-0 bg-slate-50 border border-slate-100 px-2.5 py-1.5 text-xs outline-none focus:border-proef-blue"
229
+ }
230
+ ),
231
+ botaoModo && /* @__PURE__ */ jsx("span", { className: "pr-1.5", children: botaoModo })
232
+ ] }),
233
+ visiveis.length > 0 && /* @__PURE__ */ jsxs(
234
+ "button",
235
+ {
236
+ onClick: alternarTodos,
237
+ className: "flex items-center gap-2 px-3 py-1.5 border-y border-slate-100 hover:bg-slate-50 text-left flex-shrink-0",
238
+ children: [
239
+ /* @__PURE__ */ jsx("div", { className: `w-3.5 h-3.5 flex items-center justify-center border flex-shrink-0 transition-colors ${todosVisiveis ? "bg-primary border-primary" : algunsVisiveis ? "bg-primary/30 border-primary" : "border-slate-300"}`, children: todosVisiveis && /* @__PURE__ */ jsx(CheckIcon, { size: 9, strokeWidth: 3, className: "text-white" }) }),
240
+ /* @__PURE__ */ jsx("span", { className: "text-caption font-semibold text-slate-600", children: busca ? L.selectAllFound(visiveis.length) : L.selectAll })
241
+ ]
242
+ }
243
+ ),
244
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto p-1.5 space-y-0.5 min-h-0", children: visiveis.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-caption text-slate-400 text-center py-3", children: L.noResults }) : visiveis.map((v) => {
245
+ const escolhido = rascunho.has(v);
246
+ return /* @__PURE__ */ jsxs("button", { onClick: () => alternar(v), className: "w-full flex items-center gap-2 px-2 py-1.5 hover:bg-slate-50 text-left", children: [
247
+ /* @__PURE__ */ jsx("div", { className: `w-3.5 h-3.5 flex items-center justify-center border flex-shrink-0 transition-colors ${escolhido ? "bg-primary border-primary" : "border-slate-300"}`, children: escolhido && /* @__PURE__ */ jsx(CheckIcon, { size: 9, strokeWidth: 3, className: "text-white" }) }),
248
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-slate-700 whitespace-normal break-words leading-snug", children: v })
249
+ ] }, v);
250
+ }) })
251
+ ] }),
252
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 p-1.5 border-t border-slate-100 flex-shrink-0 bg-white", children: [
253
+ /* @__PURE__ */ jsx(
254
+ "button",
255
+ {
256
+ onClick: () => {
257
+ if (tipo === "data") onAplicarDatas?.(de, ate);
258
+ else if (tipo === "numero" && !modoLista) onAplicarNumeros?.(min, max);
259
+ else onAplicar(rascunho);
260
+ },
261
+ disabled: !sujo,
262
+ className: "flex-1 text-micro font-black uppercase tracking-wider text-white bg-primary hover:bg-primary/90 py-1.5 disabled:opacity-30",
263
+ children: L.apply
264
+ }
265
+ ),
266
+ /* @__PURE__ */ jsx(
267
+ "button",
268
+ {
269
+ onClick: onFechar,
270
+ className: "text-micro font-black uppercase tracking-wider text-slate-500 hover:text-slate-700 px-2 py-1.5",
271
+ children: L.cancel
272
+ }
273
+ ),
274
+ temFiltro && /* @__PURE__ */ jsx(
275
+ "button",
276
+ {
277
+ onClick: onLimpar,
278
+ className: "text-micro font-black uppercase tracking-wider text-red-400 hover:text-red-500 px-2 py-1.5",
279
+ children: L.clearFilter
280
+ }
281
+ )
282
+ ] })
283
+ ]
284
+ }
285
+ ),
286
+ document.body
287
+ );
288
+ }
289
+ export {
290
+ ColumnFilter
291
+ };
292
+ //# sourceMappingURL=ColumnFilter.js.map