@bluemarble/bi 0.3.0 → 0.4.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.
@@ -1,5 +1,5 @@
1
- import { f as isBuiltinChart, o as chartCardStyle, u as customChartProps } from "../layout-DTR4vI-I.js";
2
- import { a as useDashboard, c as layoutItemKey, i as DashboardProvider, n as INSPECT_ATTRIBUTE, r as useModelQuery, s as LAYOUT_ITEM_ATTRIBUTE, t as ModelDictionary } from "../ModelDictionary-CBILYbZ1.js";
1
+ import { f as isBuiltinChart, o as chartCardStyle, u as customChartProps } from "../layout-676sEvvb.js";
2
+ import { a as useDashboard, c as layoutItemKey, i as DashboardProvider, n as INSPECT_ATTRIBUTE, r as useModelQuery, s as LAYOUT_ITEM_ATTRIBUTE, t as ModelDictionary } from "../ModelDictionary-Y7W9oK1J.js";
3
3
  import { Box, Checkbox, CircularProgress, FormControl, InputLabel, ListItemText, MenuItem, OutlinedInput, Paper, Select, Table, TableBody, TableCell, TableHead, TableRow, TableSortLabel, Typography } from "@mui/material";
4
4
  import { Bar, BarChart as BarChart$1, CartesianGrid, Cell, ComposedChart, LabelList, Line, Pie, PieChart, ResponsiveContainer, Tooltip as Tooltip$1, XAxis, YAxis } from "recharts";
5
5
  import { createContext, useContext, useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
@@ -95,7 +95,8 @@ function chartPlaceholder({ height, error, isLoading, empty }) {
95
95
  children: error ? "Erro ao carregar o gráfico" : isLoading ? "Carregando…" : "Sem dados para os filtros selecionados"
96
96
  });
97
97
  }
