@proef/common-ui 2.2.6 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/legacy/components/charts/Charts.js +52 -192
- package/dist/esm/legacy/components/charts/Charts.js.map +1 -1
- package/dist/esm/legacy/components/molecules/DataTable/DataTable.js +81 -24
- package/dist/esm/legacy/components/molecules/DataTable/DataTable.js.map +1 -1
- package/dist/esm/legacy/components/organisms/GanttChart/GanttChart.js +7 -4
- package/dist/esm/legacy/components/organisms/GanttChart/GanttChart.js.map +1 -1
- package/dist/esm/v1/components/data/Charts/Charts.js +301 -0
- package/dist/esm/v1/components/data/Charts/Charts.js.map +1 -0
- package/dist/esm/v1/components/overlays/Dialog/Dialog.js +4 -1
- package/dist/esm/v1/components/overlays/Dialog/Dialog.js.map +1 -1
- package/dist/esm/v1/components/tables/Table/ColumnFilter.js +3 -1
- package/dist/esm/v1/components/tables/Table/ColumnFilter.js.map +1 -1
- package/dist/esm/v1/primitives/forms/SelectInput/SelectInput.js +3 -1
- package/dist/esm/v1/primitives/forms/SelectInput/SelectInput.js.map +1 -1
- package/dist/style.components.css +1 -1
- package/dist/style.css +1 -1
- package/dist/style.layered.css +1 -1
- package/dist/theme.css +28 -0
- package/dist/types/legacy/components/charts/Charts.d.ts +14 -11
- package/dist/types/legacy/components/molecules/DataTable/DataTable.d.ts +3 -0
- package/dist/types/legacy/components/organisms/GanttChart/GanttChart.d.ts +15 -1
- package/dist/types/legacy/exports/organisms.d.ts +1 -1
- package/dist/types/v1/components/data/Charts/Charts.d.ts +103 -0
- package/dist/types/v1/index.d.ts +2 -0
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -94,6 +94,7 @@ import { AvatarStack } from "./v1/primitives/display/AvatarStack/AvatarStack.js"
|
|
|
94
94
|
import { AvisosProvider, useAvisos } from "./legacy/components/ui/Avisos.js";
|
|
95
95
|
import { Badge } from "./v1/primitives/display/Badge/Badge.js";
|
|
96
96
|
import { BadgeSla, BarraFiltros, Btn, BtnGroup, Campo, CampoInterruptor, CampoPesquisa, CampoSelect, ChipEstadoInterno, Estado, LinhaAlerta, ListaCampos, Modal, SectionGroup } from "./legacy/components/ui/Ui.js";
|
|
97
|
+
import { BarChart, DonutChart, LineChart, shortDateLabel, useChartPalette } from "./v1/components/data/Charts/Charts.js";
|
|
97
98
|
import { BoldIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronsUpDownIcon, CloseIcon, ErrorIcon, ExternalLinkIcon, FilterIcon, GlobeIcon, ImageIcon, InfoIcon, ItalicIcon, LayersIcon, ListBulletIcon, ListIcon, ListNumberedIcon, LockIcon, LogOutIcon, MaximizeIcon, MenuIcon, MinimizeIcon, MonitorIcon, MoonIcon, PanelOpenIcon, PrefilledIcon, QrCodeIcon, QuoteIcon, SearchIcon, SlidersIcon, SparklesIcon, StrikethroughIcon, SunIcon, UnderlineIcon, WarningIcon } from "./v1/foundations/icons/icons.js";
|
|
98
99
|
import { Card } from "./v1/primitives/display/Card/Card.js";
|
|
99
100
|
import { DEFAULT_LIST_FINDER_LABELS } from "./v1/components/lists/ListFinder/labels.js";
|
|
@@ -130,6 +131,7 @@ export {
|
|
|
130
131
|
AvisosProvider,
|
|
131
132
|
Badge,
|
|
132
133
|
BadgeSla,
|
|
134
|
+
BarChart,
|
|
133
135
|
default7 as BarraAcoes,
|
|
134
136
|
BarraFiltros,
|
|
135
137
|
default8 as BarraValor,
|
|
@@ -170,6 +172,7 @@ export {
|
|
|
170
172
|
DateInput,
|
|
171
173
|
default20 as Dialog,
|
|
172
174
|
default21 as DocumentDropzone,
|
|
175
|
+
DonutChart,
|
|
173
176
|
default22 as Error,
|
|
174
177
|
ErrorIcon,
|
|
175
178
|
default23 as ErrorPage,
|
|
@@ -208,6 +211,7 @@ export {
|
|
|
208
211
|
LayersIcon,
|
|
209
212
|
default41 as Layout,
|
|
210
213
|
LazyLoader,
|
|
214
|
+
LineChart,
|
|
211
215
|
Linha,
|
|
212
216
|
LinhaAlerta,
|
|
213
217
|
Linhas,
|
|
@@ -311,6 +315,7 @@ export {
|
|
|
311
315
|
richTextToPlain,
|
|
312
316
|
sanitizeRichText,
|
|
313
317
|
scanQRCodes,
|
|
318
|
+
shortDateLabel,
|
|
314
319
|
termosDaPesquisa,
|
|
315
320
|
textToRichText,
|
|
316
321
|
themeBootScript,
|
|
@@ -319,6 +324,7 @@ export {
|
|
|
319
324
|
useApi,
|
|
320
325
|
useAuth,
|
|
321
326
|
useAvisos,
|
|
327
|
+
useChartPalette,
|
|
322
328
|
useColumnLayout,
|
|
323
329
|
useConfirm,
|
|
324
330
|
useDialogContainer,
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Chart, registerables } from "chart.js";
|
|
3
3
|
import ChartDataLabels from "chartjs-plugin-datalabels";
|
|
4
|
-
import {
|
|
4
|
+
import { Bubble } from "react-chartjs-2";
|
|
5
5
|
import { useIsDark } from "../../../v1/capabilities/theme/useIsDark.js";
|
|
6
|
+
import { DonutChart, BarChart, LineChart } from "../../../v1/components/data/Charts/Charts.js";
|
|
6
7
|
function euros(v) {
|
|
7
8
|
if (v == null) return "—";
|
|
8
9
|
const negativo = v < 0;
|
|
@@ -10,12 +11,6 @@ function euros(v) {
|
|
|
10
11
|
const comMilhares = inteiro.replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
|
11
12
|
return `${negativo ? "-" : ""}${comMilhares},${decimal} €`;
|
|
12
13
|
}
|
|
13
|
-
function labelBucket(b) {
|
|
14
|
-
if (/^\d{4}-S\d{2}$/.test(b)) return `S${b.slice(6)}/${b.slice(2, 4)}`;
|
|
15
|
-
if (/^\d{4}-\d{2}$/.test(b)) return `${b.slice(5)}/${b.slice(0, 4)}`;
|
|
16
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(b)) return `${b.slice(8)}/${b.slice(5, 7)}`;
|
|
17
|
-
return b;
|
|
18
|
-
}
|
|
19
14
|
Chart.register(...registerables, ChartDataLabels);
|
|
20
15
|
Chart.defaults.set("plugins.datalabels", { display: false });
|
|
21
16
|
Chart.defaults.font.family = "'Montserrat', sans-serif";
|
|
@@ -41,85 +36,39 @@ function useTema() {
|
|
|
41
36
|
const escuro = useIsDark();
|
|
42
37
|
return escuro ? { texto: "#CBD5E1", forte: "#E2E8F0", grelha: "#1E293B" } : { texto: "#5B6577", forte: "#182238", grelha: "#EEF1F5" };
|
|
43
38
|
}
|
|
44
|
-
function legendaBaixo(tema) {
|
|
45
|
-
return {
|
|
46
|
-
position: "bottom",
|
|
47
|
-
labels: { boxWidth: 10, font: { size: 11 }, color: tema.forte, usePointStyle: true, pointStyle: "circle" }
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function clique(labels, series, onClick) {
|
|
51
|
-
if (!onClick) return {};
|
|
52
|
-
return {
|
|
53
|
-
onClick: (_e, els) => {
|
|
54
|
-
const el = els[0];
|
|
55
|
-
if (!el) return;
|
|
56
|
-
onClick(labels[el.index], el.index, series?.[el.datasetIndex]?.nome);
|
|
57
|
-
},
|
|
58
|
-
onHover: (e, els) => {
|
|
59
|
-
const alvo = e.native?.target;
|
|
60
|
-
if (alvo) alvo.style.cursor = els.length ? "pointer" : "default";
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
39
|
function Barras({
|
|
65
|
-
labels
|
|
66
|
-
series
|
|
67
|
-
horizontal
|
|
68
|
-
empilhado
|
|
40
|
+
labels,
|
|
41
|
+
series,
|
|
42
|
+
horizontal,
|
|
43
|
+
empilhado,
|
|
69
44
|
altura,
|
|
70
45
|
limite,
|
|
71
46
|
cores,
|
|
72
|
-
formatar
|
|
73
|
-
valores
|
|
74
|
-
percentagem
|
|
47
|
+
formatar,
|
|
48
|
+
valores,
|
|
49
|
+
percentagem,
|
|
75
50
|
legenda,
|
|
76
|
-
formatarEtiqueta
|
|
51
|
+
formatarEtiqueta,
|
|
77
52
|
onClick
|
|
78
53
|
}) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const series = todasSeries.map((s) => ({ ...s, valores: limite ? s.valores.slice(0, limite) : s.valores }));
|
|
82
|
-
const uma = series.length === 1;
|
|
83
|
-
const total = uma ? todasSeries[0].valores.reduce((a, b) => a + (b || 0), 0) : 0;
|
|
84
|
-
const etiqueta = (v) => percentagem && uma && total > 0 ? `${formatar(v)} (${Math.round(v / total * 100)}%)` : formatar(v);
|
|
85
|
-
const alturaFinal = altura ?? (horizontal ? Math.max(200, labels.length * 30 + 40) : 260);
|
|
86
|
-
const eixoValor = { beginAtZero: true, stacked: empilhado, grid: { color: tema.grelha }, ticks: { color: tema.texto, callback: (v) => formatar(Number(v)) } };
|
|
87
|
-
const eixoEtiqueta = { stacked: empilhado, grid: { display: false }, ticks: { color: tema.texto } };
|
|
88
|
-
return /* @__PURE__ */ jsx("div", { style: { height: alturaFinal }, children: /* @__PURE__ */ jsx(
|
|
89
|
-
Bar,
|
|
54
|
+
return /* @__PURE__ */ jsx(
|
|
55
|
+
BarChart,
|
|
90
56
|
{
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
responsive: true,
|
|
105
|
-
...clique(labels, series, onClick),
|
|
106
|
-
plugins: {
|
|
107
|
-
legend: legenda ?? !uma ? legendaBaixo(tema) : { display: false },
|
|
108
|
-
tooltip: { callbacks: { label: (c) => `${c.dataset.label ? `${c.dataset.label}: ` : ""}${etiqueta(Number(c.parsed[horizontal ? "x" : "y"]))}` } },
|
|
109
|
-
datalabels: {
|
|
110
|
-
display: (c) => valores && !empilhado && Number(c.dataset.data[c.dataIndex]) > 0,
|
|
111
|
-
anchor: "end",
|
|
112
|
-
align: "end",
|
|
113
|
-
color: tema.forte,
|
|
114
|
-
font: { size: 10, weight: 600 },
|
|
115
|
-
formatter: (v) => etiqueta(v)
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
scales: horizontal ? { x: eixoValor, y: eixoEtiqueta } : { x: eixoEtiqueta, y: eixoValor },
|
|
119
|
-
layout: { padding: horizontal ? { right: valores ? percentagem ? 56 : 32 : 8 } : { top: valores ? 18 : 4 } }
|
|
120
|
-
}
|
|
57
|
+
labels,
|
|
58
|
+
series: series.map((s) => ({ name: s.nome, values: s.valores, color: s.cor })),
|
|
59
|
+
horizontal,
|
|
60
|
+
stacked: empilhado,
|
|
61
|
+
height: altura,
|
|
62
|
+
limit: limite,
|
|
63
|
+
colors: cores,
|
|
64
|
+
format: formatar,
|
|
65
|
+
showValues: valores,
|
|
66
|
+
showPercent: percentagem,
|
|
67
|
+
legend: legenda,
|
|
68
|
+
formatLabel: formatarEtiqueta,
|
|
69
|
+
onClick
|
|
121
70
|
}
|
|
122
|
-
)
|
|
71
|
+
);
|
|
123
72
|
}
|
|
124
73
|
function BarrasEmpilhadas({ serie, altura = 280, onClick }) {
|
|
125
74
|
return /* @__PURE__ */ jsx(Barras, { labels: serie.labels, series: serie.series, empilhado: true, altura, onClick, legenda: true });
|
|
@@ -148,50 +97,10 @@ function Anel({
|
|
|
148
97
|
dados,
|
|
149
98
|
altura = 260,
|
|
150
99
|
cores,
|
|
151
|
-
formatar
|
|
100
|
+
formatar,
|
|
152
101
|
onClick
|
|
153
102
|
}) {
|
|
154
|
-
|
|
155
|
-
const total = dados.valores.reduce((a, b) => a + (b || 0), 0);
|
|
156
|
-
return /* @__PURE__ */ jsx("div", { style: { height: altura }, children: /* @__PURE__ */ jsx(
|
|
157
|
-
Doughnut,
|
|
158
|
-
{
|
|
159
|
-
data: {
|
|
160
|
-
labels: dados.labels,
|
|
161
|
-
datasets: [
|
|
162
|
-
{
|
|
163
|
-
data: dados.valores,
|
|
164
|
-
backgroundColor: cores ?? dados.labels.map((_, i) => cor(i)),
|
|
165
|
-
borderWidth: 0
|
|
166
|
-
}
|
|
167
|
-
]
|
|
168
|
-
},
|
|
169
|
-
options: {
|
|
170
|
-
maintainAspectRatio: false,
|
|
171
|
-
responsive: true,
|
|
172
|
-
cutout: "58%",
|
|
173
|
-
...clique(dados.labels, void 0, onClick),
|
|
174
|
-
plugins: {
|
|
175
|
-
legend: legendaBaixo(tema),
|
|
176
|
-
tooltip: {
|
|
177
|
-
callbacks: {
|
|
178
|
-
label: (c) => {
|
|
179
|
-
const v = Number(c.parsed);
|
|
180
|
-
return ` ${c.label}: ${formatar(v)}${total > 0 ? ` (${Math.round(v / total * 100)}%)` : ""}`;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
datalabels: {
|
|
185
|
-
// Só nas fatias que têm espaço para o número.
|
|
186
|
-
display: (c) => total > 0 && Number(c.dataset.data[c.dataIndex]) / total >= 0.05,
|
|
187
|
-
color: "#FFFFFF",
|
|
188
|
-
font: { size: 11, weight: 700 },
|
|
189
|
-
formatter: (v) => formatar(v)
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
) });
|
|
103
|
+
return /* @__PURE__ */ jsx(DonutChart, { labels: dados.labels, values: dados.valores, height: altura, colors: cores, format: formatar, onClick });
|
|
195
104
|
}
|
|
196
105
|
function Linha({
|
|
197
106
|
dados,
|
|
@@ -199,91 +108,42 @@ function Linha({
|
|
|
199
108
|
euros: emEuros = false,
|
|
200
109
|
onClick
|
|
201
110
|
}) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
Line,
|
|
111
|
+
return /* @__PURE__ */ jsx(
|
|
112
|
+
LineChart,
|
|
205
113
|
{
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
backgroundColor: "rgba(194,59,52,0.12)",
|
|
214
|
-
fill: true,
|
|
215
|
-
tension: 0.25,
|
|
216
|
-
pointRadius: 3
|
|
217
|
-
}
|
|
218
|
-
]
|
|
219
|
-
},
|
|
220
|
-
options: {
|
|
221
|
-
maintainAspectRatio: false,
|
|
222
|
-
responsive: true,
|
|
223
|
-
...clique(dados.labels, void 0, onClick),
|
|
224
|
-
plugins: {
|
|
225
|
-
legend: { display: false },
|
|
226
|
-
tooltip: {
|
|
227
|
-
callbacks: {
|
|
228
|
-
label: (c) => emEuros ? euros(Number(c.parsed.y)) : String(c.parsed.y)
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
},
|
|
232
|
-
scales: {
|
|
233
|
-
x: { grid: { display: false }, ticks: { color: tema.texto } },
|
|
234
|
-
y: {
|
|
235
|
-
beginAtZero: true,
|
|
236
|
-
grid: { color: tema.grelha },
|
|
237
|
-
ticks: { color: tema.texto, callback: (v) => emEuros ? euros(Number(v)) : String(v) }
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
114
|
+
labels: dados.labels,
|
|
115
|
+
series: [{ name: "", values: dados.valores, color: "#C23B34" }],
|
|
116
|
+
area: true,
|
|
117
|
+
height: altura,
|
|
118
|
+
format: emEuros ? (v) => euros(v) : void 0,
|
|
119
|
+
legend: false,
|
|
120
|
+
onClick
|
|
241
121
|
}
|
|
242
|
-
)
|
|
122
|
+
);
|
|
243
123
|
}
|
|
244
124
|
function Linhas({
|
|
245
125
|
serie,
|
|
246
126
|
altura = 280,
|
|
247
127
|
area = false,
|
|
248
128
|
cores,
|
|
249
|
-
formatar
|
|
250
|
-
formatarEtiqueta
|
|
129
|
+
formatar,
|
|
130
|
+
formatarEtiqueta,
|
|
251
131
|
onClick
|
|
252
132
|
}) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
return /* @__PURE__ */ jsx("div", { style: { height: altura }, children: /* @__PURE__ */ jsx(
|
|
256
|
-
Line,
|
|
133
|
+
return /* @__PURE__ */ jsx(
|
|
134
|
+
LineChart,
|
|
257
135
|
{
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
pointRadius: serie.labels.length > 24 ? 0 : 3,
|
|
268
|
-
pointHoverRadius: 4
|
|
269
|
-
}))
|
|
270
|
-
},
|
|
271
|
-
options: {
|
|
272
|
-
maintainAspectRatio: false,
|
|
273
|
-
responsive: true,
|
|
274
|
-
interaction: { mode: "index", intersect: false },
|
|
275
|
-
...clique(serie.labels, serie.series, onClick),
|
|
276
|
-
plugins: {
|
|
277
|
-
legend: legendaBaixo(tema),
|
|
278
|
-
tooltip: { callbacks: { label: (c) => `${c.dataset.label}: ${formatar(Number(c.parsed.y))}` } }
|
|
279
|
-
},
|
|
280
|
-
scales: {
|
|
281
|
-
x: { grid: { display: false }, ticks: { color: tema.texto, autoSkip: true, maxRotation: 0 } },
|
|
282
|
-
y: { beginAtZero: true, grid: { color: tema.grelha }, ticks: { color: tema.texto, callback: (v) => formatar(Number(v)) } }
|
|
283
|
-
}
|
|
284
|
-
}
|
|
136
|
+
labels: serie.labels,
|
|
137
|
+
series: serie.series.map((s) => ({ name: s.nome, values: s.valores })),
|
|
138
|
+
area,
|
|
139
|
+
colors: cores,
|
|
140
|
+
format: formatar,
|
|
141
|
+
formatLabel: formatarEtiqueta,
|
|
142
|
+
height: altura,
|
|
143
|
+
legend: true,
|
|
144
|
+
onClick
|
|
285
145
|
}
|
|
286
|
-
)
|
|
146
|
+
);
|
|
287
147
|
}
|
|
288
148
|
function Bolhas({
|
|
289
149
|
pontos,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Charts.js","sources":["../../../../../src/legacy/components/charts/Charts.tsx"],"sourcesContent":["import React from 'react'\r\nimport { Chart as ChartJS, registerables, type ActiveElement, type ChartEvent } from 'chart.js'\r\nimport ChartDataLabels from 'chartjs-plugin-datalabels'\r\nimport { Bar, Doughnut, Line, Bubble } from 'react-chartjs-2'\r\nimport { useIsDark } from '../../../v1/capabilities/theme/useIsDark'\r\n\r\n// ---------------------------------------------------------------------------\r\n// Local types (inlined — originally imported from CRE `../types`).\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Stacked series over a set of shared labels (e.g. a dimension over time).\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport interface SerieEmpilhada {\r\n labels: string[]\r\n series: { nome: string; valores: number[] }[]\r\n}\r\n\r\n/**\r\n * A simple distribution: parallel arrays of labels and values.\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport interface Distribuicao {\r\n labels: string[]\r\n valores: number[]\r\n}\r\n\r\n/**\r\n * Clique num elemento do gráfico: a etiqueta (ex: \"Incidente\"), a posição dela\r\n * e o nome da série (quando há várias). Serve para filtrar ao clicar.\r\n */\r\nexport type CliqueGrafico = (label: string, indice: number, serie?: string) => void\r\n\r\n// ---------------------------------------------------------------------------\r\n// Local formatting helpers (inlined — originally imported from CRE `../lib/format`).\r\n// Behavior kept close to the originals; the library stays self-contained.\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Currency formatter. Thousands separated by '.', decimals by ',', suffixed ' €'.\r\n * Independent of Intl/ICU so the thousands separator is stable across browsers.\r\n */\r\nfunction euros(v: number | null | undefined): string {\r\n if (v == null) return '—'\r\n const negativo = v < 0\r\n const [inteiro, decimal] = Math.abs(v).toFixed(2).split('.')\r\n const comMilhares = inteiro.replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.')\r\n return `${negativo ? '-' : ''}${comMilhares},${decimal} €`\r\n}\r\n\r\n/** 'YYYY-Sxx' / 'YYYY-MM' / 'YYYY-MM-DD' → short axis label. */\r\nfunction labelBucket(b: string): string {\r\n if (/^\\d{4}-S\\d{2}$/.test(b)) return `S${b.slice(6)}/${b.slice(2, 4)}`\r\n if (/^\\d{4}-\\d{2}$/.test(b)) return `${b.slice(5)}/${b.slice(0, 4)}`\r\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(b)) return `${b.slice(8)}/${b.slice(5, 7)}`\r\n return b\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Chart.js registration (once, at module load).\r\n// ---------------------------------------------------------------------------\r\n\r\n// Regista TUDO (registerables inclui Filler, controllers, scales) + o plugin de\r\n// datalabels. O registo parcial degenerava a geometria (doughnut colapsado) e o\r\n// aviso \"fill sem Filler\". registerables = equivalente a chart.js/auto.\r\nChartJS.register(...registerables, ChartDataLabels)\r\n// Datalabels off by default — enabled only where it improves readability.\r\nChartJS.defaults.set('plugins.datalabels', { display: false })\r\nChartJS.defaults.font.family = \"'Montserrat', sans-serif\"\r\nChartJS.defaults.color = '#5B6577'\r\n\r\n/**\r\n * Categorical palette. Stable order so the same dimension always maps to the same color.\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport const PALETA = [\r\n '#1868B0',\r\n '#1F8A55',\r\n '#B96E00',\r\n '#C23B34',\r\n '#7C3AED',\r\n '#0891B2',\r\n '#DB2777',\r\n '#65A30D',\r\n '#4B5563',\r\n '#D97706',\r\n '#2563EB',\r\n '#059669',\r\n]\r\n\r\n/** @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy. */\r\nexport function cor(i: number): string {\r\n return PALETA[i % PALETA.length]!\r\n}\r\n\r\n/**\r\n * Cores do texto e da grelha conforme o tema: as do claro sobre o fundo escuro\r\n * deixavam os eixos e os valores ilegíveis.\r\n */\r\nfunction useTema() {\r\n const escuro = useIsDark()\r\n return escuro\r\n ? { texto: '#CBD5E1', forte: '#E2E8F0', grelha: '#1E293B' }\r\n : { texto: '#5B6577', forte: '#182238', grelha: '#EEF1F5' }\r\n}\r\n\r\nfunction legendaBaixo(tema: ReturnType<typeof useTema>) {\r\n return {\r\n position: 'bottom' as const,\r\n labels: { boxWidth: 10, font: { size: 11 }, color: tema.forte, usePointStyle: true, pointStyle: 'circle' as const },\r\n }\r\n}\r\n\r\n/** Liga o clique do Chart.js ao `onClick` da biblioteca, com a mão por cima dos elementos. */\r\nfunction clique(labels: string[], series: { nome: string }[] | undefined, onClick?: CliqueGrafico) {\r\n if (!onClick) return {}\r\n return {\r\n onClick: (_e: ChartEvent, els: ActiveElement[]) => {\r\n const el = els[0]\r\n if (!el) return\r\n onClick(labels[el.index]!, el.index, series?.[el.datasetIndex]?.nome)\r\n },\r\n onHover: (e: ChartEvent, els: ActiveElement[]) => {\r\n const alvo = e.native?.target as HTMLElement | undefined\r\n if (alvo) alvo.style.cursor = els.length ? 'pointer' : 'default'\r\n },\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Barras — o componente geral; BarrasEmpilhadas e BarrasHorizontais são atalhos.\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface BarrasProps {\r\n labels: string[]\r\n /** Uma ou várias séries (ex: \"Atribuídos\" e \"Resolvidos\"), lado a lado ou empilhadas. */\r\n series: { nome: string; valores: number[]; cor?: string }[]\r\n /** Barras deitadas, com as etiquetas à esquerda (bom para nomes compridos e rankings). */\r\n horizontal?: boolean\r\n /** Séries empilhadas em vez de lado a lado. */\r\n empilhado?: boolean\r\n /** Altura em px. Nas horizontais, por omissão cresce com o número de barras. */\r\n altura?: number\r\n /** Só as primeiras N (ex: top 10). */\r\n limite?: number\r\n /** Cor de cada barra, quando há uma só série (ex: a cor de cada estado). */\r\n cores?: string[]\r\n /** Formato dos valores no tooltip, nas etiquetas e no eixo (ex: minutos → \"7h30\"). */\r\n formatar?: (v: number) => string\r\n /** Mostra o valor na ponta de cada barra. */\r\n valores?: boolean\r\n /** Junta a percentagem do total ao valor (ex: \"12 (34%)\"); só com uma série. */\r\n percentagem?: boolean\r\n /** Legenda das séries. Por omissão, só quando há mais do que uma. */\r\n legenda?: boolean\r\n /** Formato das etiquetas do eixo (ex: datas). Por omissão, datas ISO ficam curtas. */\r\n formatarEtiqueta?: (label: string) => string\r\n /** Clique numa barra: devolve a etiqueta, a posição e a série. */\r\n onClick?: CliqueGrafico\r\n}\r\n\r\n/** @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy. */\r\nexport function Barras({\r\n labels: todas,\r\n series: todasSeries,\r\n horizontal = false,\r\n empilhado = false,\r\n altura,\r\n limite,\r\n cores,\r\n formatar = (v) => String(v),\r\n valores = true,\r\n percentagem = false,\r\n legenda,\r\n formatarEtiqueta = labelBucket,\r\n onClick,\r\n}: BarrasProps) {\r\n const tema = useTema()\r\n const labels = limite ? todas.slice(0, limite) : todas\r\n const series = todasSeries.map((s) => ({ ...s, valores: limite ? s.valores.slice(0, limite) : s.valores }))\r\n const uma = series.length === 1\r\n // A percentagem é do total, não só das barras mostradas (com `limite` seria das top N).\r\n const total = uma ? todasSeries[0]!.valores.reduce((a, b) => a + (b || 0), 0) : 0\r\n const etiqueta = (v: number) => (percentagem && uma && total > 0 ? `${formatar(v)} (${Math.round((v / total) * 100)}%)` : formatar(v))\r\n const alturaFinal = altura ?? (horizontal ? Math.max(200, labels.length * 30 + 40) : 260)\r\n const eixoValor = { beginAtZero: true, stacked: empilhado, grid: { color: tema.grelha }, ticks: { color: tema.texto, callback: (v: string | number) => formatar(Number(v)) } }\r\n const eixoEtiqueta = { stacked: empilhado, grid: { display: false }, ticks: { color: tema.texto } }\r\n\r\n return (\r\n <div style={{ height: alturaFinal }}>\r\n <Bar\r\n data={{\r\n labels: labels.map(formatarEtiqueta),\r\n datasets: series.map((s, i) => ({\r\n label: s.nome,\r\n data: s.valores,\r\n backgroundColor: uma && cores ? labels.map((_, j) => cores[j % cores.length]!) : (s.cor ?? cor(i)),\r\n borderRadius: 4,\r\n maxBarThickness: 40,\r\n })),\r\n }}\r\n options={{\r\n indexAxis: horizontal ? 'y' : 'x',\r\n maintainAspectRatio: false,\r\n responsive: true,\r\n ...clique(labels, series, onClick),\r\n plugins: {\r\n legend: legenda ?? !uma ? legendaBaixo(tema) : { display: false },\r\n tooltip: { callbacks: { label: (c) => `${c.dataset.label ? `${c.dataset.label}: ` : ''}${etiqueta(Number(c.parsed[horizontal ? 'x' : 'y']))}` } },\r\n datalabels: {\r\n display: (c) => valores && !empilhado && Number(c.dataset.data[c.dataIndex]) > 0,\r\n anchor: 'end',\r\n align: 'end',\r\n color: tema.forte,\r\n font: { size: 10, weight: 600 },\r\n formatter: (v: number) => etiqueta(v),\r\n },\r\n },\r\n scales: horizontal ? { x: eixoValor, y: eixoEtiqueta } : { x: eixoEtiqueta, y: eixoValor },\r\n layout: { padding: horizontal ? { right: valores ? (percentagem ? 56 : 32) : 8 } : { top: valores ? 18 : 4 } },\r\n }}\r\n />\r\n </div>\r\n )\r\n}\r\n\r\n/**\r\n * Stacked bars for a dimension over time.\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport function BarrasEmpilhadas({ serie, altura = 280, onClick }: { serie: SerieEmpilhada; altura?: number; onClick?: CliqueGrafico }) {\r\n return <Barras labels={serie.labels} series={serie.series} empilhado altura={altura} onClick={onClick} legenda />\r\n}\r\n\r\n/**\r\n * Horizontal bars of a distribution (top N).\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport function BarrasHorizontais({\r\n dados,\r\n altura = 280,\r\n limite = 12,\r\n onClick,\r\n}: {\r\n dados: Distribuicao\r\n altura?: number\r\n limite?: number\r\n onClick?: CliqueGrafico\r\n}) {\r\n const n = Math.min(limite, dados.labels.length)\r\n return (\r\n <Barras\r\n horizontal\r\n labels={dados.labels}\r\n series={[{ nome: '', valores: dados.valores }]}\r\n cores={Array.from({ length: n }, (_, i) => cor(i))}\r\n limite={limite}\r\n altura={altura}\r\n onClick={onClick}\r\n />\r\n )\r\n}\r\n\r\n/** @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy. */\r\nexport function Anel({\r\n dados,\r\n altura = 260,\r\n cores,\r\n formatar = (v) => String(v),\r\n onClick,\r\n}: {\r\n dados: Distribuicao\r\n altura?: number\r\n cores?: string[]\r\n /** Formato dos valores no tooltip. */\r\n formatar?: (v: number) => string\r\n /** Clique numa fatia: devolve a etiqueta e a posição. */\r\n onClick?: CliqueGrafico\r\n}) {\r\n const tema = useTema()\r\n const total = dados.valores.reduce((a, b) => a + (b || 0), 0)\r\n return (\r\n <div style={{ height: altura }}>\r\n <Doughnut\r\n data={{\r\n labels: dados.labels,\r\n datasets: [\r\n {\r\n data: dados.valores,\r\n backgroundColor: cores ?? dados.labels.map((_, i) => cor(i)),\r\n borderWidth: 0,\r\n },\r\n ],\r\n }}\r\n options={{\r\n maintainAspectRatio: false,\r\n responsive: true,\r\n cutout: '58%',\r\n ...clique(dados.labels, undefined, onClick),\r\n plugins: {\r\n legend: legendaBaixo(tema),\r\n tooltip: {\r\n callbacks: {\r\n label: (c) => {\r\n const v = Number(c.parsed)\r\n return ` ${c.label}: ${formatar(v)}${total > 0 ? ` (${Math.round((v / total) * 100)}%)` : ''}`\r\n },\r\n },\r\n },\r\n datalabels: {\r\n // Só nas fatias que têm espaço para o número.\r\n display: (c) => total > 0 && Number(c.dataset.data[c.dataIndex]) / total >= 0.05,\r\n color: '#FFFFFF',\r\n font: { size: 11, weight: 700 },\r\n formatter: (v: number) => formatar(v),\r\n },\r\n },\r\n }}\r\n />\r\n </div>\r\n )\r\n}\r\n\r\n/**\r\n * Simple line chart — optionally formats values as currency.\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport function Linha({\r\n dados,\r\n altura = 260,\r\n euros: emEuros = false,\r\n onClick,\r\n}: {\r\n dados: Distribuicao\r\n altura?: number\r\n euros?: boolean\r\n onClick?: CliqueGrafico\r\n}) {\r\n const tema = useTema()\r\n return (\r\n <div style={{ height: altura }}>\r\n <Line\r\n data={{\r\n labels: dados.labels.map(labelBucket),\r\n datasets: [\r\n {\r\n label: '',\r\n data: dados.valores,\r\n borderColor: '#C23B34',\r\n backgroundColor: 'rgba(194,59,52,0.12)',\r\n fill: true,\r\n tension: 0.25,\r\n pointRadius: 3,\r\n },\r\n ],\r\n }}\r\n options={{\r\n maintainAspectRatio: false,\r\n responsive: true,\r\n ...clique(dados.labels, undefined, onClick),\r\n plugins: {\r\n legend: { display: false },\r\n tooltip: {\r\n callbacks: {\r\n label: (c) => (emEuros ? euros(Number(c.parsed.y)) : String(c.parsed.y)),\r\n },\r\n },\r\n },\r\n scales: {\r\n x: { grid: { display: false }, ticks: { color: tema.texto } },\r\n y: {\r\n beginAtZero: true,\r\n grid: { color: tema.grelha },\r\n ticks: { color: tema.texto, callback: (v) => (emEuros ? euros(Number(v)) : String(v)) },\r\n },\r\n },\r\n }}\r\n />\r\n </div>\r\n )\r\n}\r\n\r\n/**\r\n * Several lines over the same labels — NOT stacked.\r\n *\r\n * Separate from `BarrasEmpilhadas` on purpose: two series that measure the same\r\n * thing at two moments (created vs closed) must be read against each other, and\r\n * stacking them would draw their sum, which means nothing.\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport function Linhas({\r\n serie,\r\n altura = 280,\r\n area = false,\r\n cores,\r\n formatar = (v) => String(v),\r\n formatarEtiqueta = labelBucket,\r\n onClick,\r\n}: {\r\n serie: SerieEmpilhada\r\n altura?: number\r\n /// Fill under each line. Only legible with one or two series.\r\n area?: boolean\r\n /** Cor de cada série, pela ordem. */\r\n cores?: string[]\r\n /** Formato dos valores no tooltip e no eixo. */\r\n formatar?: (v: number) => string\r\n /** Formato das etiquetas do eixo (ex: datas). */\r\n formatarEtiqueta?: (label: string) => string\r\n /** Clique num ponto: devolve a etiqueta (ex: o dia) e a série. */\r\n onClick?: CliqueGrafico\r\n}) {\r\n const tema = useTema()\r\n const corDe = (i: number) => cores?.[i] ?? cor(i)\r\n return (\r\n <div style={{ height: altura }}>\r\n <Line\r\n data={{\r\n labels: serie.labels.map(formatarEtiqueta),\r\n datasets: serie.series.map((s, i) => ({\r\n label: s.nome,\r\n data: s.valores,\r\n borderColor: corDe(i),\r\n backgroundColor: area ? `${corDe(i)}22` : corDe(i),\r\n fill: area,\r\n tension: 0.25,\r\n pointRadius: serie.labels.length > 24 ? 0 : 3,\r\n pointHoverRadius: 4,\r\n })),\r\n }}\r\n options={{\r\n maintainAspectRatio: false,\r\n responsive: true,\r\n interaction: { mode: 'index', intersect: false },\r\n ...clique(serie.labels, serie.series, onClick),\r\n plugins: {\r\n legend: legendaBaixo(tema),\r\n tooltip: { callbacks: { label: (c) => `${c.dataset.label}: ${formatar(Number(c.parsed.y))}` } },\r\n },\r\n scales: {\r\n x: { grid: { display: false }, ticks: { color: tema.texto, autoSkip: true, maxRotation: 0 } },\r\n y: { beginAtZero: true, grid: { color: tema.grelha }, ticks: { color: tema.texto, callback: (v) => formatar(Number(v)) } },\r\n },\r\n }}\r\n />\r\n </div>\r\n )\r\n}\r\n\r\n/** @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy. */\r\nexport interface PontoRisco {\r\n responsavel: string\r\n otsAtivas: number\r\n percentagemForaPrazo: number\r\n valorPenalizado: number\r\n}\r\n\r\n/**\r\n * Risk-map bubbles: x = active OTs, y = % overdue, r = penalized value.\r\n * The radius is normalized against the max so bubbles stay readable at any scale.\r\n *\r\n * Axis titles and the tooltip formatter are exposed as optional props with\r\n * neutral English defaults (previously hardcoded Portuguese) so the component\r\n * carries no locale of its own.\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport function Bolhas({\r\n pontos,\r\n altura = 280,\r\n onClick,\r\n xTitle = 'Active OTs',\r\n yTitle = '% overdue',\r\n tooltipLabel = (p) => `${p.responsavel}: ${p.otsAtivas} active, ${p.percentagemForaPrazo}% overdue, ${euros(p.valorPenalizado)}`,\r\n}: {\r\n pontos: PontoRisco[]\r\n altura?: number\r\n onClick?: (p: PontoRisco) => void\r\n xTitle?: string\r\n yTitle?: string\r\n tooltipLabel?: (p: PontoRisco) => string\r\n}) {\r\n const tema = useTema()\r\n const maxValor = Math.max(1, ...pontos.map((p) => p.valorPenalizado))\r\n return (\r\n <div style={{ height: altura }}>\r\n <Bubble\r\n data={{\r\n datasets: pontos.map((p, i) => ({\r\n label: p.responsavel,\r\n data: [\r\n {\r\n x: p.otsAtivas,\r\n y: p.percentagemForaPrazo,\r\n r: 6 + (p.valorPenalizado / maxValor) * 18,\r\n },\r\n ],\r\n backgroundColor: `${cor(i)}CC`,\r\n borderColor: cor(i),\r\n })),\r\n }}\r\n options={{\r\n maintainAspectRatio: false,\r\n responsive: true,\r\n onClick: (_e, elements) => {\r\n const idx = elements[0]?.datasetIndex\r\n if (idx != null && onClick) onClick(pontos[idx]!)\r\n },\r\n plugins: {\r\n legend: { display: false },\r\n tooltip: {\r\n callbacks: {\r\n label: (c) => tooltipLabel(pontos[c.datasetIndex]!),\r\n },\r\n },\r\n },\r\n scales: {\r\n x: { beginAtZero: true, title: { display: true, text: xTitle, color: tema.texto }, grid: { color: tema.grelha }, ticks: { color: tema.texto } },\r\n y: { beginAtZero: true, title: { display: true, text: yTitle, color: tema.texto }, grid: { color: tema.grelha }, ticks: { color: tema.texto } },\r\n },\r\n }}\r\n />\r\n </div>\r\n )\r\n}\r\n"],"names":["ChartJS"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Charts.js","sources":["../../../../../src/legacy/components/charts/Charts.tsx"],"sourcesContent":["import React from 'react'\r\nimport { Chart as ChartJS, registerables } from 'chart.js'\r\nimport ChartDataLabels from 'chartjs-plugin-datalabels'\r\nimport { Bubble } from 'react-chartjs-2'\r\nimport { useIsDark } from '../../../v1/capabilities/theme/useIsDark'\r\nimport { BarChart, DonutChart, LineChart } from '../../../v1/components/data/Charts/Charts'\r\n\r\n// ---------------------------------------------------------------------------\r\n// Local types (inlined — originally imported from CRE `../types`).\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Stacked series over a set of shared labels (e.g. a dimension over time).\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport interface SerieEmpilhada {\r\n labels: string[]\r\n series: { nome: string; valores: number[] }[]\r\n}\r\n\r\n/**\r\n * A simple distribution: parallel arrays of labels and values.\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport interface Distribuicao {\r\n labels: string[]\r\n valores: number[]\r\n}\r\n\r\n/**\r\n * Clique num elemento do gráfico: a etiqueta (ex: \"Incidente\"), a posição dela\r\n * e o nome da série (quando há várias). Serve para filtrar ao clicar.\r\n */\r\nexport type CliqueGrafico = (label: string, indice: number, serie?: string) => void\r\n\r\n// ---------------------------------------------------------------------------\r\n// Local formatting helpers (inlined — originally imported from CRE `../lib/format`).\r\n// Behavior kept close to the originals; the library stays self-contained.\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Currency formatter. Thousands separated by '.', decimals by ',', suffixed ' €'.\r\n * Independent of Intl/ICU so the thousands separator is stable across browsers.\r\n */\r\nfunction euros(v: number | null | undefined): string {\r\n if (v == null) return '—'\r\n const negativo = v < 0\r\n const [inteiro, decimal] = Math.abs(v).toFixed(2).split('.')\r\n const comMilhares = inteiro.replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.')\r\n return `${negativo ? '-' : ''}${comMilhares},${decimal} €`\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Chart.js registration (once, at module load).\r\n// ---------------------------------------------------------------------------\r\n\r\n// Regista TUDO (registerables inclui Filler, controllers, scales) + o plugin de\r\n// datalabels. O registo parcial degenerava a geometria (doughnut colapsado) e o\r\n// aviso \"fill sem Filler\". registerables = equivalente a chart.js/auto.\r\nChartJS.register(...registerables, ChartDataLabels)\r\n// Datalabels off by default — enabled only where it improves readability.\r\nChartJS.defaults.set('plugins.datalabels', { display: false })\r\nChartJS.defaults.font.family = \"'Montserrat', sans-serif\"\r\nChartJS.defaults.color = '#5B6577'\r\n\r\n/**\r\n * Categorical palette. Stable order so the same dimension always maps to the same color.\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport const PALETA = [\r\n '#1868B0',\r\n '#1F8A55',\r\n '#B96E00',\r\n '#C23B34',\r\n '#7C3AED',\r\n '#0891B2',\r\n '#DB2777',\r\n '#65A30D',\r\n '#4B5563',\r\n '#D97706',\r\n '#2563EB',\r\n '#059669',\r\n]\r\n\r\n/** @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy. */\r\nexport function cor(i: number): string {\r\n return PALETA[i % PALETA.length]!\r\n}\r\n\r\n/**\r\n * Cores do texto e da grelha conforme o tema: as do claro sobre o fundo escuro\r\n * deixavam os eixos e os valores ilegíveis.\r\n */\r\nfunction useTema() {\r\n const escuro = useIsDark()\r\n return escuro\r\n ? { texto: '#CBD5E1', forte: '#E2E8F0', grelha: '#1E293B' }\r\n : { texto: '#5B6577', forte: '#182238', grelha: '#EEF1F5' }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Barras, Anel e Linhas: adaptadores dos gráficos V1 (BarChart, DonutChart, LineChart),\r\n// com as props de sempre. Só as Bolhas continuam desenhadas aqui.\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface BarrasProps {\r\n labels: string[]\r\n /** Uma ou várias séries (ex: \"Atribuídos\" e \"Resolvidos\"), lado a lado ou empilhadas. */\r\n series: { nome: string; valores: number[]; cor?: string }[]\r\n /** Barras deitadas, com as etiquetas à esquerda (bom para nomes compridos e rankings). */\r\n horizontal?: boolean\r\n /** Séries empilhadas em vez de lado a lado. */\r\n empilhado?: boolean\r\n /** Altura em px. Nas horizontais, por omissão cresce com o número de barras. */\r\n altura?: number\r\n /** Só as primeiras N (ex: top 10). */\r\n limite?: number\r\n /** Cor de cada barra, quando há uma só série (ex: a cor de cada estado). */\r\n cores?: string[]\r\n /** Formato dos valores no tooltip, nas etiquetas e no eixo (ex: minutos → \"7h30\"). */\r\n formatar?: (v: number) => string\r\n /** Mostra o valor na ponta de cada barra. */\r\n valores?: boolean\r\n /** Junta a percentagem do total ao valor (ex: \"12 (34%)\"); só com uma série. */\r\n percentagem?: boolean\r\n /** Legenda das séries. Por omissão, só quando há mais do que uma. */\r\n legenda?: boolean\r\n /** Formato das etiquetas do eixo (ex: datas). Por omissão, datas ISO ficam curtas. */\r\n formatarEtiqueta?: (label: string) => string\r\n /** Clique numa barra: devolve a etiqueta, a posição e a série. */\r\n onClick?: CliqueGrafico\r\n}\r\n\r\n/**\r\n * Migrado para o V1: adaptador do `BarChart` (mesmas props de sempre).\r\n * @deprecated Legacy — usar o `BarChart` do V1. Ver Storybook › Legacy.\r\n */\r\nexport function Barras({\r\n labels,\r\n series,\r\n horizontal,\r\n empilhado,\r\n altura,\r\n limite,\r\n cores,\r\n formatar,\r\n valores,\r\n percentagem,\r\n legenda,\r\n formatarEtiqueta,\r\n onClick,\r\n}: BarrasProps) {\r\n return (\r\n <BarChart\r\n labels={labels}\r\n series={series.map((s) => ({ name: s.nome, values: s.valores, color: s.cor }))}\r\n horizontal={horizontal}\r\n stacked={empilhado}\r\n height={altura}\r\n limit={limite}\r\n colors={cores}\r\n format={formatar}\r\n showValues={valores}\r\n showPercent={percentagem}\r\n legend={legenda}\r\n formatLabel={formatarEtiqueta}\r\n onClick={onClick}\r\n />\r\n )\r\n}\r\n\r\n/**\r\n * Stacked bars for a dimension over time.\r\n * @deprecated Legacy — usar o `BarChart` do V1 com `stacked`. Ver Storybook › Legacy.\r\n */\r\nexport function BarrasEmpilhadas({ serie, altura = 280, onClick }: { serie: SerieEmpilhada; altura?: number; onClick?: CliqueGrafico }) {\r\n return <Barras labels={serie.labels} series={serie.series} empilhado altura={altura} onClick={onClick} legenda />\r\n}\r\n\r\n/**\r\n * Horizontal bars of a distribution (top N).\r\n * @deprecated Legacy — usar o `BarChart` do V1 com `horizontal`. Ver Storybook › Legacy.\r\n */\r\nexport function BarrasHorizontais({\r\n dados,\r\n altura = 280,\r\n limite = 12,\r\n onClick,\r\n}: {\r\n dados: Distribuicao\r\n altura?: number\r\n limite?: number\r\n onClick?: CliqueGrafico\r\n}) {\r\n const n = Math.min(limite, dados.labels.length)\r\n return (\r\n <Barras\r\n horizontal\r\n labels={dados.labels}\r\n series={[{ nome: '', valores: dados.valores }]}\r\n cores={Array.from({ length: n }, (_, i) => cor(i))}\r\n limite={limite}\r\n altura={altura}\r\n onClick={onClick}\r\n />\r\n )\r\n}\r\n\r\n/**\r\n * Migrado para o V1: adaptador do `DonutChart`.\r\n * @deprecated Legacy — usar o `DonutChart` do V1. Ver Storybook › Legacy.\r\n */\r\nexport function Anel({\r\n dados,\r\n altura = 260,\r\n cores,\r\n formatar,\r\n onClick,\r\n}: {\r\n dados: Distribuicao\r\n altura?: number\r\n cores?: string[]\r\n /** Formato dos valores no tooltip. */\r\n formatar?: (v: number) => string\r\n /** Clique numa fatia: devolve a etiqueta e a posição. */\r\n onClick?: CliqueGrafico\r\n}) {\r\n return <DonutChart labels={dados.labels} values={dados.valores} height={altura} colors={cores} format={formatar} onClick={onClick} />\r\n}\r\n\r\n/**\r\n * Simple line chart — optionally formats values as currency.\r\n * @deprecated Legacy — usar o `LineChart` do V1. Ver Storybook › Legacy.\r\n */\r\nexport function Linha({\r\n dados,\r\n altura = 260,\r\n euros: emEuros = false,\r\n onClick,\r\n}: {\r\n dados: Distribuicao\r\n altura?: number\r\n euros?: boolean\r\n onClick?: CliqueGrafico\r\n}) {\r\n return (\r\n <LineChart\r\n labels={dados.labels}\r\n series={[{ name: '', values: dados.valores, color: '#C23B34' }]}\r\n area\r\n height={altura}\r\n format={emEuros ? (v) => euros(v) : undefined}\r\n legend={false}\r\n onClick={onClick}\r\n />\r\n )\r\n}\r\n\r\n/**\r\n * Several lines over the same labels — NOT stacked.\r\n * Migrado para o V1: adaptador do `LineChart` (com a legenda sempre, como antes).\r\n * @deprecated Legacy — usar o `LineChart` do V1. Ver Storybook › Legacy.\r\n */\r\nexport function Linhas({\r\n serie,\r\n altura = 280,\r\n area = false,\r\n cores,\r\n formatar,\r\n formatarEtiqueta,\r\n onClick,\r\n}: {\r\n serie: SerieEmpilhada\r\n altura?: number\r\n /// Fill under each line. Only legible with one or two series.\r\n area?: boolean\r\n /** Cor de cada série, pela ordem. */\r\n cores?: string[]\r\n /** Formato dos valores no tooltip e no eixo. */\r\n formatar?: (v: number) => string\r\n /** Formato das etiquetas do eixo (ex: datas). */\r\n formatarEtiqueta?: (label: string) => string\r\n /** Clique num ponto: devolve a etiqueta (ex: o dia) e a série. */\r\n onClick?: CliqueGrafico\r\n}) {\r\n return (\r\n <LineChart\r\n labels={serie.labels}\r\n series={serie.series.map((s) => ({ name: s.nome, values: s.valores }))}\r\n area={area}\r\n colors={cores}\r\n format={formatar}\r\n formatLabel={formatarEtiqueta}\r\n height={altura}\r\n legend\r\n onClick={onClick}\r\n />\r\n )\r\n}\r\n\r\n/** @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy. */\r\nexport interface PontoRisco {\r\n responsavel: string\r\n otsAtivas: number\r\n percentagemForaPrazo: number\r\n valorPenalizado: number\r\n}\r\n\r\n/**\r\n * Risk-map bubbles: x = active OTs, y = % overdue, r = penalized value.\r\n * The radius is normalized against the max so bubbles stay readable at any scale.\r\n *\r\n * Axis titles and the tooltip formatter are exposed as optional props with\r\n * neutral English defaults (previously hardcoded Portuguese) so the component\r\n * carries no locale of its own.\r\n * @deprecated Legacy — não usar em código novo. Ver Storybook › Legacy.\r\n */\r\nexport function Bolhas({\r\n pontos,\r\n altura = 280,\r\n onClick,\r\n xTitle = 'Active OTs',\r\n yTitle = '% overdue',\r\n tooltipLabel = (p) => `${p.responsavel}: ${p.otsAtivas} active, ${p.percentagemForaPrazo}% overdue, ${euros(p.valorPenalizado)}`,\r\n}: {\r\n pontos: PontoRisco[]\r\n altura?: number\r\n onClick?: (p: PontoRisco) => void\r\n xTitle?: string\r\n yTitle?: string\r\n tooltipLabel?: (p: PontoRisco) => string\r\n}) {\r\n const tema = useTema()\r\n const maxValor = Math.max(1, ...pontos.map((p) => p.valorPenalizado))\r\n return (\r\n <div style={{ height: altura }}>\r\n <Bubble\r\n data={{\r\n datasets: pontos.map((p, i) => ({\r\n label: p.responsavel,\r\n data: [\r\n {\r\n x: p.otsAtivas,\r\n y: p.percentagemForaPrazo,\r\n r: 6 + (p.valorPenalizado / maxValor) * 18,\r\n },\r\n ],\r\n backgroundColor: `${cor(i)}CC`,\r\n borderColor: cor(i),\r\n })),\r\n }}\r\n options={{\r\n maintainAspectRatio: false,\r\n responsive: true,\r\n onClick: (_e, elements) => {\r\n const idx = elements[0]?.datasetIndex\r\n if (idx != null && onClick) onClick(pontos[idx]!)\r\n },\r\n plugins: {\r\n legend: { display: false },\r\n tooltip: {\r\n callbacks: {\r\n label: (c) => tooltipLabel(pontos[c.datasetIndex]!),\r\n },\r\n },\r\n },\r\n scales: {\r\n x: { beginAtZero: true, title: { display: true, text: xTitle, color: tema.texto }, grid: { color: tema.grelha }, ticks: { color: tema.texto } },\r\n y: { beginAtZero: true, title: { display: true, text: yTitle, color: tema.texto }, grid: { color: tema.grelha }, ticks: { color: tema.texto } },\r\n },\r\n }}\r\n />\r\n </div>\r\n )\r\n}\r\n"],"names":["ChartJS"],"mappings":";;;;;;AA4CA,SAAS,MAAM,GAAsC;AACnD,MAAI,KAAK,KAAM,QAAO;AACtB,QAAM,WAAW,IAAI;AACrB,QAAM,CAAC,SAAS,OAAO,IAAI,KAAK,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG;AAC3D,QAAM,cAAc,QAAQ,QAAQ,yBAAyB,GAAG;AAChE,SAAO,GAAG,WAAW,MAAM,EAAE,GAAG,WAAW,IAAI,OAAO;AACxD;AASAA,MAAQ,SAAS,GAAG,eAAe,eAAe;AAElDA,MAAQ,SAAS,IAAI,sBAAsB,EAAE,SAAS,OAAO;AAC7DA,MAAQ,SAAS,KAAK,SAAS;AAC/BA,MAAQ,SAAS,QAAQ;AAMlB,MAAM,SAAS;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,SAAS,IAAI,GAAmB;AACrC,SAAO,OAAO,IAAI,OAAO,MAAM;AACjC;AAMA,SAAS,UAAU;AACjB,QAAM,SAAS,UAAA;AACf,SAAO,SACH,EAAE,OAAO,WAAW,OAAO,WAAW,QAAQ,UAAA,IAC9C,EAAE,OAAO,WAAW,OAAO,WAAW,QAAQ,UAAA;AACpD;AAuCO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAgB;AACd,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,QAAQ,OAAO,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,EAAE,SAAS,OAAO,EAAE,MAAM;AAAA,MAC7E;AAAA,MACA,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,aAAa;AAAA,MACb;AAAA,IAAA;AAAA,EAAA;AAGN;AAMO,SAAS,iBAAiB,EAAE,OAAO,SAAS,KAAK,WAAgF;AACtI,SAAO,oBAAC,QAAA,EAAO,QAAQ,MAAM,QAAQ,QAAQ,MAAM,QAAQ,WAAS,MAAC,QAAgB,SAAkB,SAAO,MAAC;AACjH;AAMO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA,SAAS;AAAA,EACT,SAAS;AAAA,EACT;AACF,GAKG;AACD,QAAM,IAAI,KAAK,IAAI,QAAQ,MAAM,OAAO,MAAM;AAC9C,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,YAAU;AAAA,MACV,QAAQ,MAAM;AAAA,MACd,QAAQ,CAAC,EAAE,MAAM,IAAI,SAAS,MAAM,SAAS;AAAA,MAC7C,OAAO,MAAM,KAAK,EAAE,QAAQ,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC;AAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAAA;AAGN;AAMO,SAAS,KAAK;AAAA,EACnB;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AACF,GAQG;AACD,SAAO,oBAAC,YAAA,EAAW,QAAQ,MAAM,QAAQ,QAAQ,MAAM,SAAS,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,UAAU,SAAkB;AACrI;AAMO,SAAS,MAAM;AAAA,EACpB;AAAA,EACA,SAAS;AAAA,EACT,OAAO,UAAU;AAAA,EACjB;AACF,GAKG;AACD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,QAAQ,MAAM;AAAA,MACd,QAAQ,CAAC,EAAE,MAAM,IAAI,QAAQ,MAAM,SAAS,OAAO,WAAW;AAAA,MAC9D,MAAI;AAAA,MACJ,QAAQ;AAAA,MACR,QAAQ,UAAU,CAAC,MAAM,MAAM,CAAC,IAAI;AAAA,MACpC,QAAQ;AAAA,MACR;AAAA,IAAA;AAAA,EAAA;AAGN;AAOO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA,SAAS;AAAA,EACT,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAaG;AACD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,QAAQ,MAAM;AAAA,MACd,QAAQ,MAAM,OAAO,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,EAAE,UAAU;AAAA,MACrE;AAAA,MACA,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,QAAM;AAAA,MACN;AAAA,IAAA;AAAA,EAAA;AAGN;AAmBO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA,SAAS;AAAA,EACT,SAAS;AAAA,EACT,eAAe,CAAC,MAAM,GAAG,EAAE,WAAW,KAAK,EAAE,SAAS,YAAY,EAAE,oBAAoB,cAAc,MAAM,EAAE,eAAe,CAAC;AAChI,GAOG;AACD,QAAM,OAAO,QAAA;AACb,QAAM,WAAW,KAAK,IAAI,GAAG,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC;AACpE,6BACG,OAAA,EAAI,OAAO,EAAE,QAAQ,UACpB,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAM;AAAA,QACJ,UAAU,OAAO,IAAI,CAAC,GAAG,OAAO;AAAA,UAC9B,OAAO,EAAE;AAAA,UACT,MAAM;AAAA,YACJ;AAAA,cACE,GAAG,EAAE;AAAA,cACL,GAAG,EAAE;AAAA,cACL,GAAG,IAAK,EAAE,kBAAkB,WAAY;AAAA,YAAA;AAAA,UAC1C;AAAA,UAEF,iBAAiB,GAAG,IAAI,CAAC,CAAC;AAAA,UAC1B,aAAa,IAAI,CAAC;AAAA,QAAA,EAClB;AAAA,MAAA;AAAA,MAEJ,SAAS;AAAA,QACP,qBAAqB;AAAA,QACrB,YAAY;AAAA,QACZ,SAAS,CAAC,IAAI,aAAa;AACzB,gBAAM,MAAM,SAAS,CAAC,GAAG;AACzB,cAAI,OAAO,QAAQ,QAAS,SAAQ,OAAO,GAAG,CAAE;AAAA,QAClD;AAAA,QACA,SAAS;AAAA,UACP,QAAQ,EAAE,SAAS,MAAA;AAAA,UACnB,SAAS;AAAA,YACP,WAAW;AAAA,cACT,OAAO,CAAC,MAAM,aAAa,OAAO,EAAE,YAAY,CAAE;AAAA,YAAA;AAAA,UACpD;AAAA,QACF;AAAA,QAEF,QAAQ;AAAA,UACN,GAAG,EAAE,aAAa,MAAM,OAAO,EAAE,SAAS,MAAM,MAAM,QAAQ,OAAO,KAAK,SAAS,MAAM,EAAE,OAAO,KAAK,OAAA,GAAU,OAAO,EAAE,OAAO,KAAK,QAAM;AAAA,UAC5I,GAAG,EAAE,aAAa,MAAM,OAAO,EAAE,SAAS,MAAM,MAAM,QAAQ,OAAO,KAAK,SAAS,MAAM,EAAE,OAAO,KAAK,UAAU,OAAO,EAAE,OAAO,KAAK,MAAA,EAAM;AAAA,QAAE;AAAA,MAChJ;AAAA,IACF;AAAA,EAAA,GAEJ;AAEJ;"}
|
|
@@ -37,7 +37,9 @@ const DEFAULT_LABELS = {
|
|
|
37
37
|
clearGroups: "Clear grouping",
|
|
38
38
|
perPage: "Per page",
|
|
39
39
|
selectAll: "(Select all)",
|
|
40
|
-
selectAllResults: "(Select results)"
|
|
40
|
+
selectAllResults: "(Select results)",
|
|
41
|
+
cancel: "Cancel",
|
|
42
|
+
confirm: "Confirm"
|
|
41
43
|
};
|
|
42
44
|
const Funnel = ({ size = 12, className }) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx("path", { d: "M22 3H2l8 9.46V19l4 2v-8.54L22 3z" }) });
|
|
43
45
|
const Layers = ({ size = 11, className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
@@ -136,14 +138,18 @@ function valorParaIntervalo(row, col) {
|
|
|
136
138
|
const v = rawValue(row, col);
|
|
137
139
|
return col.sortType === "date" ? timestampDeData(v) : Number(v);
|
|
138
140
|
}
|
|
141
|
+
function csvValue(row, col) {
|
|
142
|
+
const v = rawValue(row, col);
|
|
143
|
+
if (v == null) return "";
|
|
144
|
+
if (typeof v === "number") return Number.isInteger(v) ? String(v) : String(v).replace(".", ",");
|
|
145
|
+
return v === "[object Object]" ? "" : v;
|
|
146
|
+
}
|
|
139
147
|
function toCsv(columns, rows) {
|
|
140
|
-
const esc = (
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const body = rows.map((r) => columns.map((c) => esc(rawValue(r, c))).join(",")).join("\n");
|
|
146
|
-
return `${head}
|
|
148
|
+
const esc = (s) => /[";\n\r]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
|
|
149
|
+
const cols = columns.filter((c) => rows.some((r) => csvValue(r, c) !== ""));
|
|
150
|
+
const head = cols.map((c) => esc(c.label)).join(";");
|
|
151
|
+
const body = rows.map((r) => cols.map((c) => esc(csvValue(r, c))).join(";")).join("\r\n");
|
|
152
|
+
return `${head}\r
|
|
147
153
|
${body}`;
|
|
148
154
|
}
|
|
149
155
|
const ordenarRotulos = (a, b) => a === EMPTY ? 1 : b === EMPTY ? -1 : COLLATOR.compare(a, b);
|
|
@@ -308,6 +314,10 @@ function DataTable({
|
|
|
308
314
|
const [selectedKeys, setSelectedKeys] = useState(() => new Set(selecaoInicial ?? []));
|
|
309
315
|
const [openFilter, setOpenFilter] = useState(null);
|
|
310
316
|
const [filterSearch, setFilterSearch] = useState("");
|
|
317
|
+
const [rascunho, setRascunho] = useState(null);
|
|
318
|
+
useEffect(() => {
|
|
319
|
+
setRascunho(null);
|
|
320
|
+
}, [openFilter]);
|
|
311
321
|
const filterRefs = useRef(/* @__PURE__ */ new Map());
|
|
312
322
|
const popupRef = useRef(null);
|
|
313
323
|
const [popupPos, setPopupPos] = useState(null);
|
|
@@ -666,8 +676,17 @@ function DataTable({
|
|
|
666
676
|
if (!allData) onDataNeeded?.();
|
|
667
677
|
setSort((s) => s?.key === key ? s.dir === 1 ? { key, dir: -1 } : null : { key, dir: 1 });
|
|
668
678
|
};
|
|
669
|
-
const selecaoDaColuna = (key) => new Set(columnFilters[key] ?? (modoExcel ? openFilterOptions : []));
|
|
670
|
-
const aplicarSelecao = (key, sel) =>
|
|
679
|
+
const selecaoDaColuna = (key) => new Set(rascunho?.key === key ? rascunho.sel : columnFilters[key] ?? (modoExcel ? openFilterOptions : []));
|
|
680
|
+
const aplicarSelecao = (key, sel) => setRascunho({ key, sel });
|
|
681
|
+
const confirmarSelecao = (key) => {
|
|
682
|
+
if (rascunho?.key === key) {
|
|
683
|
+
if (!allData) onDataNeeded?.();
|
|
684
|
+
gravarSelecao(key, rascunho.sel);
|
|
685
|
+
}
|
|
686
|
+
setOpenFilter(null);
|
|
687
|
+
setFilterSearch("");
|
|
688
|
+
};
|
|
689
|
+
const gravarSelecao = (key, sel) => mudarFiltrosCol((prev) => {
|
|
671
690
|
const proximo = { ...prev };
|
|
672
691
|
if (modoExcel && sel.size === openFilterOptions.length) delete proximo[key];
|
|
673
692
|
else proximo[key] = sel;
|
|
@@ -703,6 +722,7 @@ function DataTable({
|
|
|
703
722
|
});
|
|
704
723
|
};
|
|
705
724
|
const clearColumnFilter = (key) => {
|
|
725
|
+
setRascunho(null);
|
|
706
726
|
mudarFiltrosCol((prev) => {
|
|
707
727
|
const n = { ...prev };
|
|
708
728
|
delete n[key];
|
|
@@ -724,8 +744,9 @@ function DataTable({
|
|
|
724
744
|
};
|
|
725
745
|
const temFiltro = (key) => (modoExcel ? columnFilters[key] !== void 0 : (columnFilters[key]?.size ?? 0) > 0) || temIntervalo(key);
|
|
726
746
|
const handleExport = () => {
|
|
727
|
-
|
|
728
|
-
|
|
747
|
+
const linhas = allData && !isClientMode ? ordenar(filtrar(allData)) : sorted;
|
|
748
|
+
if (onExport) return onExport(linhas);
|
|
749
|
+
const csv = toCsv(columns, linhas);
|
|
729
750
|
const blob = new Blob([`\uFEFF${csv}`], { type: "text/csv;charset=utf-8;" });
|
|
730
751
|
const url = URL.createObjectURL(blob);
|
|
731
752
|
const a = document.createElement("a");
|
|
@@ -789,7 +810,7 @@ function DataTable({
|
|
|
789
810
|
const renderPopup = (coluna, key, listas) => {
|
|
790
811
|
const col = key === coluna.key ? coluna : void 0;
|
|
791
812
|
const { opts, total: totalOpcoes } = opcoesVisiveis;
|
|
792
|
-
const sel = columnFilters[key];
|
|
813
|
+
const sel = rascunho?.key === key ? rascunho.sel : columnFilters[key];
|
|
793
814
|
const isFiltered = temFiltro(key);
|
|
794
815
|
const podeOrdenar = !!sortFromFilter && !!col && col.sortable !== false;
|
|
795
816
|
const eData = col?.sortType === "date";
|
|
@@ -898,6 +919,12 @@ function DataTable({
|
|
|
898
919
|
autoFocus: true,
|
|
899
920
|
value: filterSearch,
|
|
900
921
|
onChange: (e) => setFilterSearch(e.target.value),
|
|
922
|
+
onKeyDown: (e) => {
|
|
923
|
+
if (e.key === "Enter") {
|
|
924
|
+
e.preventDefault();
|
|
925
|
+
confirmarSelecao(key);
|
|
926
|
+
}
|
|
927
|
+
},
|
|
901
928
|
placeholder: L.search,
|
|
902
929
|
className: "w-full bg-slate-50 dark:bg-slate-800 dark:text-slate-100 border border-slate-200 dark:border-slate-700 rounded-lg px-2 py-1.5 text-xs outline-none focus:border-proef-blue dark:focus:border-proef-turquoise mb-2"
|
|
903
930
|
}
|
|
@@ -951,14 +978,38 @@ function DataTable({
|
|
|
951
978
|
})
|
|
952
979
|
] }),
|
|
953
980
|
totalOpcoes > opts.length && /* @__PURE__ */ jsx("p", { className: "text-[10.5px] text-slate-400 text-center pt-2", children: L.moreOptions.replace("{shown}", String(opts.length)).replace("{total}", String(totalOpcoes)) }),
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
981
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-2 pt-2 border-t border-slate-100 dark:border-slate-800", children: [
|
|
982
|
+
isFiltered && /* @__PURE__ */ jsx(
|
|
983
|
+
"button",
|
|
984
|
+
{
|
|
985
|
+
type: "button",
|
|
986
|
+
onClick: () => clearColumnFilter(key),
|
|
987
|
+
className: "appearance-none bg-transparent border-0 cursor-pointer text-[10px] font-black uppercase tracking-wider text-red-400 hover:text-red-500",
|
|
988
|
+
children: L.clear
|
|
989
|
+
}
|
|
990
|
+
),
|
|
991
|
+
/* @__PURE__ */ jsx(
|
|
992
|
+
"button",
|
|
993
|
+
{
|
|
994
|
+
type: "button",
|
|
995
|
+
onClick: () => {
|
|
996
|
+
setOpenFilter(null);
|
|
997
|
+
setFilterSearch("");
|
|
998
|
+
},
|
|
999
|
+
className: "appearance-none bg-transparent border-0 cursor-pointer ml-auto text-[10px] font-black uppercase tracking-wider text-slate-400 hover:text-slate-600 dark:hover:text-slate-200",
|
|
1000
|
+
children: L.cancel
|
|
1001
|
+
}
|
|
1002
|
+
),
|
|
1003
|
+
/* @__PURE__ */ jsx(
|
|
1004
|
+
"button",
|
|
1005
|
+
{
|
|
1006
|
+
type: "button",
|
|
1007
|
+
onClick: () => confirmarSelecao(key),
|
|
1008
|
+
className: "appearance-none border-0 cursor-pointer rounded-lg bg-proef-navy dark:bg-proef-turquoise px-3 py-1.5 text-[10px] font-black uppercase tracking-wider text-white dark:text-proef-navy hover:bg-proef-blue dark:hover:opacity-90",
|
|
1009
|
+
children: L.confirm
|
|
1010
|
+
}
|
|
1011
|
+
)
|
|
1012
|
+
] })
|
|
962
1013
|
] })
|
|
963
1014
|
]
|
|
964
1015
|
}
|
|
@@ -1085,13 +1136,19 @@ function DataTable({
|
|
|
1085
1136
|
/* @__PURE__ */ jsx("span", { className: "text-xs text-slate-500 dark:text-slate-400", children: isLoading ? "" : L.results.replace("{count}", String(totalResultados)) }),
|
|
1086
1137
|
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex flex-wrap items-center justify-end gap-2", children: [
|
|
1087
1138
|
extraToolbar,
|
|
1088
|
-
exportFileName && sorted.length > 0 &&
|
|
1139
|
+
exportFileName && sorted.length > 0 && // Mesmo aspeto do botão Colunas ao lado (o navy cheio competia com as ações da página).
|
|
1140
|
+
/* @__PURE__ */ jsxs(
|
|
1089
1141
|
"button",
|
|
1090
1142
|
{
|
|
1143
|
+
type: "button",
|
|
1091
1144
|
onClick: handleExport,
|
|
1092
|
-
className: "appearance-none cursor-pointer inline-flex items-center gap-
|
|
1145
|
+
className: "appearance-none cursor-pointer bg-white inline-flex items-center gap-2 h-8 rounded-lg border border-slate-300 px-3 text-xs font-medium text-slate-700 transition hover:bg-slate-50 dark:bg-slate-800 dark:border-slate-600 dark:text-slate-200 dark:hover:bg-slate-700",
|
|
1093
1146
|
children: [
|
|
1094
|
-
"
|
|
1147
|
+
/* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", className: "h-4 w-4", "aria-hidden": true, children: [
|
|
1148
|
+
/* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
1149
|
+
/* @__PURE__ */ jsx("polyline", { points: "7 10 12 15 17 10" }),
|
|
1150
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
|
|
1151
|
+
] }),
|
|
1095
1152
|
L.export
|
|
1096
1153
|
]
|
|
1097
1154
|
}
|