98
- function TooltipBox({ title, children }) {
98
+ /** `caption`: o que é o título (ex.: o rótulo da dimensão), em cinza acima dele. */
99
+ function TooltipBox({ title, caption, children }) {
99
100
  return /* @__PURE__ */ jsxs(Box, {
100
101
  sx: {
101
102
  bgcolor: "#fff",
@@ -103,53 +104,90 @@ function TooltipBox({ title, children }) {
103
104
  p: 1,
104
105
  fontSize: 13
105
106
  },
106
- children: [/* @__PURE__ */ jsx(Box, {
107
- sx: { fontWeight: 700 },
108
- children: title
109
- }), children]
107
+ children: [
108
+ caption && /* @__PURE__ */ jsx(Box, {
109
+ sx: {
110
+ fontSize: 11,
111
+ color: "#777"
112
+ },
113
+ children: caption
114
+ }),
115
+ /* @__PURE__ */ jsx(Box, {
116
+ sx: { fontWeight: 700 },
117
+ children: title
118
+ }),
119
+ children
120
+ ]
110
121
  });
111
122
  }
112
123
  //#endregion
113
124
  //#region src/client/format.ts
114
125
  const formatters = /* @__PURE__ */ new Map();
115
- function formatNumber(value, decimals = 2) {
126
+ /** `compact`: notação curta do pt-BR (1,2 mil / 3,4 mi / 5,6 bi). */
127
+ function formatNumber(value, decimals = 2, compact = false) {
116
128
  if (value === null || value === void 0 || value === "") return "";
117
129
  const number = Number(value);
118
130
  if (Number.isNaN(number)) return String(value);
119
- let formatter = formatters.get(decimals);
131
+ const key = `${decimals}:${compact}`;
132
+ let formatter = formatters.get(key);
120
133
  if (!formatter) {
121
134
  formatter = new Intl.NumberFormat("pt-BR", {
122
135
  minimumFractionDigits: decimals,
123
- maximumFractionDigits: decimals
136
+ maximumFractionDigits: decimals,
137
+ ...compact && { notation: "compact" }
124
138
  });
125
- formatters.set(decimals, formatter);
139
+ formatters.set(key, formatter);
126
140
  }
127
141
  return formatter.format(number);
128
142
  }
129
- const formatCurrency = (value, decimals = 2) => {
130
- const text = formatNumber(value, decimals);
143
+ const formatCurrency = (value, decimals = 2, compact = false) => {
144
+ const text = formatNumber(value, decimals, compact);
131
145
  return text && `R$ ${text}`;
132
146
  };
133
147
  /**
134
- * Formata pelo dicionário do modelo (`format`/`decimals` da medida). `fallbackDecimals` é o padrão
135
- * do componente quando a medida não define `decimals`.
148
+ * Formata pelo dicionário do modelo (`format`/`decimals` da medida) ou pelo formato do gráfico.
149
+ * `fallbackDecimals` é o padrão do componente quando nenhum dos dois define `decimals`.
136
150
  */
137
151
  function formatMeasure(value, meta, fallbackDecimals = 2) {
152
+ if (value === null || value === void 0 || value === "") return "";
138
153
  const decimals = meta?.decimals ?? (meta?.format === "integer" ? 0 : fallbackDecimals);
154
+ const compact = meta?.compact ?? false;
155
+ let text;
139
156
  switch (meta?.format) {
140
- case "currency": return formatCurrency(value, decimals);
157
+ case "currency":
158
+ text = formatCurrency(value, decimals, compact);
159
+ break;
141
160
  case "percent": {
142
- if (value === null || value === void 0 || value === "") return "";
143
- const text = formatNumber(Number(value) * 100, decimals);
144
- return text && `${text}%`;
161
+ const number = formatNumber(Number(value) * 100, decimals, compact);
162
+ text = number && `${number}%`;
163
+ break;
145
164
  }
146
- default: return formatNumber(value, decimals);
165
+ default: text = formatNumber(value, decimals, compact);
147
166
  }
167
+ return text && `${meta?.prefix ?? ""}${text}${meta?.suffix ?? ""}`;
148
168
  }
149
- /** Formatter de uma medida pelo dicionário do modelo; sem `format`, número com `fallbackDecimals`. */
150
- function measureFormatter(meta, measure, fallbackDecimals = 2) {
151
- const measureMeta = meta?.measures[measure];
152
- return (value) => formatMeasure(value, measureMeta, fallbackDecimals);
169
+ /** Dicionário do modelo com o formato do gráfico por cima. */
170
+ function measureFormat(meta, measure, formats) {
171
+ const fromModel = meta?.measures[measure];
172
+ const fromChart = formats?.[measure];
173
+ if (!fromChart) return fromModel;
174
+ return {
175
+ ...fromModel?.format !== void 0 && { format: fromModel.format },
176
+ ...fromModel?.decimals !== void 0 && { decimals: fromModel.decimals },
177
+ ...fromChart
178
+ };
179
+ }
180
+ /**
181
+ * Formatter de uma medida: o `formats` do gráfico (se houver) por cima do dicionário do modelo; sem
182
+ * `format`, número com `fallbackDecimals`.
183
+ */
184
+ function measureFormatter(meta, measure, fallbackDecimals = 2, formats) {
185
+ const format = measureFormat(meta, measure, formats);
186
+ return (value) => formatMeasure(value, format, fallbackDecimals);
187
+ }
188
+ /** Rótulo de uma dimensão/medida: o `labels` do gráfico, o dicionário do modelo ou o nome. */
189
+ function fieldLabel(meta, name, labels) {
190
+ return labels?.[name] || meta?.dimensions[name]?.label || meta?.measures[name]?.label || name;
153
191
  }
154
192
  //#endregion
155
193
  //#region src/client/BarChart.tsx
@@ -160,7 +198,7 @@ const ROW_HEIGHT = 28;
160
198
  * Barras de uma ou mais medidas por uma dimensão. Ex.:
161
199
  * `<BarChart dimension="navio" measures={['custoTotal']} orientation="horizontal" sort="desc" limit={10} />`.
162
200
  */
163
- function BarChart({ dimension, measures, orientation = "vertical", stacked = false, sort = "dimension", limit, formatDimension = String, hideEmpty = true, showValues = true, clickToFilter = false, height = 360, queryLabel }) {
201
+ function BarChart({ dimension, measures, orientation = "vertical", stacked = false, sort = "dimension", limit, formatDimension = String, hideEmpty = true, showValues = true, clickToFilter = false, height = 360, labels, formats: formatsByMeasure, queryLabel }) {
164
202
  const { meta } = useDashboard();
165
203
  const { rows, isLoading, error, inspectProps } = useModelQuery({
166
204
  dimensions: [dimension],
@@ -169,8 +207,13 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
169
207
  label: queryLabel ?? `BarChart · ${dimension}`
170
208
  });
171
209
  const filter = useClickFilter(dimension, clickToFilter);
172
- const formats = measures.map((measure) => measureFormatter(meta, measure, 0));
173
- const labelOf = (measure) => meta?.measures[measure]?.label ?? measure;
210
+ const formats = measures.map((measure) => measureFormatter(meta, measure, 0, formatsByMeasure));
211
+ const labelOf = (name) => fieldLabel(meta, name, labels);
212
+ const axisFormat = measures[0] ? measureFormat(meta, measures[0], formatsByMeasure) : void 0;
213
+ const formatTick = (value) => formatMeasure(value, {
214
+ ...axisFormat,
215
+ decimals: axisFormat?.compact ? 1 : 0
216
+ }, 0);
174
217
  const first = measures[0];
175
218
  let data = rows.filter((row) => !hideEmpty || measures.some((measure) => numberOf(row, measure))).map((row) => {
176
219
  const value = row[dimension] ?? "";
@@ -184,7 +227,7 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
184
227
  if (sort !== "dimension" && first) data = [...data].sort((a, b) => sort === "desc" ? Number(b[first]) - Number(a[first]) : Number(a[first]) - Number(b[first]));
185
228
  if (limit) data = data.slice(0, limit);
186
229
  const horizontal = orientation === "horizontal";
187
- const labels = showValues && data.length <= MAX_VALUE_LABELS;
230
+ const showLabels = showValues && data.length <= MAX_VALUE_LABELS;
188
231
  const chartHeight = horizontal ? Math.max(height, data.length * ROW_HEIGHT + 24) : height;
189
232
  const longest = Math.max(0, ...data.map((point) => point.label.length));
190
233
  const state = chartPlaceholder({
@@ -198,6 +241,7 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
198
241
  const point = payload[0].payload;
199
242
  return /* @__PURE__ */ jsx(TooltipBox, {
200
243
  title: point.label,
244
+ caption: labelOf(dimension),
201
245
  children: measures.map((measure, index) => /* @__PURE__ */ jsxs(Box, {
202
246
  sx: {
203
247
  display: "flex",
@@ -271,11 +315,11 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
271
315
  barCategoryGap: "20%",
272
316
  margin: horizontal ? {
273
317
  top: 4,
274
- right: labels ? 96 : 16,
318
+ right: showLabels ? 96 : 16,
275
319
  left: 8,
276
320
  bottom: 4
277
321
  } : {
278
- top: labels ? 24 : 8,
322
+ top: showLabels ? 24 : 8,
279
323
  right: 8,
280
324
  left: 8,
281
325
  bottom: 0
@@ -288,11 +332,12 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
288
332
  }),
289
333
  horizontal ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(XAxis, {
290
334
  type: "number",
291
- hide: labels,
335
+ hide: showLabels,
292
336
  tick: {
293
337
  fontSize: 12,
294
338
  fill: "#555"
295
- }
339
+ },
340
+ tickFormatter: formatTick
296
341
  }), /* @__PURE__ */ jsx(YAxis, {
297
342
  type: "category",
298
343
  dataKey: "label",
@@ -314,12 +359,12 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
314
359
  tickLine: false,
315
360
  axisLine: { stroke: "#ccc" }
316
361
  }), /* @__PURE__ */ jsx(YAxis, {
317
- hide: labels,
362
+ hide: showLabels,
318
363
  tick: {
319
364
  fontSize: 12,
320
365
  fill: "#555"
321
366
  },
322
- tickFormatter: (value) => formatNumber(value, 0),
367
+ tickFormatter: formatTick,
323
368
  width: 72
324
369
  })] }),
325
370
  /* @__PURE__ */ jsx(Tooltip$1, {
@@ -336,7 +381,7 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
336
381
  isAnimationActive: false,
337
382
  onClick: clickToFilter ? (_bar, barIndex, event) => handleClick(barIndex, event) : void 0,
338
383
  cursor: clickToFilter ? "pointer" : void 0,
339
- children: [clickToFilter && data.map((point) => /* @__PURE__ */ jsx(Cell, { fillOpacity: filter.isDimmed(point.value) ? .35 : 1 }, String(point.value))), labels && !stacked && /* @__PURE__ */ jsx(LabelList, {
384
+ children: [clickToFilter && data.map((point) => /* @__PURE__ */ jsx(Cell, { fillOpacity: filter.isDimmed(point.value) ? .35 : 1 }, String(point.value))), showLabels && !stacked && /* @__PURE__ */ jsx(LabelList, {
340
385
  dataKey: measure,
341
386
  position: horizontal ? "right" : "top",
342
387
  formatter: (value) => formats[index]?.(value) ?? "",
@@ -365,18 +410,26 @@ const lineDomain = ([min, max]) => {
365
410
  * Barras + linha de uma dimensão, consultando o modelo do `DashboardProvider` (com os filtros dele).
366
411
  * Ex.: `<ComboChart dimension="mes" bar="custoTotal" line="custoTon" detail="volTotal" />`.
367
412
  */
368
- function ComboChart({ dimension, bar, line, detail, barLabel, lineLabel, detailLabel, formatDimension = String, formatBar, formatLine, formatDetail, hideEmpty = true, height = 360, maxLabels = 24, barColor = "#F58220", lineColor = "#555", clickToFilter = false, queryLabel }) {
413
+ function ComboChart({ dimension, bar, line, detail, barLabel, lineLabel, detailLabel, formatDimension = String, formatBar, formatLine, formatDetail, labels, formats, hideEmpty = true, height = 360, maxLabels = 24, barColor = "#F58220", lineColor = "#555", clickToFilter = false, queryLabel }) {
369
414
  const { meta, filters, setFilter } = useDashboard();
370
- const fromModel = (measure, decimals, fallback) => {
371
- const measureMeta = meta?.measures[measure];
372
- return measureMeta?.format ? (value) => formatMeasure(value, measureMeta, decimals) : fallback;
415
+ const fromModel = (measure, fallback) => {
416
+ const format = measureFormat(meta, measure, formats);
417
+ const resolved = format?.format ? format : {
418
+ ...fallback,
419
+ ...format
420
+ };
421
+ return (value) => formatMeasure(value, resolved, fallback.decimals);
373
422
  };
374
- formatBar ??= fromModel(bar, 0, (value) => formatCurrency(value, 0));
375
- formatLine ??= fromModel(line, 2, (value) => formatNumber(value, 2));
376
- formatDetail ??= detail ? fromModel(detail, 3, (value) => formatNumber(value, 3)) : (value) => formatNumber(value, 3);
377
- barLabel ??= meta?.measures[bar]?.label ?? bar;
378
- lineLabel ??= meta?.measures[line]?.label ?? line;
379
- detailLabel ??= detail && (meta?.measures[detail]?.label ?? detail);
423
+ formatBar ??= fromModel(bar, {
424
+ format: "currency",
425
+ decimals: 0
426
+ });
427
+ formatLine ??= fromModel(line, { decimals: 2 });
428
+ formatDetail ??= detail ? fromModel(detail, { decimals: 3 }) : (value) => formatNumber(value, 3);
429
+ barLabel ??= fieldLabel(meta, bar, labels);
430
+ lineLabel ??= fieldLabel(meta, line, labels);
431
+ detailLabel ??= detail && fieldLabel(meta, detail, labels);
432
+ const dimensionLabel = fieldLabel(meta, dimension, labels);
380
433
  const { rows, isLoading, error, inspectProps } = useModelQuery({
381
434
  dimensions: [dimension],
382
435
  measures: detail ? [
@@ -467,6 +520,13 @@ function ComboChart({ dimension, bar, line, detail, barLabel, lineLabel, detailL
467
520
  fontSize: 13
468
521
  },
469
522
  children: [
523
+ /* @__PURE__ */ jsx(Typography, {
524
+ sx: {
525
+ fontSize: 11,
526
+ color: "#777"
527
+ },
528
+ children: dimensionLabel
529
+ }),
470
530
  /* @__PURE__ */ jsx(Typography, {
471
531
  sx: {
472
532
  fontWeight: 700,
@@ -716,7 +776,6 @@ function DashboardCanvas({ layout, children }) {
716
776
  const EMPTY = [];
717
777
  /** Chave da coluna de percentual de uma medida (ordenação). */
718
778
  const PERCENT = "%:";
719
- const formatPercent = (value) => value === null ? "" : `${formatNumber(value * 100, 1)}%`;
720
779
  function compare(a, b) {
721
780
  if (typeof a === "number" && typeof b === "number") return a - b;
722
781
  return String(a).localeCompare(String(b), "pt-BR", { numeric: true });
@@ -725,7 +784,7 @@ function compare(a, b) {
725
784
  * Tabela de medidas por dimensões, com total e ordenação pelo cabeçalho. Ex.:
726
785
  * `<DataTable dimensions={['navio']} measures={['volTotal', 'custoTotal', 'custoTon']} />`.
727
786
  */
728
- function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDimensions = {}, showTotal = true, sortBy, sortDirection = "desc", clickToFilter = false, height = 400, queryLabel }) {
787
+ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDimensions = {}, showTotal = true, sortBy, sortDirection = "desc", clickToFilter = false, height = 400, labels, formats: formatsByMeasure, percentDecimals = 1, queryLabel }) {
729
788
  const { meta } = useDashboard();
730
789
  const name = queryLabel ?? `DataTable · ${dimensions.join(", ") || "total"}`;
731
790
  const firstDimension = dimensions[0];
@@ -763,9 +822,10 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
763
822
  if (y === null || y === void 0) return -1;
764
823
  return sort.direction === "asc" ? compare(x, y) : compare(y, x);
765
824
  }) : rows;
766
- const formats = Object.fromEntries(measures.map((measure) => [measure, measureFormatter(meta, measure, 2)]));
825
+ const formats = Object.fromEntries(measures.map((measure) => [measure, measureFormatter(meta, measure, 2, formatsByMeasure)]));
826
+ const formatPercent = (value) => value === null ? "" : `${formatNumber(value * 100, percentDecimals)}%`;
767
827
  const dimensionText = (dimension, value) => value === null || value === void 0 ? "(vazio)" : (formatDimensions[dimension] ?? String)(value);
768
- const labelOf = (column) => meta?.dimensions[column]?.label ?? meta?.measures[column]?.label ?? column;
828
+ const labelOf = (column) => fieldLabel(meta, column, labels);
769
829
  const headerOf = (column) => {
770
830
  if (!column.startsWith(PERCENT)) return labelOf(column);
771
831
  const measure = column.slice(2);
@@ -874,7 +934,7 @@ const OTHERS = "Outros";
874
934
  * Rosca de uma medida por uma dimensão, com o total no centro e a legenda ao lado (nome, % e valor).
875
935
  * Ex.: `<DonutChart dimension="operacao_status" measure="custoTotal" />`.
876
936
  */
877
- function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = String, clickToFilter = false, height = 300, queryLabel }) {
937
+ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = String, clickToFilter = false, height = 300, labels, formats, percentDecimals = 1, queryLabel }) {
878
938
  const { meta } = useDashboard();
879
939
  const { rows, isLoading, error, inspectProps } = useModelQuery({
880
940
  dimensions: [dimension],
@@ -883,7 +943,7 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
883
943
  label: queryLabel ?? `DonutChart · ${dimension}`
884
944
  });
885
945
  const filter = useClickFilter(dimension, clickToFilter);
886
- const format = measureFormatter(meta, measure, 0);
946
+ const format = measureFormatter(meta, measure, 0, formats);
887
947
  const positive = rows.map((row) => ({
888
948
  value: row[dimension] ?? "",
889
949
  amount: numberOf(row, measure) ?? 0
@@ -906,7 +966,7 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
906
966
  color: OTHER_COLOR
907
967
  });
908
968
  const total = slices.reduce((sum, slice) => sum + slice.amount, 0);
909
- const percent = (amount) => `${formatNumber(amount / total * 100, 1)}%`;
969
+ const percent = (amount) => `${formatNumber(amount / total * 100, percentDecimals)}%`;
910
970
  const placeholder = chartPlaceholder({
911
971
  height,
912
972
  error,
@@ -922,7 +982,10 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
922
982
  const slice = payload[0].payload;
923
983
  return /* @__PURE__ */ jsxs(TooltipBox, {
924
984
  title: slice.label,
985
+ caption: fieldLabel(meta, dimension, labels),
925
986
  children: [
987
+ fieldLabel(meta, measure, labels),
988
+ ": ",
926
989
  format(slice.amount),
927
990
  " · ",
928
991
  percent(slice.amount)
@@ -1067,7 +1130,7 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
1067
1130
  * dimensões: razões (custo/t) saem do total, não de uma média. Ex.:
1068
1131
  * `<KpiCard label="Custo total" measure="custoTotal" secondary="custoTon" />`.
1069
1132
  */
1070
- function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
1133
+ function KpiCard({ measure, label, secondary, secondaryLabel, labels, formats, queryLabel }) {
1071
1134
  const { meta } = useDashboard();
1072
1135
  const { rows, isLoading, error, inspectProps } = useModelQuery({
1073
1136
  measures: secondary ? [measure, secondary] : [measure],
@@ -1076,6 +1139,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
1076
1139
  const row = rows[0];
1077
1140
  const value = row ? numberOf(row, measure) : null;
1078
1141
  const extra = row && secondary ? numberOf(row, secondary) : null;
1142
+ label ??= labels?.[measure];
1079
1143
  return /* @__PURE__ */ jsxs(Box, {
1080
1144
  ...inspectProps,
1081
1145
  sx: {
@@ -1112,7 +1176,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
1112
1176
  opacity: isLoading ? .5 : 1,
1113
1177
  transition: "opacity .2s"
1114
1178
  },
1115
- children: error ? "Erro" : value === null ? "—" : measureFormatter(meta, measure, 0)(value)
1179
+ children: error ? "Erro" : value === null ? "—" : measureFormatter(meta, measure, 0, formats)(value)
1116
1180
  }),
1117
1181
  secondary && /* @__PURE__ */ jsxs(Box, {
1118
1182
  sx: {
@@ -1122,7 +1186,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
1122
1186
  minHeight: 20
1123
1187
  },
1124
1188
  children: [
1125
- secondaryLabel ?? meta?.measures[secondary]?.label ?? secondary,
1189
+ secondaryLabel ?? fieldLabel(meta, secondary, labels),
1126
1190
  ":",
1127
1191
  " ",
1128
1192
  /* @__PURE__ */ jsx(Box, {
@@ -1131,7 +1195,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
1131
1195
  fontWeight: 600,
1132
1196
  color: "#444"
1133
1197
  },
1134
- children: extra === null ? "—" : measureFormatter(meta, secondary, 2)(extra)
1198
+ children: extra === null ? "—" : measureFormatter(meta, secondary, 2, formats)(extra)
1135
1199
  })
1136
1200
  ]
1137
1201
  })
@@ -1364,6 +1428,6 @@ function DashboardFilters({ layout, formatters = {}, gap = 2 }) {
1364
1428
  });
1365
1429
  }
1366
1430
  //#endregion
1367
- export { BarChart, ComboChart, DashboardCanvas, DashboardCharts, DashboardFilters, DashboardProvider, DataTable, DonutChart, FilterSelect, INSPECT_ATTRIBUTE, KpiCard, Legend, ModelDictionary, OTHER_COLOR, SERIES_COLORS, TooltipBox, chartPlaceholder, formatCurrency, formatMeasure, formatNumber, measureFormatter, numberOf, seriesColor, useClickFilter, useDashboard, useModelQuery };
1431
+ export { BarChart, ComboChart, DashboardCanvas, DashboardCharts, DashboardFilters, DashboardProvider, DataTable, DonutChart, FilterSelect, INSPECT_ATTRIBUTE, KpiCard, Legend, ModelDictionary, OTHER_COLOR, SERIES_COLORS, TooltipBox, chartPlaceholder, fieldLabel, formatCurrency, formatMeasure, formatNumber, measureFormat, measureFormatter, numberOf, seriesColor, useClickFilter, useDashboard, useModelQuery };
1368
1432
 
1369
1433
  //# sourceMappingURL=index.js.map