@bluemarble/bi 0.6.3 → 0.6.4
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/{DashboardDevtools-Osu5V30U.js → DashboardDevtools-CSRt9lib.js} +10 -6
- package/dist/DashboardDevtools-CSRt9lib.js.map +1 -0
- package/dist/{ModelDictionary-Dc3_LKqr.js → ModelDictionary-Dib4Vk3i.js} +3 -3
- package/dist/{ModelDictionary-Dc3_LKqr.js.map → ModelDictionary-Dib4Vk3i.js.map} +1 -1
- package/dist/client/index.d.ts +15 -4
- package/dist/client/index.js +213 -57
- package/dist/client/index.js.map +1 -1
- package/dist/{layout-Bn1OiRov.d.ts → layout-CoGyGWYM.d.ts} +19 -4
- package/dist/{layout-DAFeHIuP.js → layout-nViz3MdU.js} +31 -3
- package/dist/layout-nViz3MdU.js.map +1 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
- package/dist/DashboardDevtools-Osu5V30U.js.map +0 -1
- package/dist/layout-DAFeHIuP.js.map +0 -1
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["RechartsBarChart","Tooltip","Tooltip","Tooltip"],"sources":["../../src/client/chartKit.tsx","../../src/client/BarChart.tsx","../../src/client/ComboChart.tsx","../../src/client/useLayout.ts","../../src/client/DashboardCanvas.tsx","../../src/client/DataTable.tsx","../../src/client/DonutChart.tsx","../../src/client/KpiCard.tsx","../../src/client/DashboardCharts.tsx","../../src/client/FilterSelect.tsx","../../src/client/DashboardFilters.tsx"],"sourcesContent":["import { Box, CircularProgress } from '@mui/material'\nimport type { MouseEvent, ReactNode } from 'react'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\n\n/**\n * Peças comuns dos gráficos ligados ao modelo: paleta, filtro por clique, legenda e os estados de\n * carregando/erro/vazio.\n */\n\n/**\n * Paleta categórica, sempre nesta ordem (a série N tem sempre a mesma cor). Laranja Rocha primeiro;\n * a ordem passa no validador de daltonismo (CVD ΔE ≥ 9 entre vizinhas) e de visão normal (≥ 19).\n */\nexport const SERIES_COLORS = [\n '#F58220',\n '#2a78d6',\n '#1baf7a',\n '#eda100',\n '#e87ba4',\n '#008300',\n '#6250d6',\n '#e34948'\n] as const\n\n/** \"Outros\" (fatias agrupadas) fica neutro, fora da paleta. */\nexport const OTHER_COLOR = '#9e9e9e'\n\nexport const seriesColor = (index: number) => SERIES_COLORS[index % SERIES_COLORS.length] as string\n\n/** Valor numérico de uma coluna da linha (`null` quando vazio). */\nexport const numberOf = (row: DashboardRow, key?: string) =>\n key && row[key] !== null && row[key] !== undefined ? Number(row[key]) : null\n\n/**\n * Filtro cruzado a partir do gráfico: clicar num valor filtra o dashboard por ele (Ctrl/Cmd+clique\n * acumula; clicar de novo no único selecionado limpa). O gráfico deve ignorar o próprio filtro na\n * consulta (`ignoreFilters`) e só destacar a seleção.\n */\nexport function useClickFilter(dimension: string | undefined, enabled: boolean) {\n const { filters, setFilter } = useDashboard()\n const selected = enabled && dimension ? (filters[dimension] ?? []) : []\n\n const toggle = (value: FilterValue, event?: Pick<MouseEvent, 'ctrlKey' | 'metaKey'>) => {\n if (!enabled || !dimension) return\n if (event?.ctrlKey || event?.metaKey)\n setFilter(\n dimension,\n selected.includes(value) ? selected.filter((item) => item !== value) : [...selected, value]\n )\n else setFilter(dimension, selected.length === 1 && selected[0] === value ? [] : [value])\n }\n\n return {\n selected,\n /** Há seleção e este valor não está nela. */\n isDimmed: (value: FilterValue) => selected.length > 0 && !selected.includes(value),\n toggle,\n clear: () => {\n if (enabled && dimension && selected.length) setFilter(dimension, [])\n }\n }\n}\n\nexport function Legend({\n items,\n loading\n}: {\n items: { label: string; color: string }[]\n loading?: boolean\n}) {\n return (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n columnGap: 1.5,\n rowGap: 0.5,\n mb: 1,\n fontSize: 14,\n color: '#555',\n minHeight: 21\n }}\n >\n {items.map((item) => (\n <Box key={item.label} sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n <Box sx={{ width: 9, height: 9, borderRadius: '50%', bgcolor: item.color }} />\n {item.label}\n </Box>\n ))}\n {loading && <CircularProgress size={14} sx={{ ml: 'auto' }} />}\n </Box>\n )\n}\n\n/** Erro / carregando / sem dados no lugar do gráfico; `null` quando há o que desenhar (função, não componente). */\nexport function chartPlaceholder({\n height,\n error,\n isLoading,\n empty\n}: {\n height: number\n error: unknown\n isLoading: boolean\n empty: boolean\n}): ReactNode {\n if (!error && !empty) return null\n return (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: error ? 'error.main' : '#999'\n }}\n >\n {error\n ? 'Erro ao carregar o gráfico'\n : isLoading\n ? 'Carregando…'\n : 'Sem dados para os filtros selecionados'}\n </Box>\n )\n}\n\n/** `caption`: o que é o título (ex.: o rótulo da dimensão), em cinza acima dele. */\nexport function TooltipBox({\n title,\n caption,\n children\n}: {\n title: string\n caption?: string\n children: ReactNode\n}) {\n return (\n <Box sx={{ bgcolor: '#fff', border: '1px solid #ccc', p: 1, fontSize: 13 }}>\n {caption && <Box sx={{ fontSize: 11, color: '#777' }}>{caption}</Box>}\n <Box sx={{ fontWeight: 700 }}>{title}</Box>\n {children}\n </Box>\n )\n}\n","import { Box } from '@mui/material'\nimport type { MouseEvent } from 'react'\nimport {\n Bar,\n CartesianGrid,\n Cell,\n LabelList,\n BarChart as RechartsBarChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis\n} from 'recharts'\nimport type { ChartNumberFormat } from '../layout'\nimport type { FilterValue } from '../types'\nimport {\n chartPlaceholder,\n Legend,\n numberOf,\n seriesColor,\n TooltipBox,\n useClickFilter\n} from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatMeasure, measureFormat, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype BarChartProps = {\n /** Dimensão das categorias. */\n dimension: string\n /** Uma série por medida (cores fixas pela posição). */\n measures: string[]\n /** `horizontal` cabe nomes longos; com muitas categorias, rola dentro da altura. */\n orientation?: 'vertical' | 'horizontal'\n /** Empilha as séries (só faz sentido com partes de um total). */\n stacked?: boolean\n /** `dimension` = ordem da consulta; `desc`/`asc` = pela primeira medida. */\n sort?: 'dimension' | 'desc' | 'asc'\n /** Só os N primeiros depois de ordenar. */\n limit?: number\n formatDimension?: (value: FilterValue) => string\n /** Esconde categorias sem valor em nenhuma medida. */\n hideEmpty?: boolean\n /** Valores nas pontas das barras (até 30 categorias; acima disso, só tooltip). */\n showValues?: boolean\n clickToFilter?: boolean\n height?: number\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\nconst MAX_VALUE_LABELS = 30\n/** Altura de cada categoria no modo horizontal (barras finas, com respiro). */\nconst ROW_HEIGHT = 28\n\ntype Point = { value: FilterValue; label: string } & Record<string, number | string | FilterValue>\n\n/**\n * Barras de uma ou mais medidas por uma dimensão. Ex.:\n * `<BarChart dimension=\"navio\" measures={['custoTotal']} orientation=\"horizontal\" sort=\"desc\" limit={10} />`.\n */\nexport function BarChart({\n dimension,\n measures,\n orientation = 'vertical',\n stacked = false,\n sort = 'dimension',\n limit,\n formatDimension = String,\n hideEmpty = true,\n showValues = true,\n clickToFilter = false,\n height = 360,\n labels,\n formats: formatsByMeasure,\n queryLabel\n}: BarChartProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures,\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `BarChart · ${dimension}`\n })\n const filter = useClickFilter(dimension, clickToFilter)\n const formats = measures.map((measure) => measureFormatter(meta, measure, 0, formatsByMeasure))\n const labelOf = (name: string) => fieldLabel(meta, name, labels)\n // Eixo de valores: formato da primeira medida, sem casas (os valores exatos ficam nos rótulos)\n const axisFormat = measures[0] ? measureFormat(meta, measures[0], formatsByMeasure) : undefined\n const formatTick = (value: number) =>\n formatMeasure(value, { ...axisFormat, decimals: axisFormat?.compact ? 1 : 0 }, 0)\n\n const first = measures[0]\n let data: Point[] = rows\n .filter((row) => !hideEmpty || measures.some((measure) => numberOf(row, measure)))\n .map((row) => {\n const value = row[dimension] ?? ''\n const point: Point = { value, label: formatDimension(value) }\n for (const measure of measures) point[measure] = numberOf(row, measure) ?? 0\n return point\n })\n if (sort !== 'dimension' && first)\n data = [...data].sort((a, b) =>\n sort === 'desc' ? Number(b[first]) - Number(a[first]) : Number(a[first]) - Number(b[first])\n )\n if (limit) data = data.slice(0, limit)\n\n const horizontal = orientation === 'horizontal'\n const showLabels = showValues && data.length <= MAX_VALUE_LABELS\n // Horizontal com muitas categorias: o gráfico cresce e a caixa rola\n const chartHeight = horizontal ? Math.max(height, data.length * ROW_HEIGHT + 24) : height\n const longest = Math.max(0, ...data.map((point) => point.label.length))\n\n const state = chartPlaceholder({ height, error, isLoading, empty: !data.length })\n\n const ChartTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const point: Point = payload[0].payload\n return (\n <TooltipBox title={point.label} caption={labelOf(dimension)}>\n {measures.map((measure, index) => (\n <Box key={measure} sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: seriesColor(index) }} />\n {labelOf(measure)}: {formats[index]?.(point[measure] as number)}\n </Box>\n ))}\n </TooltipBox>\n )\n }\n\n const handleClick = (index: number, event: MouseEvent) => {\n // Senão o clique sobe até o container, que limpa o filtro\n event.stopPropagation()\n const point = data[index]\n if (point) filter.toggle(point.value, event)\n }\n\n // Ponta arredondada só no fim da barra (no empilhado, só no último segmento)\n const radius = (index: number): [number, number, number, number] => {\n if (stacked && index < measures.length - 1) return [0, 0, 0, 0]\n return horizontal ? [0, 4, 4, 0] : [4, 4, 0, 0]\n }\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0 }}>\n <Legend\n items={\n measures.length > 1\n ? measures.map((measure, index) => ({\n label: labelOf(measure),\n color: seriesColor(index)\n }))\n : []\n }\n loading={isLoading}\n />\n {state ?? (\n <Box\n onClick={filter.clear}\n sx={{\n height,\n overflowY: horizontal ? 'auto' : 'hidden',\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Box sx={{ height: chartHeight }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsBarChart\n data={data}\n layout={horizontal ? 'vertical' : 'horizontal'}\n barGap={2}\n barCategoryGap=\"20%\"\n margin={\n horizontal\n ? { top: 4, right: showLabels ? 96 : 16, left: 8, bottom: 4 }\n : { top: showLabels ? 24 : 8, right: 8, left: 8, bottom: 0 }\n }\n >\n <CartesianGrid stroke=\"#eee\" vertical={horizontal} horizontal={!horizontal} />\n {horizontal ? (\n <>\n <XAxis\n type=\"number\"\n hide={showLabels}\n tick={{ fontSize: 12, fill: '#555' }}\n tickFormatter={formatTick}\n />\n <YAxis\n type=\"category\"\n dataKey=\"label\"\n interval={0}\n width={Math.min(220, longest * 7 + 12)}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={false}\n />\n </>\n ) : (\n <>\n <XAxis\n dataKey=\"label\"\n interval={data.length > MAX_VALUE_LABELS ? 'preserveStartEnd' : 0}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={{ stroke: '#ccc' }}\n />\n <YAxis\n hide={showLabels}\n tick={{ fontSize: 12, fill: '#555' }}\n tickFormatter={formatTick}\n width={72}\n />\n </>\n )}\n <Tooltip content={<ChartTooltip />} cursor={{ fill: 'rgba(0,0,0,.04)' }} />\n {measures.map((measure, index) => (\n <Bar\n key={measure}\n dataKey={measure}\n name={labelOf(measure)}\n fill={seriesColor(index)}\n stackId={stacked ? 'stack' : undefined}\n radius={radius(index)}\n maxBarSize={horizontal ? 18 : 56}\n isAnimationActive={false}\n onClick={\n clickToFilter\n ? (_bar, barIndex, event) => handleClick(barIndex, event)\n : undefined\n }\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {clickToFilter &&\n data.map((point) => (\n <Cell\n key={String(point.value)}\n fillOpacity={filter.isDimmed(point.value) ? 0.35 : 1}\n />\n ))}\n {/* Empilhado: valor só no fim da pilha seria o total; fica no tooltip */}\n {showLabels && !stacked && (\n <LabelList\n dataKey={measure}\n position={horizontal ? 'right' : 'top'}\n formatter={(value: unknown) => formats[index]?.(value as number) ?? ''}\n style={{ fontSize: 12, fill: '#333', fontWeight: 600 }}\n />\n )}\n </Bar>\n ))}\n </RechartsBarChart>\n </ResponsiveContainer>\n </Box>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, CircularProgress, Typography } from '@mui/material'\nimport type { MouseEvent } from 'react'\nimport {\n Bar,\n Cell,\n ComposedChart,\n LabelList,\n Line,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis\n} from 'recharts'\nimport type { ChartNumberFormat } from '../layout'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatMeasure, formatNumber, measureFormat } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype ComboChartProps = {\n /** Dimensão do eixo X. */\n dimension: string\n /** Medida das barras. */\n bar: string\n /** Medida da linha (eixo próprio, oculto; os valores aparecem nos pontos). */\n line: string\n /** Medida extra mostrada como segunda linha do rótulo da barra (ex.: volume). */\n detail?: string\n /**\n * Rótulos e formatos: sem a prop, vale o `labels`/`formats` do gráfico e depois o dicionário do\n * modelo (`label`, `format`).\n */\n barLabel?: string\n lineLabel?: string\n detailLabel?: string\n formatDimension?: (value: FilterValue) => string\n formatBar?: (value: number) => string\n formatLine?: (value: number) => string\n formatDetail?: (value: number) => string\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Esconde grupos cuja medida da barra é vazia/zero (como o Power BI faz). */\n hideEmpty?: boolean\n height?: number\n /** Rótulos de dados só até essa quantidade de barras (acima disso, só tooltip). */\n maxLabels?: number\n barColor?: string\n lineColor?: string\n /**\n * Clicar numa barra filtra o dashboard pelo valor dela (Ctrl/Cmd+clique acumula; clicar de novo\n * no único selecionado ou fora das barras limpa). O próprio gráfico ignora esse filtro e só\n * destaca a seleção, como o filtro cruzado do Power BI.\n */\n clickToFilter?: boolean\n /** Nome da consulta no devtools (padrão: `ComboChart · <dimensão>`). */\n queryLabel?: string\n}\n\n/** Mantém a linha na faixa de baixo do gráfico, longe dos rótulos que ficam em cima das barras. */\nconst lineDomain = ([min, max]: readonly number[]): [number, number] => {\n const range = max - min || Math.abs(max) || 1\n return [min - range * 0.3, max + range * 1.7]\n}\n\ntype Point = {\n value: FilterValue\n label: string\n bar: number\n line: number | null\n detail: number | null\n}\n\n/**\n * Barras + linha de uma dimensão, consultando o modelo do `DashboardProvider` (com os filtros dele).\n * Ex.: `<ComboChart dimension=\"mes\" bar=\"custoTotal\" line=\"custoTon\" detail=\"volTotal\" />`.\n */\nexport function ComboChart({\n dimension,\n bar,\n line,\n detail,\n barLabel,\n lineLabel,\n detailLabel,\n formatDimension = String,\n formatBar,\n formatLine,\n formatDetail,\n labels,\n formats,\n hideEmpty = true,\n height = 360,\n maxLabels = 24,\n barColor = '#F58220',\n lineColor = '#555',\n clickToFilter = false,\n queryLabel\n}: ComboChartProps) {\n const { meta, filters, setFilter } = useDashboard()\n // Prop > formato do gráfico > dicionário do modelo > padrão do componente\n // (sem `format` em nenhum dos dois, o do componente vale com as casas/prefixo de lá por cima)\n const fromModel = (measure: string, fallback: ChartNumberFormat) => {\n const format = measureFormat(meta, measure, formats)\n const resolved = format?.format ? format : { ...fallback, ...format }\n return (value: number) => formatMeasure(value, resolved, fallback.decimals)\n }\n formatBar ??= fromModel(bar, { format: 'currency', decimals: 0 })\n formatLine ??= fromModel(line, { decimals: 2 })\n formatDetail ??= detail ? fromModel(detail, { decimals: 3 }) : (value) => formatNumber(value, 3)\n barLabel ??= fieldLabel(meta, bar, labels)\n lineLabel ??= fieldLabel(meta, line, labels)\n detailLabel ??= detail && fieldLabel(meta, detail, labels)\n const dimensionLabel = fieldLabel(meta, dimension, labels)\n\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures: detail ? [bar, line, detail] : [bar, line],\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `ComboChart · ${dimension}`\n })\n\n const num = (row: DashboardRow, key?: string) =>\n key && row[key] !== null && row[key] !== undefined ? Number(row[key]) : null\n\n const data: Point[] = rows\n .filter((row) => !hideEmpty || num(row, bar))\n .map((row) => ({\n value: row[dimension] ?? '',\n label: formatDimension(row[dimension] ?? ''),\n bar: num(row, bar) ?? 0,\n line: num(row, line),\n detail: num(row, detail)\n }))\n\n const showLabels = data.length <= maxLabels\n\n const selected = clickToFilter ? (filters[dimension] ?? []) : []\n const isDimmed = (point: Point) => selected.length > 0 && !selected.includes(point.value)\n\n const handleBarClick = (index: number, event: MouseEvent) => {\n // Senão o clique sobe até o container do gráfico, que limpa o filtro\n event.stopPropagation()\n const point = data[index]\n if (!point) return\n if (event.ctrlKey || event.metaKey) {\n setFilter(\n dimension,\n selected.includes(point.value)\n ? selected.filter((value) => value !== point.value)\n : [...selected, point.value]\n )\n } else {\n const onlyThis = selected.length === 1 && selected[0] === point.value\n setFilter(dimension, onlyThis ? [] : [point.value])\n }\n }\n\n const clearFilter = () => {\n if (selected.length) setFilter(dimension, [])\n }\n\n const BarValueLabel = (props: any) => {\n const point = data[props.index]\n if (!point?.bar) return null\n const cx = Number(props.x) + Number(props.width) / 2\n const lines = [\n formatBar(point.bar),\n point.detail === null ? null : formatDetail(point.detail)\n ].filter((text): text is string => !!text)\n const top = Number(props.y) - 6 - lines.length * 15\n const width = Math.max(...lines.map((text) => text.length)) * 6.8 + 10\n return (\n <g>\n <rect\n x={cx - width / 2}\n y={top}\n width={width}\n height={lines.length * 15 + 4}\n rx={2}\n fill=\"#555\"\n />\n {lines.map((text, i) => (\n <text\n key={text}\n x={cx}\n y={top + 14 + i * 15}\n textAnchor=\"middle\"\n fill=\"#fff\"\n fontSize={12}\n fontWeight={700}\n >\n {text}\n </text>\n ))}\n </g>\n )\n }\n\n const LineValueLabel = (props: any) => {\n if (props.value === null || props.value === undefined) return null\n const text = formatLine(Number(props.value))\n const width = text.length * 7 + 10\n return (\n <g>\n <rect\n x={props.x - width / 2}\n y={props.y - 9}\n width={width}\n height={18}\n rx={2}\n fill=\"#d9d9d9\"\n />\n <text\n x={props.x}\n y={props.y + 4}\n textAnchor=\"middle\"\n fill=\"#222\"\n fontSize={12}\n fontWeight={700}\n >\n {text}\n </text>\n </g>\n )\n }\n\n const ChartTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const point: Point = payload[0].payload\n return (\n <Box sx={{ bgcolor: '#fff', border: '1px solid #ccc', p: 1, fontSize: 13 }}>\n <Typography sx={{ fontSize: 11, color: '#777' }}>{dimensionLabel}</Typography>\n <Typography sx={{ fontWeight: 700, fontSize: 13 }}>{point.label}</Typography>\n <div>\n {barLabel}: {formatBar(point.bar)}\n </div>\n {point.detail !== null && (\n <div>\n {detailLabel}: {formatDetail(point.detail)}\n </div>\n )}\n <div>\n {lineLabel}: {point.line === null ? '' : formatLine(point.line)}\n </div>\n </Box>\n )\n }\n\n const legend = [\n { label: barLabel, color: barColor },\n { label: lineLabel, color: lineColor }\n ]\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n <Box sx={{ display: 'flex', gap: 1.5, mb: 1, fontSize: 14, color: '#555' }}>\n {legend.map((item) => (\n <Box key={item.label} sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n <Box sx={{ width: 9, height: 9, borderRadius: '50%', bgcolor: item.color }} />\n {item.label}\n </Box>\n ))}\n {isLoading && <CircularProgress size={14} sx={{ ml: 'auto' }} />}\n </Box>\n {error ? (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'error.main'\n }}\n >\n Erro ao carregar o gráfico\n </Box>\n ) : !data.length ? (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#999'\n }}\n >\n {isLoading ? 'Carregando…' : 'Sem dados para os filtros selecionados'}\n </Box>\n ) : (\n <Box\n onClick={clickToFilter ? clearFilter : undefined}\n sx={{ height, opacity: isLoading ? 0.5 : 1, transition: 'opacity .2s' }}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <ComposedChart data={data} margin={{ top: showLabels ? 48 : 12, right: 8, left: 8 }}>\n <XAxis\n dataKey=\"label\"\n interval={0}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={false}\n />\n <YAxis yAxisId=\"bar\" hide domain={[0, 'auto']} />\n <YAxis yAxisId=\"line\" hide domain={lineDomain} />\n <Tooltip content={<ChartTooltip />} />\n <Bar\n yAxisId=\"bar\"\n dataKey=\"bar\"\n fill={barColor}\n isAnimationActive={false}\n onClick={\n clickToFilter ? (_bar, index, event) => handleBarClick(index, event) : undefined\n }\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {clickToFilter &&\n data.map((point) => (\n <Cell key={String(point.value)} fillOpacity={isDimmed(point) ? 0.35 : 1} />\n ))}\n {showLabels && <LabelList dataKey=\"bar\" content={<BarValueLabel />} />}\n </Bar>\n <Line\n yAxisId=\"line\"\n dataKey=\"line\"\n stroke={lineColor}\n strokeWidth={2}\n strokeDasharray=\"5 4\"\n dot={{ r: 2, fill: lineColor }}\n connectNulls\n isAnimationActive={false}\n >\n {showLabels && <LabelList dataKey=\"line\" content={<LineValueLabel />} />}\n </Line>\n </ComposedChart>\n </ResponsiveContainer>\n </Box>\n )}\n </Box>\n )\n}\n","import { useEffect, useState, useSyncExternalStore } from 'react'\nimport type { LayoutPart } from '../devtools/layoutStore'\nimport type { ChartsLayout } from '../layout'\nimport { useDashboard } from './DashboardProvider'\n\nconst noLayouts = () => () => {}\n\n/**\n * Layout em vigor: o do arquivo ou, com o devtools, o rascunho editado na aba Layout. Registra a\n * parte (`charts`/`filters`) para o devtools saber o que a página renderiza.\n */\nexport function useLayout(\n layout: ChartsLayout,\n part: LayoutPart,\n formatters: Record<string, unknown>\n): ChartsLayout {\n const { devtools } = useDashboard()\n const layouts = devtools?.layouts\n const formatterNames = Object.keys(formatters).sort().join(',')\n\n useEffect(\n () => layouts?.register(layout, part, formatterNames ? formatterNames.split(',') : []),\n [layouts, layout, part, formatterNames]\n )\n\n // Re-renderiza quando o rascunho muda\n useSyncExternalStore(\n layouts?.subscribe ?? noLayouts,\n () => layouts?.getSnapshot(),\n () => undefined\n )\n // O rascunho vem do sessionStorage: só depois de montar, para não divergir da hidratação\n const [mounted, setMounted] = useState(false)\n useEffect(() => setMounted(true), [])\n return (mounted && layouts?.draftOf(layout)) || layout\n}\n","import { Box } from '@mui/material'\nimport {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState\n} from 'react'\nimport type { ChartsLayout } from '../layout'\nimport { useLayout } from './useLayout'\n\n// No servidor o useLayoutEffect só gera aviso; lá não há o que medir\nconst useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect\n\nconst FixedCanvasContext = createContext(false)\n\n/** Dentro de um `<DashboardCanvas>` com tamanho fixo: o grid não troca de colunas pela tela. */\nexport const useFixedCanvas = () => useContext(FixedCanvasContext)\n\ntype DashboardCanvasProps = {\n /** O mesmo layout do `<DashboardCharts>` (`canvas` do JSON). */\n layout: ChartsLayout\n children: ReactNode\n}\n\n/**\n * Tela de tamanho fixo (`layout.canvas`, ex.: 1920×1080): desenha os filhos nessa largura e escala\n * tudo para caber na largura disponível, mantendo a proporção — numa tela menor o dashboard encolhe\n * em vez de reorganizar os gráficos. Sem `canvas` no layout, só renderiza os filhos (responsivo).\n *\n * ```tsx\n * <DashboardCanvas layout={layout}>\n * <DashboardFilters layout={layout} />\n * <DashboardCharts layout={layout} />\n * </DashboardCanvas>\n * ```\n *\n * A escala é um `transform`: os gráficos continuam medindo o tamanho de projeto (o Recharts compensa\n * a escala no mouse) e os breakpoints do MUI, que olham a janela, ficam desligados no grid.\n */\nexport function DashboardCanvas({ layout, children }: DashboardCanvasProps) {\n const { canvas } = useLayout(layout, 'canvas', {})\n const outer = useRef<HTMLDivElement>(null)\n const inner = useRef<HTMLDivElement>(null)\n // Largura disponível e altura de projeto do conteúdo (offsetHeight ignora o transform)\n const [size, setSize] = useState<{ available: number; content: number } | null>(null)\n\n useIsomorphicLayoutEffect(() => {\n if (!canvas || !outer.current || !inner.current) return\n const outerElement = outer.current\n const innerElement = inner.current\n const measure = () => {\n const next = { available: outerElement.clientWidth, content: innerElement.offsetHeight }\n // Mudar a altura do outer dispara o observer de novo: só re-renderiza se mudou algo\n setSize((current) =>\n current?.available === next.available && current.content === next.content ? current : next\n )\n }\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(outerElement)\n observer.observe(innerElement)\n return () => observer.disconnect()\n }, [canvas])\n\n if (!canvas) return <>{children}</>\n\n const scale = size ? size.available / canvas.width : 1\n return (\n <FixedCanvasContext.Provider value>\n <Box\n ref={outer}\n sx={{\n width: '100%',\n overflow: 'hidden',\n height: size ? size.content * scale : undefined\n }}\n >\n <Box\n ref={inner}\n sx={{\n width: canvas.width,\n minHeight: canvas.height,\n transform: `scale(${scale})`,\n transformOrigin: '0 0',\n // Antes de medir a escala é desconhecida: evita piscar no tamanho de projeto\n visibility: size ? undefined : 'hidden'\n }}\n >\n {children}\n </Box>\n </Box>\n </FixedCanvasContext.Provider>\n )\n}\n","import {\n Box,\n CircularProgress,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TableSortLabel\n} from '@mui/material'\nimport { useState } from 'react'\nimport { type FormatRule, type RuleStyle, rowRuleStyles } from '../formatRules'\nimport {\n type ChartNumberFormat,\n type ColumnAlign,\n type ColumnVerticalAlign,\n PERCENT_PREFIX as PERCENT,\n percentColumn,\n tableColumns\n} from '../layout'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { chartPlaceholder, useClickFilter } from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatNumber, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype SortDirection = 'asc' | 'desc'\n\ntype DataTableProps = {\n /** Uma linha por combinação de dimensões (sem dimensões, uma linha só). */\n dimensions?: string[]\n /** Uma coluna por medida, formatada pelo dicionário do modelo. */\n measures: string[]\n /**\n * Medidas com coluna de participação no total (valor da linha ÷ soma da coluna), logo depois da\n * coluna da medida. Medida fora de `measures` é consultada só para o percentual (coluna no fim).\n */\n percentOf?: string[]\n /** Formatter por dimensão. */\n formatDimensions?: Record<string, (value: FilterValue) => string>\n /**\n * Linha de total, consultada sem as dimensões: razões (custo/t) saem do total, não da soma das\n * linhas.\n */\n showTotal?: boolean\n /**\n * Coluna da ordem inicial (dimensão, medida ou `%:medida`); quem usa reordena clicando no\n * cabeçalho. Dimensão/medida fora da tabela entra na consulta sem coluna (ex.: número do mês para\n * ordenar o nome do mês) — uma dimensão de fora divide as linhas se tiver mais de um valor por linha.\n */\n sortBy?: string\n sortDirection?: SortDirection\n /** Clicar numa linha filtra o dashboard pela primeira dimensão. */\n clickToFilter?: boolean\n /** Altura máxima; a tabela rola com o cabeçalho fixo. */\n height?: number\n /** Cabeçalho por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Casas decimais das colunas de percentual. Padrão: 1. */\n percentDecimals?: number\n /**\n * Ordem das colunas misturando dimensões, medidas e percentuais (ex.: `['custoTotal',\n * '%:custoTotal', 'navio']`); o que não estiver nela vai depois. Padrão: dimensões e depois\n * medidas, cada percentual logo depois da medida.\n */\n columnOrder?: string[]\n /**\n * Formatação condicional: cor do texto/fundo e negrito da célula ou da linha conforme o valor de\n * uma dimensão/medida (da tabela, de fora dela ou `%:medida`).\n */\n formatRules?: FormatRule[]\n /** Bordas entre as células (grade). Padrão: só a linha embaixo de cada linha. */\n cellBorders?: boolean\n /** Cor das bordas da grade. Padrão: `#e0e0e0`. */\n borderColor?: string\n /**\n * Alinhamento horizontal por coluna (`%:medida` para o percentual): cabeçalho, células e total.\n * Padrão: dimensão à esquerda, número à direita.\n */\n align?: Record<string, ColumnAlign>\n /** Alinhamento vertical por coluna (`top`, `middle`, `bottom`). Padrão: `middle`. */\n verticalAlign?: Record<string, ColumnVerticalAlign>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\nconst EMPTY: string[] = []\nconst NO_RULES: FormatRule[] = []\n\nfunction compare(a: DashboardRow[string], b: DashboardRow[string]) {\n // Vazios sempre por último, nas duas direções (tratado por quem chama)\n if (typeof a === 'number' && typeof b === 'number') return a - b\n return String(a).localeCompare(String(b), 'pt-BR', { numeric: true })\n}\n\n/**\n * Tabela de medidas por dimensões, com total e ordenação pelo cabeçalho. Ex.:\n * `<DataTable dimensions={['navio']} measures={['volTotal', 'custoTotal', 'custoTon']} />`.\n */\nexport function DataTable({\n dimensions = EMPTY,\n measures,\n percentOf = EMPTY,\n formatDimensions = {},\n showTotal = true,\n sortBy,\n sortDirection = 'desc',\n clickToFilter = false,\n height = 400,\n labels,\n formats: formatsByMeasure,\n percentDecimals = 1,\n columnOrder,\n formatRules = NO_RULES,\n cellBorders = false,\n borderColor = '#e0e0e0',\n align,\n verticalAlign,\n queryLabel\n}: DataTableProps) {\n const { meta } = useDashboard()\n const name = queryLabel ?? `DataTable · ${dimensions.join(', ') || 'total'}`\n const firstDimension = dimensions[0]\n const ignoreFilters = clickToFilter && firstDimension ? [firstDimension] : undefined\n const extraMeasures = percentOf.filter((measure) => !measures.includes(measure))\n // Dimensões/medidas fora da tabela (ordem inicial, regras): consultadas sem coluna. Saber se é\n // dimensão ou medida depende do dicionário; até ele chegar, a consulta espera\n const outside = [\n ...new Set([sortBy, ...formatRules.map((rule) => rule.field)].filter(Boolean) as string[])\n ].filter(\n (field) =>\n !field.startsWith(PERCENT) &&\n !dimensions.includes(field) &&\n !measures.includes(field) &&\n !extraMeasures.includes(field)\n )\n const waitingMeta = outside.length > 0 && !meta\n const queryDimensions = [...dimensions, ...outside.filter((field) => meta?.dimensions[field])]\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: queryDimensions,\n measures: [\n ...measures,\n ...extraMeasures,\n ...outside.filter((field) => meta?.measures[field] && !meta.dimensions[field])\n ],\n ignoreFilters,\n label: name,\n skip: waitingMeta\n })\n // Sem dimensões a própria consulta já é o total\n const totals = useModelQuery({\n measures,\n ignoreFilters,\n label: `${name} · total`,\n skip: !showTotal || !dimensions.length\n })\n const filter = useClickFilter(firstDimension, clickToFilter)\n\n const [sort, setSort] = useState<{ by?: string; direction: SortDirection }>({\n by: sortBy,\n direction: sortDirection\n })\n // Props mudaram (ex.: devtools): volta para a ordem configurada\n const [configured, setConfigured] = useState([sortBy, sortDirection])\n if (configured[0] !== sortBy || configured[1] !== sortDirection) {\n setConfigured([sortBy, sortDirection])\n setSort({ by: sortBy, direction: sortDirection })\n }\n\n // O percentual ordena igual à medida\n const sortKey = sort.by?.startsWith(PERCENT) ? sort.by.slice(PERCENT.length) : sort.by\n const sorted = sortKey\n ? [...rows].sort((a, b) => {\n const [x, y] = [a[sortKey], b[sortKey]]\n if (x === null || x === undefined) return 1\n if (y === null || y === undefined) return -1\n return sort.direction === 'asc' ? compare(x, y) : compare(y, x)\n })\n : rows\n\n const formats = Object.fromEntries(\n measures.map((measure) => [measure, measureFormatter(meta, measure, 2, formatsByMeasure)])\n )\n const formatPercent = (value: number | null) =>\n value === null ? '' : `${formatNumber(value * 100, percentDecimals)}%`\n const dimensionText = (dimension: string, value: DashboardRow[string]) =>\n value === null || value === undefined\n ? '(vazio)'\n : (formatDimensions[dimension] ?? String)(value)\n const labelOf = (column: string) => fieldLabel(meta, column, labels)\n const headerOf = (column: string) => {\n if (!column.startsWith(PERCENT)) return labelOf(column)\n const measure = column.slice(PERCENT.length)\n return measures.includes(measure) ? '%' : `% ${labelOf(measure)}`\n }\n\n // Total de cada medida com percentual: soma das linhas mostradas\n const sums = Object.fromEntries(\n percentOf.map((measure) => [\n measure,\n rows.reduce((total, row) => total + (Number(row[measure]) || 0), 0)\n ])\n )\n const percentOfRow = (row: DashboardRow, measure: string) => {\n const value = row[measure]\n const total = sums[measure]\n return value === null || value === undefined || !total ? null : Number(value) / total\n }\n // Colunas na ordem configurada; percentual fora dela logo depois da medida (avulsos no fim)\n const columns = tableColumns(\n [...dimensions, ...measures],\n percentOf.filter((measure) => !dimensions.includes(measure)),\n columnOrder\n )\n // Estilo das regras por coluna; percentuais entram na linha avaliada como `%:medida`\n const ruleStyles = (row: DashboardRow): Record<string, RuleStyle> | undefined => {\n if (!formatRules.length) return undefined\n const evaluated = { ...row }\n for (const measure of percentOf) evaluated[percentColumn(measure)] = percentOfRow(row, measure)\n return rowRuleStyles(formatRules, evaluated, columns)\n }\n const ruleSx = (style: RuleStyle | undefined) =>\n style && {\n ...(style.color && { color: style.color }),\n ...(style.background && { bgcolor: style.background }),\n ...(style.bold && { fontWeight: 700 }),\n ...(style.align && { textAlign: style.align }),\n ...(style.verticalAlign && { verticalAlign: style.verticalAlign })\n }\n const isDimension = (column: string) => dimensions.includes(column)\n const alignOf = (column: string) => align?.[column] ?? (isDimension(column) ? 'left' : 'right')\n const verticalOf = (column: string) => verticalAlign?.[column] ?? 'middle'\n // \"Total\" vai na primeira coluna de dimensão da tabela\n const totalLabelColumn = columns.find(isDimension)\n const cellText = (row: DashboardRow, column: string) =>\n column.startsWith(PERCENT)\n ? formatPercent(percentOfRow(row, column.slice(PERCENT.length)))\n : formats[column]?.(row[column])\n\n const toggleSort = (column: string) =>\n setSort((current) =>\n current.by === column\n ? { by: column, direction: current.direction === 'asc' ? 'desc' : 'asc' }\n : // Medidas começam do maior; dimensões, em ordem alfabética\n { by: column, direction: dimensions.includes(column) ? 'asc' : 'desc' }\n )\n\n const totalRow = dimensions.length ? totals.rows[0] : undefined\n const loading = isLoading || waitingMeta\n const placeholder = chartPlaceholder({\n height: 160,\n error,\n isLoading: loading,\n empty: !rows.length\n })\n\n const header = (column: string, numeric: boolean) => (\n <TableCell\n key={column}\n align={alignOf(column)}\n sortDirection={sort.by === column ? sort.direction : false}\n sx={{\n fontWeight: 700,\n bgcolor: '#f3f3f3',\n whiteSpace: 'nowrap',\n verticalAlign: verticalOf(column)\n }}\n >\n <TableSortLabel\n active={sort.by === column}\n direction={sort.by === column ? sort.direction : numeric ? 'desc' : 'asc'}\n onClick={() => toggleSort(column)}\n >\n {headerOf(column)}\n </TableSortLabel>\n </TableCell>\n )\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {loading && <CircularProgress size={14} sx={{ position: 'absolute', top: -22, right: 0 }} />}\n {placeholder ?? (\n <Box\n sx={{\n maxHeight: height,\n overflow: 'auto',\n opacity: loading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Table\n size=\"small\"\n stickyHeader\n sx={{\n '& td, & th': {\n fontSize: 13,\n ...(cellBorders && { border: `1px solid ${borderColor}` })\n }\n }}\n >\n <TableHead>\n <TableRow>{columns.map((column) => header(column, !isDimension(column)))}</TableRow>\n </TableHead>\n <TableBody>\n {sorted.map((row) => {\n const value = firstDimension ? row[firstDimension] : null\n const clickable = clickToFilter && value !== null && value !== undefined\n const styles = ruleStyles(row)\n return (\n <TableRow\n key={queryDimensions.map((dimension) => String(row[dimension])).join('\\u0000')}\n hover\n onClick={clickable ? (event) => filter.toggle(value, event) : undefined}\n selected={clickable && filter.selected.includes(value)}\n sx={{\n cursor: clickable ? 'pointer' : undefined,\n opacity: clickable && filter.isDimmed(value) ? 0.5 : 1\n }}\n >\n {columns.map((column) =>\n isDimension(column) ? (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ verticalAlign: verticalOf(column), ...ruleSx(styles?.[column]) }}\n >\n {dimensionText(column, row[column])}\n </TableCell>\n ) : (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{\n whiteSpace: 'nowrap',\n verticalAlign: verticalOf(column),\n ...ruleSx(styles?.[column])\n }}\n >\n {cellText(row, column)}\n </TableCell>\n )\n )}\n </TableRow>\n )\n })}\n {totalRow && (\n <TableRow\n sx={{\n '& td': {\n fontWeight: 700,\n position: 'sticky',\n bottom: 0,\n bgcolor: '#f3f3f3',\n borderTop: '2px solid #ddd'\n }\n }}\n >\n {columns.map((column) =>\n isDimension(column) ? (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ verticalAlign: verticalOf(column) }}\n >\n {column === totalLabelColumn ? 'Total' : ''}\n </TableCell>\n ) : (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ whiteSpace: 'nowrap', verticalAlign: verticalOf(column) }}\n >\n {column.startsWith(PERCENT)\n ? formatPercent(sums[column.slice(PERCENT.length)] ? 1 : null)\n : formats[column]?.(totalRow[column])}\n </TableCell>\n )\n )}\n </TableRow>\n )}\n </TableBody>\n </Table>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box } from '@mui/material'\nimport { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts'\nimport type { ChartNumberFormat } from '../layout'\nimport type { FilterValue } from '../types'\nimport {\n chartPlaceholder,\n numberOf,\n OTHER_COLOR,\n seriesColor,\n TooltipBox,\n useClickFilter\n} from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatNumber, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype DonutChartProps = {\n /** Dimensão das fatias. */\n dimension: string\n /** Medida somável (partes de um total). Valores negativos ou zerados ficam de fora. */\n measure: string\n /** Fatias além dessa quantidade viram \"Outros\" (no máximo 8, o tamanho da paleta). */\n maxSlices?: number\n formatDimension?: (value: FilterValue) => string\n clickToFilter?: boolean\n height?: number\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Casas decimais do percentual. Padrão: 1. */\n percentDecimals?: number\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\ntype Slice = {\n key: string\n value: FilterValue | null\n label: string\n amount: number\n color: string\n}\n\nconst OTHERS = 'Outros'\n\n/**\n * Rosca de uma medida por uma dimensão, com o total no centro e a legenda ao lado (nome, % e valor).\n * Ex.: `<DonutChart dimension=\"operacao_status\" measure=\"custoTotal\" />`.\n */\nexport function DonutChart({\n dimension,\n measure,\n maxSlices = 6,\n formatDimension = String,\n clickToFilter = false,\n height = 300,\n labels,\n formats,\n percentDecimals = 1,\n queryLabel\n}: DonutChartProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures: [measure],\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `DonutChart · ${dimension}`\n })\n const filter = useClickFilter(dimension, clickToFilter)\n const format = measureFormatter(meta, measure, 0, formats)\n\n const positive = rows\n .map((row) => ({ value: row[dimension] ?? '', amount: numberOf(row, measure) ?? 0 }))\n .filter((item) => item.amount > 0)\n .sort((a, b) => b.amount - a.amount)\n const limit = Math.min(Math.max(maxSlices, 2), 8)\n // Com fatias sobrando, a última vaga vira \"Outros\"\n const kept = positive.length > limit ? positive.slice(0, limit - 1) : positive\n const rest = positive.slice(kept.length)\n // A cor segue a posição na ordem (maior = laranja); \"Outros\" é neutro\n const slices: Slice[] = kept.map((item, index) => ({\n key: String(item.value),\n value: item.value,\n label: formatDimension(item.value),\n amount: item.amount,\n color: seriesColor(index)\n }))\n if (rest.length)\n slices.push({\n key: `\\u0000${OTHERS}`,\n value: null,\n label: `${OTHERS} (${rest.length})`,\n amount: rest.reduce((total, item) => total + item.amount, 0),\n color: OTHER_COLOR\n })\n const total = slices.reduce((sum, slice) => sum + slice.amount, 0)\n const percent = (amount: number) => `${formatNumber((amount / total) * 100, percentDecimals)}%`\n\n const placeholder = chartPlaceholder({ height, error, isLoading, empty: !slices.length })\n\n const select = (slice: Slice | undefined, event?: { ctrlKey: boolean; metaKey: boolean }) => {\n if (slice?.value !== null && slice?.value !== undefined) filter.toggle(slice.value, event)\n }\n const dimmed = (slice: Slice) =>\n filter.selected.length > 0 && (slice.value === null || filter.isDimmed(slice.value))\n\n const SliceTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const slice: Slice = payload[0].payload\n return (\n <TooltipBox title={slice.label} caption={fieldLabel(meta, dimension, labels)}>\n {fieldLabel(meta, measure, labels)}: {format(slice.amount)} · {percent(slice.amount)}\n </TooltipBox>\n )\n }\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {placeholder ?? (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n gap: 2,\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Box sx={{ position: 'relative', height: '100%', flex: '0 0 50%', minWidth: 140 }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <PieChart>\n <Tooltip content={<SliceTooltip />} />\n <Pie\n data={slices}\n dataKey=\"amount\"\n nameKey=\"label\"\n innerRadius=\"62%\"\n outerRadius=\"92%\"\n startAngle={90}\n endAngle={-270}\n stroke=\"#fff\"\n strokeWidth={2}\n isAnimationActive={false}\n onClick={(_, index, event) => select(slices[index], event)}\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {slices.map((slice) => (\n <Cell\n key={slice.key}\n fill={slice.color}\n fillOpacity={dimmed(slice) ? 0.35 : 1}\n />\n ))}\n </Pie>\n </PieChart>\n </ResponsiveContainer>\n {/* Total no furo da rosca */}\n <Box\n sx={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n textAlign: 'center'\n }}\n >\n <Box sx={{ fontSize: 12, color: '#777' }}>Total</Box>\n <Box sx={{ fontSize: 15, fontWeight: 700, color: '#333' }}>{format(total)}</Box>\n </Box>\n </Box>\n <Box\n component=\"ul\"\n sx={{\n listStyle: 'none',\n m: 0,\n p: 0,\n minWidth: 0,\n flex: 1,\n overflow: 'auto',\n maxHeight: '100%'\n }}\n >\n {slices.map((slice) => (\n <Box\n component=\"li\"\n key={slice.key}\n onClick={(event) => select(slice, event)}\n sx={{\n display: 'grid',\n gridTemplateColumns: '10px minmax(0, 1fr) auto',\n alignItems: 'center',\n columnGap: 0.75,\n py: 0.5,\n fontSize: 13,\n color: '#333',\n opacity: dimmed(slice) ? 0.45 : 1,\n cursor: clickToFilter && slice.value !== null ? 'pointer' : undefined\n }}\n >\n <Box sx={{ width: 10, height: 10, borderRadius: '50%', bgcolor: slice.color }} />\n <Box sx={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {slice.label}\n </Box>\n <Box sx={{ fontWeight: 700, textAlign: 'right' }}>{percent(slice.amount)}</Box>\n <Box />\n <Box sx={{ gridColumn: '2 / 4', fontSize: 12, color: '#777' }}>\n {format(slice.amount)}\n </Box>\n </Box>\n ))}\n </Box>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, CircularProgress } from '@mui/material'\nimport type { ChartNumberFormat } from '../layout'\nimport { numberOf } from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype KpiCardProps = {\n /** Medida do número grande: o total com os filtros da página. */\n measure: string\n /** Rótulo acima do número (no `<DashboardCharts>`, o título do painel faz esse papel). */\n label?: string\n /** Medida extra numa linha menor embaixo (ex.: volume, custo/t). */\n secondary?: string\n /** Padrão: `labels[secondary]` ou o `label` da medida secundária no dicionário. */\n secondaryLabel?: string\n /** Rótulo por medida (sobrepõe o dicionário); o da principal entra quando não há `label`. */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário). */\n formats?: Record<string, ChartNumberFormat>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\n/**\n * Card com o total de uma medida (e, opcionalmente, uma segunda medida embaixo). Uma consulta sem\n * dimensões: razões (custo/t) saem do total, não de uma média. Ex.:\n * `<KpiCard label=\"Custo total\" measure=\"custoTotal\" secondary=\"custoTon\" />`.\n */\nexport function KpiCard({\n measure,\n label,\n secondary,\n secondaryLabel,\n labels,\n formats,\n queryLabel\n}: KpiCardProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n measures: secondary ? [measure, secondary] : [measure],\n label: queryLabel ?? `KpiCard · ${measure}`\n })\n const row = rows[0]\n const value = row ? numberOf(row, measure) : null\n const extra = row && secondary ? numberOf(row, secondary) : null\n label ??= labels?.[measure]\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {label && <Box sx={{ fontSize: 13, color: '#666', mb: 0.5 }}>{label}</Box>}\n {isLoading && <CircularProgress size={12} sx={{ position: 'absolute', top: 0, right: 0 }} />}\n <Box\n sx={{\n fontSize: 28,\n fontWeight: 700,\n lineHeight: 1.2,\n color: error ? 'error.main' : '#333',\n fontVariantNumeric: 'tabular-nums',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n {error ? 'Erro' : value === null ? '—' : measureFormatter(meta, measure, 0, formats)(value)}\n </Box>\n {secondary && (\n <Box sx={{ fontSize: 13, color: '#666', mt: 0.25, minHeight: 20 }}>\n {secondaryLabel ?? fieldLabel(meta, secondary, labels)}:{' '}\n <Box component=\"span\" sx={{ fontWeight: 600, color: '#444' }}>\n {extra === null ? '—' : measureFormatter(meta, secondary, 2, formats)(extra)}\n </Box>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, Paper, Typography } from '@mui/material'\nimport type { ComponentType, ReactNode } from 'react'\nimport { LAYOUT_ITEM_ATTRIBUTE, layoutItemKey } from '../devtools/layoutStore'\nimport {\n type CardStyle,\n type ChartDef,\n type ChartsLayout,\n chartCardStyle,\n customChartProps,\n isBuiltinChart,\n LAYOUT_COLUMNS\n} from '../layout'\nimport type { FilterValue } from '../types'\nimport { BarChart } from './BarChart'\nimport { ComboChart } from './ComboChart'\nimport { useFixedCanvas } from './DashboardCanvas'\nimport { useDashboard } from './DashboardProvider'\nimport { DataTable } from './DataTable'\nimport { DonutChart } from './DonutChart'\nimport { KpiCard } from './KpiCard'\nimport { useLayout } from './useLayout'\n\nexport type ChartPanelProps = {\n title: string\n chart: ChartDef\n /** Estilo do card (`cards` do layout com o `card` do gráfico por cima); vazio = padrão. */\n card: CardStyle\n children: ReactNode\n}\n\ntype DashboardChartsProps = {\n /** Layout importado do JSON (`src/dashboard/layouts/<id>.json`). */\n layout: ChartsLayout\n /** Formatters por nome, referenciados no JSON por `formatDimension`. */\n formatters?: Record<string, (value: FilterValue) => string>\n /** Moldura de cada gráfico (título + conteúdo). */\n panel?: ComponentType<ChartPanelProps>\n /** Espaço entre os cards (unidades do `theme.spacing`); o `cards.gap` do layout (px) tem prioridade. */\n gap?: number\n}\n\nfunction DefaultPanel({ title, card, children }: ChartPanelProps) {\n const px = (value: number | undefined) => (value === undefined ? undefined : `${value}px`)\n return (\n <Paper\n elevation={card.shadow ?? 0}\n sx={{\n p: px(card.padding) ?? 1.5,\n minWidth: 0,\n height: '100%',\n bgcolor: card.background,\n border: `${card.borderWidth ?? 1}px solid`,\n borderColor: card.borderColor ?? 'divider',\n borderRadius: px(card.borderRadius)\n }}\n >\n {title && (\n <Typography\n sx={{\n fontWeight: 700,\n mb: 1,\n color: card.titleColor,\n fontSize: px(card.titleSize),\n textAlign: card.titleAlign\n }}\n >\n {title}\n </Typography>\n )}\n {children}\n </Paper>\n )\n}\n\n/**\n * Renderiza os gráficos de um layout declarativo num grid de 12 colunas (no celular, um por linha;\n * dentro de um `<DashboardCanvas>` de tamanho fixo, sempre as 12). Em desenvolvimento, a aba\n * Layout do devtools edita esse layout ao vivo (rascunho) e grava o JSON de volta.\n *\n * ```tsx\n * import layout from '@/dashboard/layouts/analiseCusto.json'\n * <DashboardCharts layout={layout as ChartsLayout} formatters={{ nomeMes }} panel={Panel} />\n * ```\n */\nexport function DashboardCharts({\n layout,\n formatters = {},\n panel: Panel = DefaultPanel,\n gap = 1.5\n}: DashboardChartsProps) {\n const current = useLayout(layout, 'charts', formatters)\n const { charts } = current\n // Tela fixa: a janela não decide as colunas, o canvas é que escala\n const fixed = useFixedCanvas()\n const columns = `repeat(${LAYOUT_COLUMNS}, minmax(0, 1fr))`\n\n return (\n <Box\n sx={{\n display: 'grid',\n gap: current.cards?.gap === undefined ? gap : `${current.cards.gap}px`,\n gridTemplateColumns: fixed ? columns : { xs: '1fr', lg: columns }\n }}\n >\n {charts.map((chart) => (\n <Box\n key={chart.id}\n {...{\n [LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, { kind: 'chart', key: chart.id })\n }}\n sx={{\n minWidth: 0,\n gridColumn: fixed\n ? `span ${chart.span ?? LAYOUT_COLUMNS}`\n : { lg: `span ${chart.span ?? LAYOUT_COLUMNS}` }\n }}\n >\n <Panel title={chart.title} chart={chart} card={chartCardStyle(current, chart)}>\n <Chart chart={chart} formatters={formatters} />\n </Panel>\n </Box>\n ))}\n </Box>\n )\n}\n\ntype Formatters = Record<string, (value: FilterValue) => string>\n\nfunction Chart({ chart, formatters }: { chart: ChartDef; formatters: Formatters }) {\n const { chartTypes, chartComponents } = useDashboard()\n if (!isBuiltinChart(chart)) {\n const Component = chartComponents[chart.type]\n if (Component) return <Component {...customChartProps(chart, chartTypes, formatters)} />\n return <UnknownChart type={chart.type} />\n }\n const queryLabel = `${chart.title || chart.id} · ${chart.type}`\n const formatter = (name?: string) => (name ? formatters[name] : undefined)\n switch (chart.type) {\n case 'kpi': {\n const { id, type, title, span, card, ...props } = chart\n return <KpiCard {...props} queryLabel={queryLabel} />\n }\n case 'combo': {\n const { id, type, title, span, card, formatDimension, ...props } = chart\n return (\n <ComboChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n />\n )\n }\n case 'bar': {\n const { id, type, title, span, card, formatDimension, ...props } = chart\n return (\n <BarChart {...props} queryLabel={queryLabel} formatDimension={formatter(formatDimension)} />\n )\n }\n case 'donut': {\n const { id, type, title, span, card, formatDimension, ...props } = chart\n return (\n <DonutChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n />\n )\n }\n case 'table': {\n const { id, type, title, span, card, formatDimensions, ...props } = chart\n const resolved: Formatters = {}\n for (const [dimension, name] of Object.entries(formatDimensions ?? {})) {\n const format = formatter(name)\n if (format) resolved[dimension] = format\n }\n return <DataTable {...props} queryLabel={queryLabel} formatDimensions={resolved} />\n }\n default:\n return <UnknownChart type={(chart as { type: unknown }).type} />\n }\n}\n\nfunction UnknownChart({ type }: { type: unknown }) {\n return (\n <Box sx={{ color: 'error.main', p: 2 }}>\n Tipo de gráfico desconhecido: {String(type)} (tipos do app vão no{' '}\n <code>{'<DashboardProvider charts>'}</code>)\n </Box>\n )\n}\n","import {\n Checkbox,\n FormControl,\n InputLabel,\n ListItemText,\n MenuItem,\n OutlinedInput,\n Select\n} from '@mui/material'\nimport type { FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\nimport { useModelQuery } from './useModelQuery'\n\ntype FilterSelectProps = {\n dimension: string\n /** Padrão: `label` da dimensão no dicionário do modelo. */\n label?: string\n formatLabel?: (value: FilterValue) => string\n width?: number\n}\n\n/**\n * Filtro de múltipla escolha de uma dimensão. As opções vêm do próprio modelo e respeitam os\n * DEMAIS filtros (filtro cruzado): com Mês = Janeiro, o filtro de navio só lista quem atracou em\n * janeiro. Nada selecionado = \"Todos\".\n */\nexport function FilterSelect({\n dimension,\n label,\n formatLabel = String,\n width = 200\n}: FilterSelectProps) {\n const { filters, setFilter, meta } = useDashboard()\n label ??= meta?.dimensions[dimension]?.label ?? dimension\n const { rows, inspectProps } = useModelQuery({\n dimensions: [dimension],\n ignoreFilters: [dimension],\n label: `FilterSelect · ${dimension}`\n })\n\n const selected = filters[dimension] ?? []\n const options = rows\n .map((row) => row[dimension])\n .filter((value): value is FilterValue => value !== null && value !== '')\n // Mantém visíveis valores selecionados que sumiram das opções por causa de outro filtro\n for (const value of selected) if (!options.includes(value)) options.push(value)\n\n return (\n <FormControl {...inspectProps} size=\"small\" sx={{ width }}>\n <InputLabel shrink>{label}</InputLabel>\n <Select<FilterValue[]>\n multiple\n displayEmpty\n value={selected}\n onChange={(event) => setFilter(dimension, event.target.value as FilterValue[])}\n input={<OutlinedInput notched label={label} />}\n renderValue={(values) => (values.length ? values.map(formatLabel).join(', ') : 'Todos')}\n MenuProps={{ slotProps: { paper: { sx: { maxHeight: 360 } } } }}\n sx={{ bgcolor: '#fff' }}\n >\n {options.map((option) => (\n <MenuItem key={option} value={option} dense>\n <Checkbox size=\"small\" checked={selected.includes(option)} sx={{ p: 0.5, mr: 1 }} />\n <ListItemText primary={formatLabel(option)} />\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n )\n}\n","import { Box } from '@mui/material'\nimport { LAYOUT_ITEM_ATTRIBUTE, layoutItemKey } from '../devtools/layoutStore'\nimport type { ChartsLayout } from '../layout'\nimport type { FilterValue } from '../types'\nimport { FilterSelect } from './FilterSelect'\nimport { useLayout } from './useLayout'\n\ntype DashboardFiltersProps = {\n /** O mesmo layout do `<DashboardCharts>` (`filters` do JSON). */\n layout: ChartsLayout\n /** Formatters por nome, referenciados no JSON por `formatLabel`. */\n formatters?: Record<string, (value: FilterValue) => string>\n gap?: number\n}\n\n/**\n * Filtros (slicers) declarados em `layout.filters`, na ordem. Em desenvolvimento, a aba Layout do\n * devtools adiciona, remove, reordena e edita os filtros ao vivo.\n */\nexport function DashboardFilters({ layout, formatters = {}, gap = 2 }: DashboardFiltersProps) {\n const { filters = [] } = useLayout(layout, 'filters', formatters)\n return (\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap }}>\n {filters.map((filter) => (\n <Box\n key={filter.dimension}\n {...{\n [LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, {\n kind: 'filter',\n key: filter.dimension\n })\n }}\n >\n <FilterSelect\n dimension={filter.dimension}\n label={filter.label}\n width={filter.width}\n formatLabel={filter.formatLabel ? formatters[filter.formatLabel] : undefined}\n />\n </Box>\n ))}\n </Box>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["OTHERS","RechartsBarChart","Tooltip","Tooltip","Tooltip"],"sources":["../../src/client/chartKit.tsx","../../src/client/seriesPivot.ts","../../src/client/BarChart.tsx","../../src/client/ComboChart.tsx","../../src/client/useLayout.ts","../../src/client/DashboardCanvas.tsx","../../src/client/DataTable.tsx","../../src/client/DonutChart.tsx","../../src/client/KpiCard.tsx","../../src/client/DashboardCharts.tsx","../../src/client/FilterSelect.tsx","../../src/client/DashboardFilters.tsx"],"sourcesContent":["import { Box, CircularProgress } from '@mui/material'\nimport type { MouseEvent, ReactNode } from 'react'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\n\n/**\n * Peças comuns dos gráficos ligados ao modelo: paleta, filtro por clique, legenda e os estados de\n * carregando/erro/vazio.\n */\n\n/**\n * Paleta categórica, sempre nesta ordem (a série N tem sempre a mesma cor). Laranja Rocha primeiro;\n * a ordem passa no validador de daltonismo (CVD ΔE ≥ 9 entre vizinhas) e de visão normal (≥ 19).\n */\nexport const SERIES_COLORS = [\n '#F58220',\n '#2a78d6',\n '#1baf7a',\n '#eda100',\n '#e87ba4',\n '#008300',\n '#6250d6',\n '#e34948'\n] as const\n\n/** \"Outros\" (fatias agrupadas) fica neutro, fora da paleta. */\nexport const OTHER_COLOR = '#9e9e9e'\n\nexport const seriesColor = (index: number) => SERIES_COLORS[index % SERIES_COLORS.length] as string\n\n/** Valor numérico de uma coluna da linha (`null` quando vazio). */\nexport const numberOf = (row: DashboardRow, key?: string) =>\n key && row[key] !== null && row[key] !== undefined ? Number(row[key]) : null\n\n/**\n * Filtro cruzado a partir do gráfico: clicar num valor filtra o dashboard por ele (Ctrl/Cmd+clique\n * acumula; clicar de novo no único selecionado limpa). O gráfico deve ignorar o próprio filtro na\n * consulta (`ignoreFilters`) e só destacar a seleção.\n */\nexport function useClickFilter(dimension: string | undefined, enabled: boolean) {\n const { filters, setFilter } = useDashboard()\n const selected = enabled && dimension ? (filters[dimension] ?? []) : []\n\n const toggle = (value: FilterValue, event?: Pick<MouseEvent, 'ctrlKey' | 'metaKey'>) => {\n if (!enabled || !dimension) return\n if (event?.ctrlKey || event?.metaKey)\n setFilter(\n dimension,\n selected.includes(value) ? selected.filter((item) => item !== value) : [...selected, value]\n )\n else setFilter(dimension, selected.length === 1 && selected[0] === value ? [] : [value])\n }\n\n return {\n selected,\n /** Há seleção e este valor não está nela. */\n isDimmed: (value: FilterValue) => selected.length > 0 && !selected.includes(value),\n toggle,\n clear: () => {\n if (enabled && dimension && selected.length) setFilter(dimension, [])\n }\n }\n}\n\nexport function Legend({\n items,\n loading\n}: {\n items: { label: string; color: string }[]\n loading?: boolean\n}) {\n return (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n columnGap: 1.5,\n rowGap: 0.5,\n mb: 1,\n fontSize: 14,\n color: '#555',\n minHeight: 21\n }}\n >\n {items.map((item) => (\n <Box key={item.label} sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n <Box sx={{ width: 9, height: 9, borderRadius: '50%', bgcolor: item.color }} />\n {item.label}\n </Box>\n ))}\n {loading && <CircularProgress size={14} sx={{ ml: 'auto' }} />}\n </Box>\n )\n}\n\n/** Erro / carregando / sem dados no lugar do gráfico; `null` quando há o que desenhar (função, não componente). */\nexport function chartPlaceholder({\n height,\n error,\n isLoading,\n empty\n}: {\n height: number\n error: unknown\n isLoading: boolean\n empty: boolean\n}): ReactNode {\n if (!error && !empty) return null\n return (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: error ? 'error.main' : '#999'\n }}\n >\n {error\n ? 'Erro ao carregar o gráfico'\n : isLoading\n ? 'Carregando…'\n : 'Sem dados para os filtros selecionados'}\n </Box>\n )\n}\n\n/** `caption`: o que é o título (ex.: o rótulo da dimensão), em cinza acima dele. */\nexport function TooltipBox({\n title,\n caption,\n children\n}: {\n title: string\n caption?: string\n children: ReactNode\n}) {\n return (\n <Box sx={{ bgcolor: '#fff', border: '1px solid #ccc', p: 1, fontSize: 13 }}>\n {caption && <Box sx={{ fontSize: 11, color: '#777' }}>{caption}</Box>}\n <Box sx={{ fontWeight: 700 }}>{title}</Box>\n {children}\n </Box>\n )\n}\n","import type { DashboardRow, FilterValue } from '../types'\nimport { numberOf, OTHER_COLOR, seriesColor } from './chartKit'\n\n/**\n * Séries vindas de uma dimensão (o `series` do `BarChart`, a \"Legenda\" do Power BI): a consulta\n * devolve linhas longas (categoria, série, valor) e o gráfico precisa delas largas (categoria,\n * série 1, série 2, …).\n */\n\nexport type SeriesItem = {\n /** Chave da série no ponto do gráfico (`s0`, `s1`, …; o valor pode ter \".\" e o Recharts lê como caminho). */\n dataKey: string\n /** Valor da dimensão; `null` = linhas sem valor ou \"Outros\" (não filtram). */\n value: FilterValue | null\n label: string\n color: string\n others?: boolean\n}\n\nexport const EMPTY_SERIES_LABEL = '(em branco)'\nconst OTHERS = 'Outros'\n\nconst keyOf = (value: FilterValue | null) => (value === null ? '\\u0000' : String(value))\n\n/**\n * Séries a partir do domínio (série × medida sem filtros): ordenadas pelo total, maior primeiro, e\n * a cor segue essa ordem — como o domínio não depende dos filtros, cada valor tem sempre a mesma\n * cor. Além de `max`, as menores viram \"Outros\" (a última vaga), em cinza.\n */\nexport function seriesItems(\n domain: DashboardRow[],\n series: string,\n measure: string,\n max: number,\n format: (value: FilterValue) => string = String\n): SeriesItem[] {\n const ranked = domain\n .map((row) => ({ value: row[series] ?? null, amount: Math.abs(numberOf(row, measure) ?? 0) }))\n .sort((a, b) => b.amount - a.amount)\n const limit = Math.min(Math.max(max, 2), 8)\n const kept = ranked.length > limit ? ranked.slice(0, limit - 1) : ranked\n const items: SeriesItem[] = kept.map((item, index) => ({\n dataKey: `s${index}`,\n value: item.value,\n label: item.value === null ? EMPTY_SERIES_LABEL : format(item.value),\n color: seriesColor(index)\n }))\n if (ranked.length > kept.length) items.push(othersItem(ranked.length - kept.length))\n return items\n}\n\nconst othersItem = (count?: number): SeriesItem => ({\n dataKey: 'outros',\n value: null,\n label: count ? `${OTHERS} (${count})` : OTHERS,\n color: OTHER_COLOR,\n others: true\n})\n\nexport type SeriesPoint = { value: FilterValue; label: string } & Record<string, number | string>\n\n/**\n * Linhas (categoria, série, medida) → um ponto por categoria, na ordem da consulta, com o valor de\n * cada série em `dataKey`. Valor fora das séries soma em \"Outros\" (criado se o domínio não tinha).\n * Devolve só as séries com algum valor nos pontos (um filtro pode ter tirado uma delas).\n */\nexport function pivotSeries(\n rows: DashboardRow[],\n dimension: string,\n series: string,\n measure: string,\n items: SeriesItem[],\n format: (value: FilterValue) => string = String\n): { points: SeriesPoint[]; items: SeriesItem[] } {\n const all = [...items]\n const byValue = new Map(\n all.filter((item) => !item.others).map((item) => [keyOf(item.value), item])\n )\n const points = new Map<string, SeriesPoint>()\n const used = new Set<string>()\n for (const row of rows) {\n const value = row[dimension] ?? ''\n const key = String(value)\n let point = points.get(key)\n if (!point) {\n point = { value, label: format(value) }\n for (const item of all) point[item.dataKey] = 0\n points.set(key, point)\n }\n let item = byValue.get(keyOf(row[series] ?? null))\n if (!item) {\n item = all.find((other) => other.others)\n if (!item) {\n item = othersItem()\n all.push(item)\n for (const other of points.values()) other[item.dataKey] = 0\n }\n }\n const amount = numberOf(row, measure)\n if (amount) {\n point[item.dataKey] = Number(point[item.dataKey] ?? 0) + amount\n used.add(item.dataKey)\n }\n }\n return { points: [...points.values()], items: all.filter((item) => used.has(item.dataKey)) }\n}\n\n/** Soma das séries de um ponto (a altura da barra empilhada). */\nexport const pointTotal = (point: SeriesPoint, items: SeriesItem[]) =>\n items.reduce((total, item) => total + Number(point[item.dataKey] ?? 0), 0)\n","import { Box } from '@mui/material'\nimport type { MouseEvent } from 'react'\nimport {\n Bar,\n CartesianGrid,\n Cell,\n LabelList,\n BarChart as RechartsBarChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis\n} from 'recharts'\nimport type { ChartNumberFormat } from '../layout'\nimport type { FilterValue } from '../types'\nimport {\n chartPlaceholder,\n Legend,\n numberOf,\n seriesColor,\n TooltipBox,\n useClickFilter\n} from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatMeasure, measureFormat, measureFormatter } from './format'\nimport { pivotSeries, pointTotal, type SeriesItem, seriesItems } from './seriesPivot'\nimport { useModelQuery } from './useModelQuery'\n\ntype BarChartProps = {\n /** Dimensão das categorias. */\n dimension: string\n /** Uma série por medida (cores fixas pela posição); com `series`, só a primeira. */\n measures: string[]\n /**\n * Dimensão da legenda: quebra a medida pelos valores dela, uma série por valor (a \"Legenda\" do\n * Power BI). A cor de cada valor é fixa (ordem do total sem filtros), mesmo que um filtro tire\n * outro valor do gráfico.\n */\n series?: string\n formatSeries?: (value: FilterValue) => string\n /** Com `series`: as menores além dessa quantidade viram \"Outros\" (no máximo 8). Padrão: 6. */\n maxSeries?: number\n /** `horizontal` cabe nomes longos; com muitas categorias, rola dentro da altura. */\n orientation?: 'vertical' | 'horizontal'\n /** Empilha as séries (só faz sentido com partes de um total). */\n stacked?: boolean\n /** `dimension` = ordem da consulta; `desc`/`asc` = pela primeira medida (com `series`, pelo total). */\n sort?: 'dimension' | 'desc' | 'asc'\n /** Só os N primeiros depois de ordenar. */\n limit?: number\n formatDimension?: (value: FilterValue) => string\n /** Esconde categorias sem valor em nenhuma medida. */\n hideEmpty?: boolean\n /** Valores nas pontas das barras (até 30 categorias; acima disso, só tooltip). */\n showValues?: boolean\n clickToFilter?: boolean\n height?: number\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\nconst MAX_VALUE_LABELS = 30\n/** Altura de cada categoria no modo horizontal (barras finas, com respiro). */\nconst ROW_HEIGHT = 28\n\ntype Point = { value: FilterValue; label: string } & Record<string, number | string>\n\n/** Uma `<Bar>` do gráfico: uma medida ou um valor da série. */\ntype Bar = { dataKey: string; label: string; color: string; format: (value: number) => string } & (\n | { item?: undefined }\n | { item: SeriesItem }\n)\n\n/**\n * Barras de uma ou mais medidas por uma dimensão. Ex.:\n * `<BarChart dimension=\"navio\" measures={['custoTotal']} orientation=\"horizontal\" sort=\"desc\" limit={10} />`.\n * Com `series`, uma medida quebrada pelos valores de outra dimensão:\n * `<BarChart dimension=\"mes\" series=\"tipo_descarga\" measures={['volume']} stacked />`.\n */\nexport function BarChart({\n dimension,\n measures: measureList,\n series,\n formatSeries = String,\n maxSeries = 6,\n orientation = 'vertical',\n stacked = false,\n sort = 'dimension',\n limit,\n formatDimension = String,\n hideEmpty = true,\n showValues = true,\n clickToFilter = false,\n height = 360,\n labels,\n formats: formatsByMeasure,\n queryLabel\n}: BarChartProps) {\n const { meta, filters, setFilter } = useDashboard()\n // Com série, uma medida só\n const measures = series ? measureList.slice(0, 1) : measureList\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: series ? [dimension, series] : [dimension],\n measures,\n ignoreFilters: clickToFilter ? (series ? [dimension, series] : [dimension]) : undefined,\n label: queryLabel ?? `BarChart · ${dimension}`\n })\n // Valores da série sem filtro nenhum: a cor (e quem vira \"Outros\") não muda com os filtros\n const domain = useModelQuery({\n dimensions: series ? [series] : [],\n measures,\n ignoreFilters: Object.keys(filters),\n label: `${queryLabel ?? `BarChart · ${dimension}`} · séries`,\n skip: !series\n })\n const filter = useClickFilter(dimension, clickToFilter)\n const seriesFilter = useClickFilter(series, clickToFilter)\n const formats = measures.map((measure) => measureFormatter(meta, measure, 0, formatsByMeasure))\n const labelOf = (name: string) => fieldLabel(meta, name, labels)\n // Eixo de valores: formato da primeira medida, sem casas (os valores exatos ficam nos rótulos)\n const axisFormat = measures[0] ? measureFormat(meta, measures[0], formatsByMeasure) : undefined\n const formatTick = (value: number) =>\n formatMeasure(value, { ...axisFormat, decimals: axisFormat?.compact ? 1 : 0 }, 0)\n\n let data: Point[]\n let bars: Bar[]\n const first = measures[0]\n if (series && first) {\n const format = formats[0] ?? String\n const pivot = pivotSeries(\n rows,\n dimension,\n series,\n first,\n seriesItems(domain.rows, series, first, maxSeries, formatSeries),\n formatDimension\n )\n bars = pivot.items.map((item) => ({ ...item, item, format }))\n data = pivot.points\n } else {\n bars = measures.map((measure, index) => ({\n dataKey: measure,\n label: labelOf(measure),\n color: seriesColor(index),\n format: formats[index] ?? String\n }))\n data = rows.map((row) => {\n const value = row[dimension] ?? ''\n const point: Point = { value, label: formatDimension(value) }\n for (const measure of measures) point[measure] = numberOf(row, measure) ?? 0\n return point\n })\n }\n if (hideEmpty) data = data.filter((point) => bars.some((bar) => Number(point[bar.dataKey])))\n // Ordena pela primeira medida ou, com série, pelo total da barra\n const sortValue = (point: Point) =>\n series\n ? pointTotal(\n point,\n bars.map((bar) => bar.item).filter((item) => !!item)\n )\n : Number(point[first ?? ''])\n if (sort !== 'dimension' && first)\n data = [...data].sort((a, b) =>\n sort === 'desc' ? sortValue(b) - sortValue(a) : sortValue(a) - sortValue(b)\n )\n if (limit) data = data.slice(0, limit)\n\n const horizontal = orientation === 'horizontal'\n const showLabels = showValues && data.length <= MAX_VALUE_LABELS\n // Horizontal com muitas categorias: o gráfico cresce e a caixa rola\n const chartHeight = horizontal ? Math.max(height, data.length * ROW_HEIGHT + 24) : height\n const longest = Math.max(0, ...data.map((point) => point.label.length))\n\n const loading = isLoading || domain.isLoading\n const state = chartPlaceholder({\n height,\n error: error ?? domain.error,\n isLoading: loading,\n empty: !data.length\n })\n\n const ChartTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const point: Point = payload[0].payload\n // Com série, só as que têm valor nesta barra (e o total, se empilhado)\n const shown = series ? bars.filter((bar) => Number(point[bar.dataKey])) : bars\n const format = bars[0]?.format ?? String\n return (\n <TooltipBox title={point.label} caption={labelOf(dimension)}>\n {series && first && (\n <Box sx={{ fontSize: 11, color: '#777', mt: 0.5 }}>\n {labelOf(first)} por {labelOf(series).toLocaleLowerCase('pt-BR')}\n </Box>\n )}\n {shown.map((bar) => (\n <Box key={bar.dataKey} sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: bar.color }} />\n {bar.label}: {bar.format(Number(point[bar.dataKey]))}\n </Box>\n ))}\n {series && stacked && shown.length > 1 && (\n <Box sx={{ fontWeight: 700, mt: 0.5 }}>\n Total: {format(shown.reduce((total, bar) => total + Number(point[bar.dataKey]), 0))}\n </Box>\n )}\n </TooltipBox>\n )\n }\n\n const handleClick = (index: number, bar: Bar, event: MouseEvent) => {\n // Senão o clique sobe até o container, que limpa o filtro\n event.stopPropagation()\n const point = data[index]\n if (!point) return\n const value = bar.item?.value\n // Segmento de um valor da série: filtra as duas dimensões (sem valor/\"Outros\", só a categoria)\n if (!series || value === null || value === undefined) {\n filter.toggle(point.value, event)\n seriesFilter.clear()\n } else if (event.ctrlKey || event.metaKey) {\n filter.toggle(point.value, event)\n seriesFilter.toggle(value, event)\n } else {\n // Clicar de novo no único segmento selecionado limpa; senão seleciona só ele\n const sole = (selected: FilterValue[], item: FilterValue) =>\n selected.length === 1 && selected[0] === item\n const again = sole(filter.selected, point.value) && sole(seriesFilter.selected, value)\n setFilter(dimension, again ? [] : [point.value])\n setFilter(series, again ? [] : [value])\n }\n }\n const isDimmed = (point: Point, bar: Bar) => {\n if (filter.isDimmed(point.value)) return true\n if (!bar.item || !seriesFilter.selected.length) return false\n return bar.item.value === null || seriesFilter.isDimmed(bar.item.value)\n }\n const clearFilters = () => {\n filter.clear()\n seriesFilter.clear()\n }\n\n // Ponta arredondada só no fim da barra (no empilhado, só no último segmento)\n const radius = (index: number): [number, number, number, number] => {\n if (stacked && index < bars.length - 1) return [0, 0, 0, 0]\n return horizontal ? [0, 4, 4, 0] : [4, 4, 0, 0]\n }\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0 }}>\n <Legend\n items={series || bars.length > 1 ? bars.map(({ label, color }) => ({ label, color })) : []}\n loading={loading}\n />\n {state ?? (\n <Box\n onClick={clearFilters}\n sx={{\n height,\n overflowY: horizontal ? 'auto' : 'hidden',\n opacity: loading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Box sx={{ height: chartHeight }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsBarChart\n data={data}\n layout={horizontal ? 'vertical' : 'horizontal'}\n barGap={2}\n barCategoryGap=\"20%\"\n margin={\n horizontal\n ? { top: 4, right: showLabels ? 96 : 16, left: 8, bottom: 4 }\n : { top: showLabels ? 24 : 8, right: 8, left: 8, bottom: 0 }\n }\n >\n <CartesianGrid stroke=\"#eee\" vertical={horizontal} horizontal={!horizontal} />\n {horizontal ? (\n <>\n <XAxis\n type=\"number\"\n hide={showLabels}\n tick={{ fontSize: 12, fill: '#555' }}\n tickFormatter={formatTick}\n />\n <YAxis\n type=\"category\"\n dataKey=\"label\"\n interval={0}\n width={Math.min(220, longest * 7 + 12)}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={false}\n />\n </>\n ) : (\n <>\n <XAxis\n dataKey=\"label\"\n interval={data.length > MAX_VALUE_LABELS ? 'preserveStartEnd' : 0}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={{ stroke: '#ccc' }}\n />\n <YAxis\n hide={showLabels}\n tick={{ fontSize: 12, fill: '#555' }}\n tickFormatter={formatTick}\n width={72}\n />\n </>\n )}\n <Tooltip content={<ChartTooltip />} cursor={{ fill: 'rgba(0,0,0,.04)' }} />\n {bars.map((bar, index) => (\n <Bar\n key={bar.dataKey}\n dataKey={bar.dataKey}\n name={bar.label}\n fill={bar.color}\n stackId={stacked ? 'stack' : undefined}\n radius={radius(index)}\n maxBarSize={horizontal ? 18 : 56}\n isAnimationActive={false}\n onClick={\n clickToFilter\n ? (_bar, barIndex, event) => handleClick(barIndex, bar, event)\n : undefined\n }\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {clickToFilter &&\n data.map((point) => (\n <Cell\n key={String(point.value)}\n fillOpacity={isDimmed(point, bar) ? 0.35 : 1}\n />\n ))}\n {/* Empilhado: valor só no fim da pilha seria o total; fica no tooltip */}\n {showLabels && !stacked && (\n <LabelList\n dataKey={bar.dataKey}\n position={horizontal ? 'right' : 'top'}\n formatter={(value: unknown) => bar.format(value as number)}\n style={{ fontSize: 12, fill: '#333', fontWeight: 600 }}\n />\n )}\n </Bar>\n ))}\n </RechartsBarChart>\n </ResponsiveContainer>\n </Box>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, CircularProgress, Typography } from '@mui/material'\nimport type { MouseEvent } from 'react'\nimport {\n Bar,\n Cell,\n ComposedChart,\n LabelList,\n Line,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis\n} from 'recharts'\nimport type { ChartNumberFormat } from '../layout'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatMeasure, formatNumber, measureFormat } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype ComboChartProps = {\n /** Dimensão do eixo X. */\n dimension: string\n /** Medida das barras. */\n bar: string\n /** Medida da linha (eixo próprio, oculto; os valores aparecem nos pontos). */\n line: string\n /** Medida extra mostrada como segunda linha do rótulo da barra (ex.: volume). */\n detail?: string\n /**\n * Rótulos e formatos: sem a prop, vale o `labels`/`formats` do gráfico e depois o dicionário do\n * modelo (`label`, `format`).\n */\n barLabel?: string\n lineLabel?: string\n detailLabel?: string\n formatDimension?: (value: FilterValue) => string\n formatBar?: (value: number) => string\n formatLine?: (value: number) => string\n formatDetail?: (value: number) => string\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Esconde grupos cuja medida da barra é vazia/zero (como o Power BI faz). */\n hideEmpty?: boolean\n height?: number\n /** Rótulos de dados só até essa quantidade de barras (acima disso, só tooltip). */\n maxLabels?: number\n barColor?: string\n lineColor?: string\n /**\n * Clicar numa barra filtra o dashboard pelo valor dela (Ctrl/Cmd+clique acumula; clicar de novo\n * no único selecionado ou fora das barras limpa). O próprio gráfico ignora esse filtro e só\n * destaca a seleção, como o filtro cruzado do Power BI.\n */\n clickToFilter?: boolean\n /** Nome da consulta no devtools (padrão: `ComboChart · <dimensão>`). */\n queryLabel?: string\n}\n\n/** Mantém a linha na faixa de baixo do gráfico, longe dos rótulos que ficam em cima das barras. */\nconst lineDomain = ([min, max]: readonly number[]): [number, number] => {\n const range = max - min || Math.abs(max) || 1\n return [min - range * 0.3, max + range * 1.7]\n}\n\ntype Point = {\n value: FilterValue\n label: string\n bar: number\n line: number | null\n detail: number | null\n}\n\n/**\n * Barras + linha de uma dimensão, consultando o modelo do `DashboardProvider` (com os filtros dele).\n * Ex.: `<ComboChart dimension=\"mes\" bar=\"custoTotal\" line=\"custoTon\" detail=\"volTotal\" />`.\n */\nexport function ComboChart({\n dimension,\n bar,\n line,\n detail,\n barLabel,\n lineLabel,\n detailLabel,\n formatDimension = String,\n formatBar,\n formatLine,\n formatDetail,\n labels,\n formats,\n hideEmpty = true,\n height = 360,\n maxLabels = 24,\n barColor = '#F58220',\n lineColor = '#555',\n clickToFilter = false,\n queryLabel\n}: ComboChartProps) {\n const { meta, filters, setFilter } = useDashboard()\n // Prop > formato do gráfico > dicionário do modelo > padrão do componente\n // (sem `format` em nenhum dos dois, o do componente vale com as casas/prefixo de lá por cima)\n const fromModel = (measure: string, fallback: ChartNumberFormat) => {\n const format = measureFormat(meta, measure, formats)\n const resolved = format?.format ? format : { ...fallback, ...format }\n return (value: number) => formatMeasure(value, resolved, fallback.decimals)\n }\n formatBar ??= fromModel(bar, { format: 'currency', decimals: 0 })\n formatLine ??= fromModel(line, { decimals: 2 })\n formatDetail ??= detail ? fromModel(detail, { decimals: 3 }) : (value) => formatNumber(value, 3)\n barLabel ??= fieldLabel(meta, bar, labels)\n lineLabel ??= fieldLabel(meta, line, labels)\n detailLabel ??= detail && fieldLabel(meta, detail, labels)\n const dimensionLabel = fieldLabel(meta, dimension, labels)\n\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures: detail ? [bar, line, detail] : [bar, line],\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `ComboChart · ${dimension}`\n })\n\n const num = (row: DashboardRow, key?: string) =>\n key && row[key] !== null && row[key] !== undefined ? Number(row[key]) : null\n\n const data: Point[] = rows\n .filter((row) => !hideEmpty || num(row, bar))\n .map((row) => ({\n value: row[dimension] ?? '',\n label: formatDimension(row[dimension] ?? ''),\n bar: num(row, bar) ?? 0,\n line: num(row, line),\n detail: num(row, detail)\n }))\n\n const showLabels = data.length <= maxLabels\n\n const selected = clickToFilter ? (filters[dimension] ?? []) : []\n const isDimmed = (point: Point) => selected.length > 0 && !selected.includes(point.value)\n\n const handleBarClick = (index: number, event: MouseEvent) => {\n // Senão o clique sobe até o container do gráfico, que limpa o filtro\n event.stopPropagation()\n const point = data[index]\n if (!point) return\n if (event.ctrlKey || event.metaKey) {\n setFilter(\n dimension,\n selected.includes(point.value)\n ? selected.filter((value) => value !== point.value)\n : [...selected, point.value]\n )\n } else {\n const onlyThis = selected.length === 1 && selected[0] === point.value\n setFilter(dimension, onlyThis ? [] : [point.value])\n }\n }\n\n const clearFilter = () => {\n if (selected.length) setFilter(dimension, [])\n }\n\n const BarValueLabel = (props: any) => {\n const point = data[props.index]\n if (!point?.bar) return null\n const cx = Number(props.x) + Number(props.width) / 2\n const lines = [\n formatBar(point.bar),\n point.detail === null ? null : formatDetail(point.detail)\n ].filter((text): text is string => !!text)\n const top = Number(props.y) - 6 - lines.length * 15\n const width = Math.max(...lines.map((text) => text.length)) * 6.8 + 10\n return (\n <g>\n <rect\n x={cx - width / 2}\n y={top}\n width={width}\n height={lines.length * 15 + 4}\n rx={2}\n fill=\"#555\"\n />\n {lines.map((text, i) => (\n <text\n key={text}\n x={cx}\n y={top + 14 + i * 15}\n textAnchor=\"middle\"\n fill=\"#fff\"\n fontSize={12}\n fontWeight={700}\n >\n {text}\n </text>\n ))}\n </g>\n )\n }\n\n const LineValueLabel = (props: any) => {\n if (props.value === null || props.value === undefined) return null\n const text = formatLine(Number(props.value))\n const width = text.length * 7 + 10\n return (\n <g>\n <rect\n x={props.x - width / 2}\n y={props.y - 9}\n width={width}\n height={18}\n rx={2}\n fill=\"#d9d9d9\"\n />\n <text\n x={props.x}\n y={props.y + 4}\n textAnchor=\"middle\"\n fill=\"#222\"\n fontSize={12}\n fontWeight={700}\n >\n {text}\n </text>\n </g>\n )\n }\n\n const ChartTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const point: Point = payload[0].payload\n return (\n <Box sx={{ bgcolor: '#fff', border: '1px solid #ccc', p: 1, fontSize: 13 }}>\n <Typography sx={{ fontSize: 11, color: '#777' }}>{dimensionLabel}</Typography>\n <Typography sx={{ fontWeight: 700, fontSize: 13 }}>{point.label}</Typography>\n <div>\n {barLabel}: {formatBar(point.bar)}\n </div>\n {point.detail !== null && (\n <div>\n {detailLabel}: {formatDetail(point.detail)}\n </div>\n )}\n <div>\n {lineLabel}: {point.line === null ? '' : formatLine(point.line)}\n </div>\n </Box>\n )\n }\n\n const legend = [\n { label: barLabel, color: barColor },\n { label: lineLabel, color: lineColor }\n ]\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n <Box sx={{ display: 'flex', gap: 1.5, mb: 1, fontSize: 14, color: '#555' }}>\n {legend.map((item) => (\n <Box key={item.label} sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n <Box sx={{ width: 9, height: 9, borderRadius: '50%', bgcolor: item.color }} />\n {item.label}\n </Box>\n ))}\n {isLoading && <CircularProgress size={14} sx={{ ml: 'auto' }} />}\n </Box>\n {error ? (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'error.main'\n }}\n >\n Erro ao carregar o gráfico\n </Box>\n ) : !data.length ? (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#999'\n }}\n >\n {isLoading ? 'Carregando…' : 'Sem dados para os filtros selecionados'}\n </Box>\n ) : (\n <Box\n onClick={clickToFilter ? clearFilter : undefined}\n sx={{ height, opacity: isLoading ? 0.5 : 1, transition: 'opacity .2s' }}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <ComposedChart data={data} margin={{ top: showLabels ? 48 : 12, right: 8, left: 8 }}>\n <XAxis\n dataKey=\"label\"\n interval={0}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={false}\n />\n <YAxis yAxisId=\"bar\" hide domain={[0, 'auto']} />\n <YAxis yAxisId=\"line\" hide domain={lineDomain} />\n <Tooltip content={<ChartTooltip />} />\n <Bar\n yAxisId=\"bar\"\n dataKey=\"bar\"\n fill={barColor}\n isAnimationActive={false}\n onClick={\n clickToFilter ? (_bar, index, event) => handleBarClick(index, event) : undefined\n }\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {clickToFilter &&\n data.map((point) => (\n <Cell key={String(point.value)} fillOpacity={isDimmed(point) ? 0.35 : 1} />\n ))}\n {showLabels && <LabelList dataKey=\"bar\" content={<BarValueLabel />} />}\n </Bar>\n <Line\n yAxisId=\"line\"\n dataKey=\"line\"\n stroke={lineColor}\n strokeWidth={2}\n strokeDasharray=\"5 4\"\n dot={{ r: 2, fill: lineColor }}\n connectNulls\n isAnimationActive={false}\n >\n {showLabels && <LabelList dataKey=\"line\" content={<LineValueLabel />} />}\n </Line>\n </ComposedChart>\n </ResponsiveContainer>\n </Box>\n )}\n </Box>\n )\n}\n","import { useEffect, useState, useSyncExternalStore } from 'react'\nimport type { LayoutPart } from '../devtools/layoutStore'\nimport type { ChartsLayout } from '../layout'\nimport { useDashboard } from './DashboardProvider'\n\nconst noLayouts = () => () => {}\n\n/**\n * Layout em vigor: o do arquivo ou, com o devtools, o rascunho editado na aba Layout. Registra a\n * parte (`charts`/`filters`) para o devtools saber o que a página renderiza.\n */\nexport function useLayout(\n layout: ChartsLayout,\n part: LayoutPart,\n formatters: Record<string, unknown>\n): ChartsLayout {\n const { devtools } = useDashboard()\n const layouts = devtools?.layouts\n const formatterNames = Object.keys(formatters).sort().join(',')\n\n useEffect(\n () => layouts?.register(layout, part, formatterNames ? formatterNames.split(',') : []),\n [layouts, layout, part, formatterNames]\n )\n\n // Re-renderiza quando o rascunho muda\n useSyncExternalStore(\n layouts?.subscribe ?? noLayouts,\n () => layouts?.getSnapshot(),\n () => undefined\n )\n // O rascunho vem do sessionStorage: só depois de montar, para não divergir da hidratação\n const [mounted, setMounted] = useState(false)\n useEffect(() => setMounted(true), [])\n return (mounted && layouts?.draftOf(layout)) || layout\n}\n","import { Box } from '@mui/material'\nimport {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState\n} from 'react'\nimport type { ChartsLayout } from '../layout'\nimport { useLayout } from './useLayout'\n\n// No servidor o useLayoutEffect só gera aviso; lá não há o que medir\nconst useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect\n\nconst FixedCanvasContext = createContext(false)\n\n/** Dentro de um `<DashboardCanvas>` com tamanho fixo: o grid não troca de colunas pela tela. */\nexport const useFixedCanvas = () => useContext(FixedCanvasContext)\n\ntype DashboardCanvasProps = {\n /** O mesmo layout do `<DashboardCharts>` (`canvas` do JSON). */\n layout: ChartsLayout\n children: ReactNode\n}\n\n/**\n * Tela de tamanho fixo (`layout.canvas`, ex.: 1920×1080): desenha os filhos nessa largura e escala\n * tudo para caber na largura disponível, mantendo a proporção — numa tela menor o dashboard encolhe\n * em vez de reorganizar os gráficos. Sem `canvas` no layout, só renderiza os filhos (responsivo).\n *\n * ```tsx\n * <DashboardCanvas layout={layout}>\n * <DashboardFilters layout={layout} />\n * <DashboardCharts layout={layout} />\n * </DashboardCanvas>\n * ```\n *\n * A escala é um `transform`: os gráficos continuam medindo o tamanho de projeto (o Recharts compensa\n * a escala no mouse) e os breakpoints do MUI, que olham a janela, ficam desligados no grid.\n */\nexport function DashboardCanvas({ layout, children }: DashboardCanvasProps) {\n const { canvas } = useLayout(layout, 'canvas', {})\n const outer = useRef<HTMLDivElement>(null)\n const inner = useRef<HTMLDivElement>(null)\n // Largura disponível e altura de projeto do conteúdo (offsetHeight ignora o transform)\n const [size, setSize] = useState<{ available: number; content: number } | null>(null)\n\n useIsomorphicLayoutEffect(() => {\n if (!canvas || !outer.current || !inner.current) return\n const outerElement = outer.current\n const innerElement = inner.current\n const measure = () => {\n const next = { available: outerElement.clientWidth, content: innerElement.offsetHeight }\n // Mudar a altura do outer dispara o observer de novo: só re-renderiza se mudou algo\n setSize((current) =>\n current?.available === next.available && current.content === next.content ? current : next\n )\n }\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(outerElement)\n observer.observe(innerElement)\n return () => observer.disconnect()\n }, [canvas])\n\n if (!canvas) return <>{children}</>\n\n const scale = size ? size.available / canvas.width : 1\n return (\n <FixedCanvasContext.Provider value>\n <Box\n ref={outer}\n sx={{\n width: '100%',\n overflow: 'hidden',\n height: size ? size.content * scale : undefined\n }}\n >\n <Box\n ref={inner}\n sx={{\n width: canvas.width,\n minHeight: canvas.height,\n transform: `scale(${scale})`,\n transformOrigin: '0 0',\n // Antes de medir a escala é desconhecida: evita piscar no tamanho de projeto\n visibility: size ? undefined : 'hidden'\n }}\n >\n {children}\n </Box>\n </Box>\n </FixedCanvasContext.Provider>\n )\n}\n","import {\n Box,\n CircularProgress,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TableSortLabel\n} from '@mui/material'\nimport { useState } from 'react'\nimport { type FormatRule, type RuleStyle, rowRuleStyles } from '../formatRules'\nimport {\n type ChartNumberFormat,\n type ColumnAlign,\n type ColumnVerticalAlign,\n PERCENT_PREFIX as PERCENT,\n percentColumn,\n tableColumns\n} from '../layout'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { chartPlaceholder, useClickFilter } from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatNumber, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype SortDirection = 'asc' | 'desc'\n\ntype DataTableProps = {\n /** Uma linha por combinação de dimensões (sem dimensões, uma linha só). */\n dimensions?: string[]\n /** Uma coluna por medida, formatada pelo dicionário do modelo. */\n measures: string[]\n /**\n * Medidas com coluna de participação no total (valor da linha ÷ soma da coluna), logo depois da\n * coluna da medida. Medida fora de `measures` é consultada só para o percentual (coluna no fim).\n */\n percentOf?: string[]\n /** Formatter por dimensão. */\n formatDimensions?: Record<string, (value: FilterValue) => string>\n /**\n * Linha de total, consultada sem as dimensões: razões (custo/t) saem do total, não da soma das\n * linhas.\n */\n showTotal?: boolean\n /**\n * Coluna da ordem inicial (dimensão, medida ou `%:medida`); quem usa reordena clicando no\n * cabeçalho. Dimensão/medida fora da tabela entra na consulta sem coluna (ex.: número do mês para\n * ordenar o nome do mês) — uma dimensão de fora divide as linhas se tiver mais de um valor por linha.\n */\n sortBy?: string\n sortDirection?: SortDirection\n /** Clicar numa linha filtra o dashboard pela primeira dimensão. */\n clickToFilter?: boolean\n /** Altura máxima; a tabela rola com o cabeçalho fixo. */\n height?: number\n /** Cabeçalho por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Casas decimais das colunas de percentual. Padrão: 1. */\n percentDecimals?: number\n /**\n * Ordem das colunas misturando dimensões, medidas e percentuais (ex.: `['custoTotal',\n * '%:custoTotal', 'navio']`); o que não estiver nela vai depois. Padrão: dimensões e depois\n * medidas, cada percentual logo depois da medida.\n */\n columnOrder?: string[]\n /**\n * Formatação condicional: cor do texto/fundo e negrito da célula ou da linha conforme o valor de\n * uma dimensão/medida (da tabela, de fora dela ou `%:medida`).\n */\n formatRules?: FormatRule[]\n /** Bordas entre as células (grade). Padrão: só a linha embaixo de cada linha. */\n cellBorders?: boolean\n /** Cor das bordas da grade. Padrão: `#e0e0e0`. */\n borderColor?: string\n /**\n * Alinhamento horizontal por coluna (`%:medida` para o percentual): cabeçalho, células e total.\n * Padrão: dimensão à esquerda, número à direita.\n */\n align?: Record<string, ColumnAlign>\n /** Alinhamento vertical por coluna (`top`, `middle`, `bottom`). Padrão: `middle`. */\n verticalAlign?: Record<string, ColumnVerticalAlign>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\nconst EMPTY: string[] = []\nconst NO_RULES: FormatRule[] = []\n\nfunction compare(a: DashboardRow[string], b: DashboardRow[string]) {\n // Vazios sempre por último, nas duas direções (tratado por quem chama)\n if (typeof a === 'number' && typeof b === 'number') return a - b\n return String(a).localeCompare(String(b), 'pt-BR', { numeric: true })\n}\n\n/**\n * Tabela de medidas por dimensões, com total e ordenação pelo cabeçalho. Ex.:\n * `<DataTable dimensions={['navio']} measures={['volTotal', 'custoTotal', 'custoTon']} />`.\n */\nexport function DataTable({\n dimensions = EMPTY,\n measures,\n percentOf = EMPTY,\n formatDimensions = {},\n showTotal = true,\n sortBy,\n sortDirection = 'desc',\n clickToFilter = false,\n height = 400,\n labels,\n formats: formatsByMeasure,\n percentDecimals = 1,\n columnOrder,\n formatRules = NO_RULES,\n cellBorders = false,\n borderColor = '#e0e0e0',\n align,\n verticalAlign,\n queryLabel\n}: DataTableProps) {\n const { meta } = useDashboard()\n const name = queryLabel ?? `DataTable · ${dimensions.join(', ') || 'total'}`\n const firstDimension = dimensions[0]\n const ignoreFilters = clickToFilter && firstDimension ? [firstDimension] : undefined\n const extraMeasures = percentOf.filter((measure) => !measures.includes(measure))\n // Dimensões/medidas fora da tabela (ordem inicial, regras): consultadas sem coluna. Saber se é\n // dimensão ou medida depende do dicionário; até ele chegar, a consulta espera\n const outside = [\n ...new Set([sortBy, ...formatRules.map((rule) => rule.field)].filter(Boolean) as string[])\n ].filter(\n (field) =>\n !field.startsWith(PERCENT) &&\n !dimensions.includes(field) &&\n !measures.includes(field) &&\n !extraMeasures.includes(field)\n )\n const waitingMeta = outside.length > 0 && !meta\n const queryDimensions = [...dimensions, ...outside.filter((field) => meta?.dimensions[field])]\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: queryDimensions,\n measures: [\n ...measures,\n ...extraMeasures,\n ...outside.filter((field) => meta?.measures[field] && !meta.dimensions[field])\n ],\n ignoreFilters,\n label: name,\n skip: waitingMeta\n })\n // Sem dimensões a própria consulta já é o total\n const totals = useModelQuery({\n measures,\n ignoreFilters,\n label: `${name} · total`,\n skip: !showTotal || !dimensions.length\n })\n const filter = useClickFilter(firstDimension, clickToFilter)\n\n const [sort, setSort] = useState<{ by?: string; direction: SortDirection }>({\n by: sortBy,\n direction: sortDirection\n })\n // Props mudaram (ex.: devtools): volta para a ordem configurada\n const [configured, setConfigured] = useState([sortBy, sortDirection])\n if (configured[0] !== sortBy || configured[1] !== sortDirection) {\n setConfigured([sortBy, sortDirection])\n setSort({ by: sortBy, direction: sortDirection })\n }\n\n // O percentual ordena igual à medida\n const sortKey = sort.by?.startsWith(PERCENT) ? sort.by.slice(PERCENT.length) : sort.by\n const sorted = sortKey\n ? [...rows].sort((a, b) => {\n const [x, y] = [a[sortKey], b[sortKey]]\n if (x === null || x === undefined) return 1\n if (y === null || y === undefined) return -1\n return sort.direction === 'asc' ? compare(x, y) : compare(y, x)\n })\n : rows\n\n const formats = Object.fromEntries(\n measures.map((measure) => [measure, measureFormatter(meta, measure, 2, formatsByMeasure)])\n )\n const formatPercent = (value: number | null) =>\n value === null ? '' : `${formatNumber(value * 100, percentDecimals)}%`\n const dimensionText = (dimension: string, value: DashboardRow[string]) =>\n value === null || value === undefined\n ? '(vazio)'\n : (formatDimensions[dimension] ?? String)(value)\n const labelOf = (column: string) => fieldLabel(meta, column, labels)\n const headerOf = (column: string) => {\n if (!column.startsWith(PERCENT)) return labelOf(column)\n const measure = column.slice(PERCENT.length)\n return measures.includes(measure) ? '%' : `% ${labelOf(measure)}`\n }\n\n // Total de cada medida com percentual: soma das linhas mostradas\n const sums = Object.fromEntries(\n percentOf.map((measure) => [\n measure,\n rows.reduce((total, row) => total + (Number(row[measure]) || 0), 0)\n ])\n )\n const percentOfRow = (row: DashboardRow, measure: string) => {\n const value = row[measure]\n const total = sums[measure]\n return value === null || value === undefined || !total ? null : Number(value) / total\n }\n // Colunas na ordem configurada; percentual fora dela logo depois da medida (avulsos no fim)\n const columns = tableColumns(\n [...dimensions, ...measures],\n percentOf.filter((measure) => !dimensions.includes(measure)),\n columnOrder\n )\n // Estilo das regras por coluna; percentuais entram na linha avaliada como `%:medida`\n const ruleStyles = (row: DashboardRow): Record<string, RuleStyle> | undefined => {\n if (!formatRules.length) return undefined\n const evaluated = { ...row }\n for (const measure of percentOf) evaluated[percentColumn(measure)] = percentOfRow(row, measure)\n return rowRuleStyles(formatRules, evaluated, columns)\n }\n const ruleSx = (style: RuleStyle | undefined) =>\n style && {\n ...(style.color && { color: style.color }),\n ...(style.background && { bgcolor: style.background }),\n ...(style.bold && { fontWeight: 700 }),\n ...(style.align && { textAlign: style.align }),\n ...(style.verticalAlign && { verticalAlign: style.verticalAlign })\n }\n const isDimension = (column: string) => dimensions.includes(column)\n const alignOf = (column: string) => align?.[column] ?? (isDimension(column) ? 'left' : 'right')\n const verticalOf = (column: string) => verticalAlign?.[column] ?? 'middle'\n // \"Total\" vai na primeira coluna de dimensão da tabela\n const totalLabelColumn = columns.find(isDimension)\n const cellText = (row: DashboardRow, column: string) =>\n column.startsWith(PERCENT)\n ? formatPercent(percentOfRow(row, column.slice(PERCENT.length)))\n : formats[column]?.(row[column])\n\n const toggleSort = (column: string) =>\n setSort((current) =>\n current.by === column\n ? { by: column, direction: current.direction === 'asc' ? 'desc' : 'asc' }\n : // Medidas começam do maior; dimensões, em ordem alfabética\n { by: column, direction: dimensions.includes(column) ? 'asc' : 'desc' }\n )\n\n const totalRow = dimensions.length ? totals.rows[0] : undefined\n const loading = isLoading || waitingMeta\n const placeholder = chartPlaceholder({\n height: 160,\n error,\n isLoading: loading,\n empty: !rows.length\n })\n\n const header = (column: string, numeric: boolean) => (\n <TableCell\n key={column}\n align={alignOf(column)}\n sortDirection={sort.by === column ? sort.direction : false}\n sx={{\n fontWeight: 700,\n bgcolor: '#f3f3f3',\n whiteSpace: 'nowrap',\n verticalAlign: verticalOf(column)\n }}\n >\n <TableSortLabel\n active={sort.by === column}\n direction={sort.by === column ? sort.direction : numeric ? 'desc' : 'asc'}\n onClick={() => toggleSort(column)}\n >\n {headerOf(column)}\n </TableSortLabel>\n </TableCell>\n )\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {loading && <CircularProgress size={14} sx={{ position: 'absolute', top: -22, right: 0 }} />}\n {placeholder ?? (\n <Box\n sx={{\n maxHeight: height,\n overflow: 'auto',\n opacity: loading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Table\n size=\"small\"\n stickyHeader\n sx={{\n '& td, & th': {\n fontSize: 13,\n ...(cellBorders && { border: `1px solid ${borderColor}` })\n }\n }}\n >\n <TableHead>\n <TableRow>{columns.map((column) => header(column, !isDimension(column)))}</TableRow>\n </TableHead>\n <TableBody>\n {sorted.map((row) => {\n const value = firstDimension ? row[firstDimension] : null\n const clickable = clickToFilter && value !== null && value !== undefined\n const styles = ruleStyles(row)\n return (\n <TableRow\n key={queryDimensions.map((dimension) => String(row[dimension])).join('\\u0000')}\n hover\n onClick={clickable ? (event) => filter.toggle(value, event) : undefined}\n selected={clickable && filter.selected.includes(value)}\n sx={{\n cursor: clickable ? 'pointer' : undefined,\n opacity: clickable && filter.isDimmed(value) ? 0.5 : 1\n }}\n >\n {columns.map((column) =>\n isDimension(column) ? (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ verticalAlign: verticalOf(column), ...ruleSx(styles?.[column]) }}\n >\n {dimensionText(column, row[column])}\n </TableCell>\n ) : (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{\n whiteSpace: 'nowrap',\n verticalAlign: verticalOf(column),\n ...ruleSx(styles?.[column])\n }}\n >\n {cellText(row, column)}\n </TableCell>\n )\n )}\n </TableRow>\n )\n })}\n {totalRow && (\n <TableRow\n sx={{\n '& td': {\n fontWeight: 700,\n position: 'sticky',\n bottom: 0,\n bgcolor: '#f3f3f3',\n borderTop: '2px solid #ddd'\n }\n }}\n >\n {columns.map((column) =>\n isDimension(column) ? (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ verticalAlign: verticalOf(column) }}\n >\n {column === totalLabelColumn ? 'Total' : ''}\n </TableCell>\n ) : (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ whiteSpace: 'nowrap', verticalAlign: verticalOf(column) }}\n >\n {column.startsWith(PERCENT)\n ? formatPercent(sums[column.slice(PERCENT.length)] ? 1 : null)\n : formats[column]?.(totalRow[column])}\n </TableCell>\n )\n )}\n </TableRow>\n )}\n </TableBody>\n </Table>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box } from '@mui/material'\nimport { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts'\nimport type { ChartNumberFormat } from '../layout'\nimport type { FilterValue } from '../types'\nimport {\n chartPlaceholder,\n numberOf,\n OTHER_COLOR,\n seriesColor,\n TooltipBox,\n useClickFilter\n} from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatNumber, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype DonutChartProps = {\n /** Dimensão das fatias. */\n dimension: string\n /** Medida somável (partes de um total). Valores negativos ou zerados ficam de fora. */\n measure: string\n /** Fatias além dessa quantidade viram \"Outros\" (no máximo 8, o tamanho da paleta). */\n maxSlices?: number\n formatDimension?: (value: FilterValue) => string\n clickToFilter?: boolean\n height?: number\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Casas decimais do percentual. Padrão: 1. */\n percentDecimals?: number\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\ntype Slice = {\n key: string\n value: FilterValue | null\n label: string\n amount: number\n color: string\n}\n\nconst OTHERS = 'Outros'\n\n/**\n * Rosca de uma medida por uma dimensão, com o total no centro e a legenda ao lado (nome, % e valor).\n * Ex.: `<DonutChart dimension=\"operacao_status\" measure=\"custoTotal\" />`.\n */\nexport function DonutChart({\n dimension,\n measure,\n maxSlices = 6,\n formatDimension = String,\n clickToFilter = false,\n height = 300,\n labels,\n formats,\n percentDecimals = 1,\n queryLabel\n}: DonutChartProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures: [measure],\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `DonutChart · ${dimension}`\n })\n const filter = useClickFilter(dimension, clickToFilter)\n const format = measureFormatter(meta, measure, 0, formats)\n\n const positive = rows\n .map((row) => ({ value: row[dimension] ?? '', amount: numberOf(row, measure) ?? 0 }))\n .filter((item) => item.amount > 0)\n .sort((a, b) => b.amount - a.amount)\n const limit = Math.min(Math.max(maxSlices, 2), 8)\n // Com fatias sobrando, a última vaga vira \"Outros\"\n const kept = positive.length > limit ? positive.slice(0, limit - 1) : positive\n const rest = positive.slice(kept.length)\n // A cor segue a posição na ordem (maior = laranja); \"Outros\" é neutro\n const slices: Slice[] = kept.map((item, index) => ({\n key: String(item.value),\n value: item.value,\n label: formatDimension(item.value),\n amount: item.amount,\n color: seriesColor(index)\n }))\n if (rest.length)\n slices.push({\n key: `\\u0000${OTHERS}`,\n value: null,\n label: `${OTHERS} (${rest.length})`,\n amount: rest.reduce((total, item) => total + item.amount, 0),\n color: OTHER_COLOR\n })\n const total = slices.reduce((sum, slice) => sum + slice.amount, 0)\n const percent = (amount: number) => `${formatNumber((amount / total) * 100, percentDecimals)}%`\n\n const placeholder = chartPlaceholder({ height, error, isLoading, empty: !slices.length })\n\n const select = (slice: Slice | undefined, event?: { ctrlKey: boolean; metaKey: boolean }) => {\n if (slice?.value !== null && slice?.value !== undefined) filter.toggle(slice.value, event)\n }\n const dimmed = (slice: Slice) =>\n filter.selected.length > 0 && (slice.value === null || filter.isDimmed(slice.value))\n\n const SliceTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const slice: Slice = payload[0].payload\n return (\n <TooltipBox title={slice.label} caption={fieldLabel(meta, dimension, labels)}>\n {fieldLabel(meta, measure, labels)}: {format(slice.amount)} · {percent(slice.amount)}\n </TooltipBox>\n )\n }\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {placeholder ?? (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n gap: 2,\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Box sx={{ position: 'relative', height: '100%', flex: '0 0 50%', minWidth: 140 }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <PieChart>\n <Tooltip content={<SliceTooltip />} />\n <Pie\n data={slices}\n dataKey=\"amount\"\n nameKey=\"label\"\n innerRadius=\"62%\"\n outerRadius=\"92%\"\n startAngle={90}\n endAngle={-270}\n stroke=\"#fff\"\n strokeWidth={2}\n isAnimationActive={false}\n onClick={(_, index, event) => select(slices[index], event)}\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {slices.map((slice) => (\n <Cell\n key={slice.key}\n fill={slice.color}\n fillOpacity={dimmed(slice) ? 0.35 : 1}\n />\n ))}\n </Pie>\n </PieChart>\n </ResponsiveContainer>\n {/* Total no furo da rosca */}\n <Box\n sx={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n textAlign: 'center'\n }}\n >\n <Box sx={{ fontSize: 12, color: '#777' }}>Total</Box>\n <Box sx={{ fontSize: 15, fontWeight: 700, color: '#333' }}>{format(total)}</Box>\n </Box>\n </Box>\n <Box\n component=\"ul\"\n sx={{\n listStyle: 'none',\n m: 0,\n p: 0,\n minWidth: 0,\n flex: 1,\n overflow: 'auto',\n maxHeight: '100%'\n }}\n >\n {slices.map((slice) => (\n <Box\n component=\"li\"\n key={slice.key}\n onClick={(event) => select(slice, event)}\n sx={{\n display: 'grid',\n gridTemplateColumns: '10px minmax(0, 1fr) auto',\n alignItems: 'center',\n columnGap: 0.75,\n py: 0.5,\n fontSize: 13,\n color: '#333',\n opacity: dimmed(slice) ? 0.45 : 1,\n cursor: clickToFilter && slice.value !== null ? 'pointer' : undefined\n }}\n >\n <Box sx={{ width: 10, height: 10, borderRadius: '50%', bgcolor: slice.color }} />\n <Box sx={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {slice.label}\n </Box>\n <Box sx={{ fontWeight: 700, textAlign: 'right' }}>{percent(slice.amount)}</Box>\n <Box />\n <Box sx={{ gridColumn: '2 / 4', fontSize: 12, color: '#777' }}>\n {format(slice.amount)}\n </Box>\n </Box>\n ))}\n </Box>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, CircularProgress } from '@mui/material'\nimport type { ChartNumberFormat } from '../layout'\nimport { numberOf } from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype KpiCardProps = {\n /** Medida do número grande: o total com os filtros da página. */\n measure: string\n /** Rótulo acima do número (no `<DashboardCharts>`, o título do painel faz esse papel). */\n label?: string\n /** Medida extra numa linha menor embaixo (ex.: volume, custo/t). */\n secondary?: string\n /** Padrão: `labels[secondary]` ou o `label` da medida secundária no dicionário. */\n secondaryLabel?: string\n /** Rótulo por medida (sobrepõe o dicionário); o da principal entra quando não há `label`. */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário). */\n formats?: Record<string, ChartNumberFormat>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\n/**\n * Card com o total de uma medida (e, opcionalmente, uma segunda medida embaixo). Uma consulta sem\n * dimensões: razões (custo/t) saem do total, não de uma média. Ex.:\n * `<KpiCard label=\"Custo total\" measure=\"custoTotal\" secondary=\"custoTon\" />`.\n */\nexport function KpiCard({\n measure,\n label,\n secondary,\n secondaryLabel,\n labels,\n formats,\n queryLabel\n}: KpiCardProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n measures: secondary ? [measure, secondary] : [measure],\n label: queryLabel ?? `KpiCard · ${measure}`\n })\n const row = rows[0]\n const value = row ? numberOf(row, measure) : null\n const extra = row && secondary ? numberOf(row, secondary) : null\n label ??= labels?.[measure]\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {label && <Box sx={{ fontSize: 13, color: '#666', mb: 0.5 }}>{label}</Box>}\n {isLoading && <CircularProgress size={12} sx={{ position: 'absolute', top: 0, right: 0 }} />}\n <Box\n sx={{\n fontSize: 28,\n fontWeight: 700,\n lineHeight: 1.2,\n color: error ? 'error.main' : '#333',\n fontVariantNumeric: 'tabular-nums',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n {error ? 'Erro' : value === null ? '—' : measureFormatter(meta, measure, 0, formats)(value)}\n </Box>\n {secondary && (\n <Box sx={{ fontSize: 13, color: '#666', mt: 0.25, minHeight: 20 }}>\n {secondaryLabel ?? fieldLabel(meta, secondary, labels)}:{' '}\n <Box component=\"span\" sx={{ fontWeight: 600, color: '#444' }}>\n {extra === null ? '—' : measureFormatter(meta, secondary, 2, formats)(extra)}\n </Box>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, Paper, Typography } from '@mui/material'\nimport type { ComponentType, ReactNode } from 'react'\nimport { LAYOUT_ITEM_ATTRIBUTE, layoutItemKey } from '../devtools/layoutStore'\nimport {\n type CardStyle,\n type ChartDef,\n type ChartsLayout,\n chartCardStyle,\n customChartProps,\n isBuiltinChart,\n LAYOUT_COLUMNS\n} from '../layout'\nimport type { FilterValue } from '../types'\nimport { BarChart } from './BarChart'\nimport { ComboChart } from './ComboChart'\nimport { useFixedCanvas } from './DashboardCanvas'\nimport { useDashboard } from './DashboardProvider'\nimport { DataTable } from './DataTable'\nimport { DonutChart } from './DonutChart'\nimport { KpiCard } from './KpiCard'\nimport { useLayout } from './useLayout'\n\nexport type ChartPanelProps = {\n title: string\n chart: ChartDef\n /** Estilo do card (`cards` do layout com o `card` do gráfico por cima); vazio = padrão. */\n card: CardStyle\n children: ReactNode\n}\n\ntype DashboardChartsProps = {\n /** Layout importado do JSON (`src/dashboard/layouts/<id>.json`). */\n layout: ChartsLayout\n /** Formatters por nome, referenciados no JSON por `formatDimension`. */\n formatters?: Record<string, (value: FilterValue) => string>\n /** Moldura de cada gráfico (título + conteúdo). */\n panel?: ComponentType<ChartPanelProps>\n /** Espaço entre os cards (unidades do `theme.spacing`); o `cards.gap` do layout (px) tem prioridade. */\n gap?: number\n}\n\nfunction DefaultPanel({ title, card, children }: ChartPanelProps) {\n const px = (value: number | undefined) => (value === undefined ? undefined : `${value}px`)\n return (\n <Paper\n elevation={card.shadow ?? 0}\n sx={{\n p: px(card.padding) ?? 1.5,\n minWidth: 0,\n height: '100%',\n bgcolor: card.background,\n border: `${card.borderWidth ?? 1}px solid`,\n borderColor: card.borderColor ?? 'divider',\n borderRadius: px(card.borderRadius)\n }}\n >\n {title && (\n <Typography\n sx={{\n fontWeight: 700,\n mb: 1,\n color: card.titleColor,\n fontSize: px(card.titleSize),\n textAlign: card.titleAlign\n }}\n >\n {title}\n </Typography>\n )}\n {children}\n </Paper>\n )\n}\n\n/**\n * Renderiza os gráficos de um layout declarativo num grid de 12 colunas (no celular, um por linha;\n * dentro de um `<DashboardCanvas>` de tamanho fixo, sempre as 12). Em desenvolvimento, a aba\n * Layout do devtools edita esse layout ao vivo (rascunho) e grava o JSON de volta.\n *\n * ```tsx\n * import layout from '@/dashboard/layouts/analiseCusto.json'\n * <DashboardCharts layout={layout as ChartsLayout} formatters={{ nomeMes }} panel={Panel} />\n * ```\n */\nexport function DashboardCharts({\n layout,\n formatters = {},\n panel: Panel = DefaultPanel,\n gap = 1.5\n}: DashboardChartsProps) {\n const current = useLayout(layout, 'charts', formatters)\n const { charts } = current\n // Tela fixa: a janela não decide as colunas, o canvas é que escala\n const fixed = useFixedCanvas()\n const columns = `repeat(${LAYOUT_COLUMNS}, minmax(0, 1fr))`\n\n return (\n <Box\n sx={{\n display: 'grid',\n gap: current.cards?.gap === undefined ? gap : `${current.cards.gap}px`,\n gridTemplateColumns: fixed ? columns : { xs: '1fr', lg: columns }\n }}\n >\n {charts.map((chart) => (\n <Box\n key={chart.id}\n {...{\n [LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, { kind: 'chart', key: chart.id })\n }}\n sx={{\n minWidth: 0,\n gridColumn: fixed\n ? `span ${chart.span ?? LAYOUT_COLUMNS}`\n : { lg: `span ${chart.span ?? LAYOUT_COLUMNS}` }\n }}\n >\n <Panel title={chart.title} chart={chart} card={chartCardStyle(current, chart)}>\n <Chart chart={chart} formatters={formatters} />\n </Panel>\n </Box>\n ))}\n </Box>\n )\n}\n\ntype Formatters = Record<string, (value: FilterValue) => string>\n\nfunction Chart({ chart, formatters }: { chart: ChartDef; formatters: Formatters }) {\n const { chartTypes, chartComponents } = useDashboard()\n if (!isBuiltinChart(chart)) {\n const Component = chartComponents[chart.type]\n if (Component) return <Component {...customChartProps(chart, chartTypes, formatters)} />\n return <UnknownChart type={chart.type} />\n }\n const queryLabel = `${chart.title || chart.id} · ${chart.type}`\n const formatter = (name?: string) => (name ? formatters[name] : undefined)\n switch (chart.type) {\n case 'kpi': {\n const { id, type, title, span, card, ...props } = chart\n return <KpiCard {...props} queryLabel={queryLabel} />\n }\n case 'combo': {\n const { id, type, title, span, card, formatDimension, ...props } = chart\n return (\n <ComboChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n />\n )\n }\n case 'bar': {\n const { id, type, title, span, card, formatDimension, formatSeries, ...props } = chart\n return (\n <BarChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n formatSeries={formatter(formatSeries)}\n />\n )\n }\n case 'donut': {\n const { id, type, title, span, card, formatDimension, ...props } = chart\n return (\n <DonutChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n />\n )\n }\n case 'table': {\n const { id, type, title, span, card, formatDimensions, ...props } = chart\n const resolved: Formatters = {}\n for (const [dimension, name] of Object.entries(formatDimensions ?? {})) {\n const format = formatter(name)\n if (format) resolved[dimension] = format\n }\n return <DataTable {...props} queryLabel={queryLabel} formatDimensions={resolved} />\n }\n default:\n return <UnknownChart type={(chart as { type: unknown }).type} />\n }\n}\n\nfunction UnknownChart({ type }: { type: unknown }) {\n return (\n <Box sx={{ color: 'error.main', p: 2 }}>\n Tipo de gráfico desconhecido: {String(type)} (tipos do app vão no{' '}\n <code>{'<DashboardProvider charts>'}</code>)\n </Box>\n )\n}\n","import {\n Checkbox,\n FormControl,\n InputLabel,\n ListItemText,\n MenuItem,\n OutlinedInput,\n Select\n} from '@mui/material'\nimport type { FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\nimport { useModelQuery } from './useModelQuery'\n\ntype FilterSelectProps = {\n dimension: string\n /** Padrão: `label` da dimensão no dicionário do modelo. */\n label?: string\n formatLabel?: (value: FilterValue) => string\n width?: number\n}\n\n/**\n * Filtro de múltipla escolha de uma dimensão. As opções vêm do próprio modelo e respeitam os\n * DEMAIS filtros (filtro cruzado): com Mês = Janeiro, o filtro de navio só lista quem atracou em\n * janeiro. Nada selecionado = \"Todos\".\n */\nexport function FilterSelect({\n dimension,\n label,\n formatLabel = String,\n width = 200\n}: FilterSelectProps) {\n const { filters, setFilter, meta } = useDashboard()\n label ??= meta?.dimensions[dimension]?.label ?? dimension\n const { rows, inspectProps } = useModelQuery({\n dimensions: [dimension],\n ignoreFilters: [dimension],\n label: `FilterSelect · ${dimension}`\n })\n\n const selected = filters[dimension] ?? []\n const options = rows\n .map((row) => row[dimension])\n .filter((value): value is FilterValue => value !== null && value !== '')\n // Mantém visíveis valores selecionados que sumiram das opções por causa de outro filtro\n for (const value of selected) if (!options.includes(value)) options.push(value)\n\n return (\n <FormControl {...inspectProps} size=\"small\" sx={{ width }}>\n <InputLabel shrink>{label}</InputLabel>\n <Select<FilterValue[]>\n multiple\n displayEmpty\n value={selected}\n onChange={(event) => setFilter(dimension, event.target.value as FilterValue[])}\n input={<OutlinedInput notched label={label} />}\n renderValue={(values) => (values.length ? values.map(formatLabel).join(', ') : 'Todos')}\n MenuProps={{ slotProps: { paper: { sx: { maxHeight: 360 } } } }}\n sx={{ bgcolor: '#fff' }}\n >\n {options.map((option) => (\n <MenuItem key={option} value={option} dense>\n <Checkbox size=\"small\" checked={selected.includes(option)} sx={{ p: 0.5, mr: 1 }} />\n <ListItemText primary={formatLabel(option)} />\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n )\n}\n","import { Box } from '@mui/material'\nimport { LAYOUT_ITEM_ATTRIBUTE, layoutItemKey } from '../devtools/layoutStore'\nimport type { ChartsLayout } from '../layout'\nimport type { FilterValue } from '../types'\nimport { FilterSelect } from './FilterSelect'\nimport { useLayout } from './useLayout'\n\ntype DashboardFiltersProps = {\n /** O mesmo layout do `<DashboardCharts>` (`filters` do JSON). */\n layout: ChartsLayout\n /** Formatters por nome, referenciados no JSON por `formatLabel`. */\n formatters?: Record<string, (value: FilterValue) => string>\n gap?: number\n}\n\n/**\n * Filtros (slicers) declarados em `layout.filters`, na ordem. Em desenvolvimento, a aba Layout do\n * devtools adiciona, remove, reordena e edita os filtros ao vivo.\n */\nexport function DashboardFilters({ layout, formatters = {}, gap = 2 }: DashboardFiltersProps) {\n const { filters = [] } = useLayout(layout, 'filters', formatters)\n return (\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap }}>\n {filters.map((filter) => (\n <Box\n key={filter.dimension}\n {...{\n [LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, {\n kind: 'filter',\n key: filter.dimension\n })\n }}\n >\n <FilterSelect\n dimension={filter.dimension}\n label={filter.label}\n width={filter.width}\n formatLabel={filter.formatLabel ? formatters[filter.formatLabel] : undefined}\n />\n </Box>\n ))}\n </Box>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,gBAAgB;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAa,cAAc;AAE3B,MAAa,eAAe,UAAkB,cAAc,QAAQ,cAAc;;AAGlF,MAAa,YAAY,KAAmB,QAC1C,OAAO,IAAI,SAAS,QAAQ,IAAI,SAAS,KAAA,IAAY,OAAO,IAAI,IAAI,IAAI;;;;;;AAO1E,SAAgB,eAAe,WAA+B,SAAkB;CAC9E,MAAM,EAAE,SAAS,cAAc,aAAa;CAC5C,MAAM,WAAW,WAAW,YAAa,QAAQ,cAAc,CAAC,IAAK,CAAC;CAEtE,MAAM,UAAU,OAAoB,UAAoD;EACtF,IAAI,CAAC,WAAW,CAAC,WAAW;EAC5B,IAAI,OAAO,WAAW,OAAO,SAC3B,UACE,WACA,SAAS,SAAS,KAAK,IAAI,SAAS,QAAQ,SAAS,SAAS,KAAK,IAAI,CAAC,GAAG,UAAU,KAAK,CAC5F;OACG,UAAU,WAAW,SAAS,WAAW,KAAK,SAAS,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;CACzF;CAEA,OAAO;EACL;;EAEA,WAAW,UAAuB,SAAS,SAAS,KAAK,CAAC,SAAS,SAAS,KAAK;EACjF;EACA,aAAa;GACX,IAAI,WAAW,aAAa,SAAS,QAAQ,UAAU,WAAW,CAAC,CAAC;EACtE;CACF;AACF;AAEA,SAAgB,OAAO,EACrB,OACA,WAIC;CACD,OACE,qBAAC,KAAD;EACE,IAAI;GACF,SAAS;GACT,UAAU;GACV,WAAW;GACX,QAAQ;GACR,IAAI;GACJ,UAAU;GACV,OAAO;GACP,WAAW;EACb;EAVF,UAAA,CAYG,MAAM,KAAK,SACV,qBAAC,KAAD;GAAsB,IAAI;IAAE,SAAS;IAAQ,YAAY;IAAU,KAAK;GAAI;GAA5E,UAAA,CACE,oBAAC,KAAD,EAAK,IAAI;IAAE,OAAO;IAAG,QAAQ;IAAG,cAAc;IAAO,SAAS,KAAK;GAAM,EAAI,CAAA,GAC5E,KAAK,KACH;EAHK,GAAA,KAAK,KAGV,CACN,GACA,WAAW,oBAAC,kBAAD;GAAkB,MAAM;GAAI,IAAI,EAAE,IAAI,OAAO;EAAI,CAAA,CAC1D;;AAET;;AAGA,SAAgB,iBAAiB,EAC/B,QACA,OACA,WACA,SAMY;CACZ,IAAI,CAAC,SAAS,CAAC,OAAO,OAAO;CAC7B,OACE,oBAAC,KAAD;EACE,IAAI;GACF;GACA,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,OAAO,QAAQ,eAAe;EAChC;EAEC,UAAA,QACG,+BACA,YACE,gBACA;CACH,CAAA;AAET;;AAGA,SAAgB,WAAW,EACzB,OACA,SACA,YAKC;CACD,OACE,qBAAC,KAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,QAAQ;GAAkB,GAAG;GAAG,UAAU;EAAG;EAAzE,UAAA;GACG,WAAW,oBAAC,KAAD;IAAK,IAAI;KAAE,UAAU;KAAI,OAAO;IAAO;IAAI,UAAA;GAAa,CAAA;GACpE,oBAAC,KAAD;IAAK,IAAI,EAAE,YAAY,IAAI;IAAI,UAAA;GAAW,CAAA;GACzC;EACE;;AAET;;;AC7HA,MAAa,qBAAqB;AAClC,MAAMA,WAAS;AAEf,MAAM,SAAS,UAA+B,UAAU,OAAO,OAAW,OAAO,KAAK;;;;;;AAOtF,SAAgB,YACd,QACA,QACA,SACA,KACA,SAAyC,QAC3B;CACd,MAAM,SAAS,OACZ,KAAK,SAAS;EAAE,OAAO,IAAI,WAAW;EAAM,QAAQ,KAAK,IAAI,SAAS,KAAK,OAAO,KAAK,CAAC;CAAE,EAAE,CAAC,CAC7F,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;CACrC,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC;CAC1C,MAAM,OAAO,OAAO,SAAS,QAAQ,OAAO,MAAM,GAAG,QAAQ,CAAC,IAAI;CAClE,MAAM,QAAsB,KAAK,KAAK,MAAM,WAAW;EACrD,SAAS,IAAI;EACb,OAAO,KAAK;EACZ,OAAO,KAAK,UAAU,OAAO,qBAAqB,OAAO,KAAK,KAAK;EACnE,OAAO,YAAY,KAAK;CAC1B,EAAE;CACF,IAAI,OAAO,SAAS,KAAK,QAAQ,MAAM,KAAK,WAAW,OAAO,SAAS,KAAK,MAAM,CAAC;CACnF,OAAO;AACT;AAEA,MAAM,cAAc,WAAgC;CAClD,SAAS;CACT,OAAO;CACP,OAAO,QAAQ,GAAGA,SAAO,IAAI,MAAM,KAAKA;CACxC,OAAO;CACP,QAAQ;AACV;;;;;;AASA,SAAgB,YACd,MACA,WACA,QACA,SACA,OACA,SAAyC,QACO;CAChD,MAAM,MAAM,CAAC,GAAG,KAAK;CACrB,MAAM,UAAU,IAAI,IAClB,IAAI,QAAQ,SAAS,CAAC,KAAK,MAAM,CAAC,CAAC,KAAK,SAAS,CAAC,MAAM,KAAK,KAAK,GAAG,IAAI,CAAC,CAC5E;CACA,MAAM,yBAAS,IAAI,IAAyB;CAC5C,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,IAAI,cAAc;EAChC,MAAM,MAAM,OAAO,KAAK;EACxB,IAAI,QAAQ,OAAO,IAAI,GAAG;EAC1B,IAAI,CAAC,OAAO;GACV,QAAQ;IAAE;IAAO,OAAO,OAAO,KAAK;GAAE;GACtC,KAAK,MAAM,QAAQ,KAAK,MAAM,KAAK,WAAW;GAC9C,OAAO,IAAI,KAAK,KAAK;EACvB;EACA,IAAI,OAAO,QAAQ,IAAI,MAAM,IAAI,WAAW,IAAI,CAAC;EACjD,IAAI,CAAC,MAAM;GACT,OAAO,IAAI,MAAM,UAAU,MAAM,MAAM;GACvC,IAAI,CAAC,MAAM;IACT,OAAO,WAAW;IAClB,IAAI,KAAK,IAAI;IACb,KAAK,MAAM,SAAS,OAAO,OAAO,GAAG,MAAM,KAAK,WAAW;GAC7D;EACF;EACA,MAAM,SAAS,SAAS,KAAK,OAAO;EACpC,IAAI,QAAQ;GACV,MAAM,KAAK,WAAW,OAAO,MAAM,KAAK,YAAY,CAAC,IAAI;GACzD,KAAK,IAAI,KAAK,OAAO;EACvB;CACF;CACA,OAAO;EAAE,QAAQ,CAAC,GAAG,OAAO,OAAO,CAAC;EAAG,OAAO,IAAI,QAAQ,SAAS,KAAK,IAAI,KAAK,OAAO,CAAC;CAAE;AAC7F;;AAGA,MAAa,cAAc,OAAoB,UAC7C,MAAM,QAAQ,OAAO,SAAS,QAAQ,OAAO,MAAM,KAAK,YAAY,CAAC,GAAG,CAAC;;;AC5C3E,MAAM,mBAAmB;;AAEzB,MAAM,aAAa;;;;;;;AAgBnB,SAAgB,SAAS,EACvB,WACA,UAAU,aACV,QACA,eAAe,QACf,YAAY,GACZ,cAAc,YACd,UAAU,OACV,OAAO,aACP,OACA,kBAAkB,QAClB,YAAY,MACZ,aAAa,MACb,gBAAgB,OAChB,SAAS,KACT,QACA,SAAS,kBACT,cACgB;CAChB,MAAM,EAAE,MAAM,SAAS,cAAc,aAAa;CAElD,MAAM,WAAW,SAAS,YAAY,MAAM,GAAG,CAAC,IAAI;CACpD,MAAM,EAAE,MAAM,WAAW,OAAO,iBAAiB,cAAc;EAC7D,YAAY,SAAS,CAAC,WAAW,MAAM,IAAI,CAAC,SAAS;EACrD;EACA,eAAe,gBAAiB,SAAS,CAAC,WAAW,MAAM,IAAI,CAAC,SAAS,IAAK,KAAA;EAC9E,OAAO,cAAc,cAAc;CACrC,CAAC;CAED,MAAM,SAAS,cAAc;EAC3B,YAAY,SAAS,CAAC,MAAM,IAAI,CAAC;EACjC;EACA,eAAe,OAAO,KAAK,OAAO;EAClC,OAAO,GAAG,cAAc,cAAc,YAAY;EAClD,MAAM,CAAC;CACT,CAAC;CACD,MAAM,SAAS,eAAe,WAAW,aAAa;CACtD,MAAM,eAAe,eAAe,QAAQ,aAAa;CACzD,MAAM,UAAU,SAAS,KAAK,YAAY,iBAAiB,MAAM,SAAS,GAAG,gBAAgB,CAAC;CAC9F,MAAM,WAAW,SAAiB,WAAW,MAAM,MAAM,MAAM;CAE/D,MAAM,aAAa,SAAS,KAAK,cAAc,MAAM,SAAS,IAAI,gBAAgB,IAAI,KAAA;CACtF,MAAM,cAAc,UAClB,cAAc,OAAO;EAAE,GAAG;EAAY,UAAU,YAAY,UAAU,IAAI;CAAE,GAAG,CAAC;CAElF,IAAI;CACJ,IAAI;CACJ,MAAM,QAAQ,SAAS;CACvB,IAAI,UAAU,OAAO;EACnB,MAAM,SAAS,QAAQ,MAAM;EAC7B,MAAM,QAAQ,YACZ,MACA,WACA,QACA,OACA,YAAY,OAAO,MAAM,QAAQ,OAAO,WAAW,YAAY,GAC/D,eACF;EACA,OAAO,MAAM,MAAM,KAAK,UAAU;GAAE,GAAG;GAAM;GAAM;EAAO,EAAE;EAC5D,OAAO,MAAM;CACf,OAAO;EACL,OAAO,SAAS,KAAK,SAAS,WAAW;GACvC,SAAS;GACT,OAAO,QAAQ,OAAO;GACtB,OAAO,YAAY,KAAK;GACxB,QAAQ,QAAQ,UAAU;EAC5B,EAAE;EACF,OAAO,KAAK,KAAK,QAAQ;GACvB,MAAM,QAAQ,IAAI,cAAc;GAChC,MAAM,QAAe;IAAE;IAAO,OAAO,gBAAgB,KAAK;GAAE;GAC5D,KAAK,MAAM,WAAW,UAAU,MAAM,WAAW,SAAS,KAAK,OAAO,KAAK;GAC3E,OAAO;EACT,CAAC;CACH;CACA,IAAI,WAAW,OAAO,KAAK,QAAQ,UAAU,KAAK,MAAM,QAAQ,OAAO,MAAM,IAAI,QAAQ,CAAC,CAAC;CAE3F,MAAM,aAAa,UACjB,SACI,WACE,OACA,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,QAAQ,SAAS,CAAC,CAAC,IAAI,CACrD,IACA,OAAO,MAAM,SAAS,GAAG;CAC/B,IAAI,SAAS,eAAe,OAC1B,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,GAAG,MACxB,SAAS,SAAS,UAAU,CAAC,IAAI,UAAU,CAAC,IAAI,UAAU,CAAC,IAAI,UAAU,CAAC,CAC5E;CACF,IAAI,OAAO,OAAO,KAAK,MAAM,GAAG,KAAK;CAErC,MAAM,aAAa,gBAAgB;CACnC,MAAM,aAAa,cAAc,KAAK,UAAU;CAEhD,MAAM,cAAc,aAAa,KAAK,IAAI,QAAQ,KAAK,SAAS,aAAa,EAAE,IAAI;CACnF,MAAM,UAAU,KAAK,IAAI,GAAG,GAAG,KAAK,KAAK,UAAU,MAAM,MAAM,MAAM,CAAC;CAEtE,MAAM,UAAU,aAAa,OAAO;CACpC,MAAM,QAAQ,iBAAiB;EAC7B;EACA,OAAO,SAAS,OAAO;EACvB,WAAW;EACX,OAAO,CAAC,KAAK;CACf,CAAC;CAED,MAAM,gBAAgB,EAAE,QAAQ,cAAmB;EACjD,IAAI,CAAC,UAAU,CAAC,SAAS,QAAQ,OAAO;EACxC,MAAM,QAAe,QAAQ,EAAE,CAAC;EAEhC,MAAM,QAAQ,SAAS,KAAK,QAAQ,QAAQ,OAAO,MAAM,IAAI,QAAQ,CAAC,IAAI;EAC1E,MAAM,SAAS,KAAK,EAAE,EAAE,UAAU;EAClC,OACE,qBAAC,YAAD;GAAY,OAAO,MAAM;GAAO,SAAS,QAAQ,SAAS;GAA1D,UAAA;IACG,UAAU,SACT,qBAAC,KAAD;KAAK,IAAI;MAAE,UAAU;MAAI,OAAO;MAAQ,IAAI;KAAI;KAAhD,UAAA;MACG,QAAQ,KAAK;MAAE;MAAM,QAAQ,MAAM,CAAC,CAAC,kBAAkB,OAAO;KAC5D;;IAEN,MAAM,KAAK,QACV,qBAAC,KAAD;KAAuB,IAAI;MAAE,SAAS;MAAQ,YAAY;MAAU,KAAK;KAAK;KAA9E,UAAA;MACE,oBAAC,KAAD,EAAK,IAAI;OAAE,OAAO;OAAG,QAAQ;OAAG,cAAc;OAAO,SAAS,IAAI;MAAM,EAAI,CAAA;MAC3E,IAAI;MAAM;MAAG,IAAI,OAAO,OAAO,MAAM,IAAI,QAAQ,CAAC;KAChD;IAHK,GAAA,IAAI,OAGT,CACN;IACA,UAAU,WAAW,MAAM,SAAS,KACnC,qBAAC,KAAD;KAAK,IAAI;MAAE,YAAY;MAAK,IAAI;KAAI;KAApC,UAAA,CAAuC,WAC7B,OAAO,MAAM,QAAQ,OAAO,QAAQ,QAAQ,OAAO,MAAM,IAAI,QAAQ,GAAG,CAAC,CAAC,CAC/E;;GAEG;;CAEhB;CAEA,MAAM,eAAe,OAAe,KAAU,UAAsB;EAElE,MAAM,gBAAgB;EACtB,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,OAAO;EACZ,MAAM,QAAQ,IAAI,MAAM;EAExB,IAAI,CAAC,UAAU,UAAU,QAAQ,UAAU,KAAA,GAAW;GACpD,OAAO,OAAO,MAAM,OAAO,KAAK;GAChC,aAAa,MAAM;EACrB,OAAO,IAAI,MAAM,WAAW,MAAM,SAAS;GACzC,OAAO,OAAO,MAAM,OAAO,KAAK;GAChC,aAAa,OAAO,OAAO,KAAK;EAClC,OAAO;GAEL,MAAM,QAAQ,UAAyB,SACrC,SAAS,WAAW,KAAK,SAAS,OAAO;GAC3C,MAAM,QAAQ,KAAK,OAAO,UAAU,MAAM,KAAK,KAAK,KAAK,aAAa,UAAU,KAAK;GACrF,UAAU,WAAW,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;GAC/C,UAAU,QAAQ,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;EACxC;CACF;CACA,MAAM,YAAY,OAAc,QAAa;EAC3C,IAAI,OAAO,SAAS,MAAM,KAAK,GAAG,OAAO;EACzC,IAAI,CAAC,IAAI,QAAQ,CAAC,aAAa,SAAS,QAAQ,OAAO;EACvD,OAAO,IAAI,KAAK,UAAU,QAAQ,aAAa,SAAS,IAAI,KAAK,KAAK;CACxE;CACA,MAAM,qBAAqB;EACzB,OAAO,MAAM;EACb,aAAa,MAAM;CACrB;CAGA,MAAM,UAAU,UAAoD;EAClE,IAAI,WAAW,QAAQ,KAAK,SAAS,GAAG,OAAO;GAAC;GAAG;GAAG;GAAG;EAAC;EAC1D,OAAO,aAAa;GAAC;GAAG;GAAG;GAAG;EAAC,IAAI;GAAC;GAAG;GAAG;GAAG;EAAC;CAChD;CAEA,OACE,qBAAC,KAAD;EAAK,GAAI;EAAc,IAAI,EAAE,UAAU,EAAE;EAAzC,UAAA,CACE,oBAAC,QAAD;GACE,OAAO,UAAU,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,OAAO,aAAa;IAAE;IAAO;GAAM,EAAE,IAAI,CAAC;GAChF;EACV,CAAA,GACA,SACC,oBAAC,KAAD;GACE,SAAS;GACT,IAAI;IACF;IACA,WAAW,aAAa,SAAS;IACjC,SAAS,UAAU,KAAM;IACzB,YAAY;GACd;GAEA,UAAA,oBAAC,KAAD;IAAK,IAAI,EAAE,QAAQ,YAAY;IAC7B,UAAA,oBAAC,qBAAD;KAAqB,OAAM;KAAO,QAAO;KACvC,UAAA,qBAACC,YAAD;MACQ;MACN,QAAQ,aAAa,aAAa;MAClC,QAAQ;MACR,gBAAe;MACf,QACE,aACI;OAAE,KAAK;OAAG,OAAO,aAAa,KAAK;OAAI,MAAM;OAAG,QAAQ;MAAE,IAC1D;OAAE,KAAK,aAAa,KAAK;OAAG,OAAO;OAAG,MAAM;OAAG,QAAQ;MAAE;MARjE,UAAA;OAWE,oBAAC,eAAD;QAAe,QAAO;QAAO,UAAU;QAAY,YAAY,CAAC;OAAa,CAAA;OAC5E,aACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;QACE,MAAK;QACL,MAAM;QACN,MAAM;SAAE,UAAU;SAAI,MAAM;QAAO;QACnC,eAAe;OAChB,CAAA,GACD,oBAAC,OAAD;QACE,MAAK;QACL,SAAQ;QACR,UAAU;QACV,OAAO,KAAK,IAAI,KAAK,UAAU,IAAI,EAAE;QACrC,MAAM;SAAE,UAAU;SAAI,MAAM;QAAO;QACnC,UAAU;QACV,UAAU;OACX,CAAA,CACD,EAAA,CAAA,IAEF,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;QACE,SAAQ;QACR,UAAU,KAAK,SAAS,mBAAmB,qBAAqB;QAChE,MAAM;SAAE,UAAU;SAAI,MAAM;QAAO;QACnC,UAAU;QACV,UAAU,EAAE,QAAQ,OAAO;OAC5B,CAAA,GACD,oBAAC,OAAD;QACE,MAAM;QACN,MAAM;SAAE,UAAU;SAAI,MAAM;QAAO;QACnC,eAAe;QACf,OAAO;OACR,CAAA,CACD,EAAA,CAAA;OAEJ,oBAACC,WAAD;QAAS,SAAS,oBAAC,cAAD,CAAe,CAAA;QAAG,QAAQ,EAAE,MAAM,kBAAkB;OAAI,CAAA;OACzE,KAAK,KAAK,KAAK,UACd,qBAAC,KAAD;QAEE,SAAS,IAAI;QACb,MAAM,IAAI;QACV,MAAM,IAAI;QACV,SAAS,UAAU,UAAU,KAAA;QAC7B,QAAQ,OAAO,KAAK;QACpB,YAAY,aAAa,KAAK;QAC9B,mBAAmB;QACnB,SACE,iBACK,MAAM,UAAU,UAAU,YAAY,UAAU,KAAK,KAAK,IAC3D,KAAA;QAEN,QAAQ,gBAAgB,YAAY,KAAA;QAdtC,UAAA,CAgBG,iBACC,KAAK,KAAK,UACR,oBAAC,MAAD,EAEE,aAAa,SAAS,OAAO,GAAG,IAAI,MAAO,EAC5C,GAFM,OAAO,MAAM,KAAK,CAExB,CACF,GAEF,cAAc,CAAC,WACd,oBAAC,WAAD;SACE,SAAS,IAAI;SACb,UAAU,aAAa,UAAU;SACjC,YAAY,UAAmB,IAAI,OAAO,KAAe;SACzD,OAAO;UAAE,UAAU;UAAI,MAAM;UAAQ,YAAY;SAAI;QACtD,CAAA,CAEA;OA/BE,GAAA,IAAI,OA+BN,CACN;MACe;;IACC,CAAA;GAClB,CAAA;EACF,CAAA,CAEJ;;AAET;;;;AC3SA,MAAM,cAAc,CAAC,KAAK,SAA8C;CACtE,MAAM,QAAQ,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK;CAC5C,OAAO,CAAC,MAAM,QAAQ,IAAK,MAAM,QAAQ,GAAG;AAC9C;;;;;AAcA,SAAgB,WAAW,EACzB,WACA,KACA,MACA,QACA,UACA,WACA,aACA,kBAAkB,QAClB,WACA,YACA,cACA,QACA,SACA,YAAY,MACZ,SAAS,KACT,YAAY,IACZ,WAAW,WACX,YAAY,QACZ,gBAAgB,OAChB,cACkB;CAClB,MAAM,EAAE,MAAM,SAAS,cAAc,aAAa;CAGlD,MAAM,aAAa,SAAiB,aAAgC;EAClE,MAAM,SAAS,cAAc,MAAM,SAAS,OAAO;EACnD,MAAM,WAAW,QAAQ,SAAS,SAAS;GAAE,GAAG;GAAU,GAAG;EAAO;EACpE,QAAQ,UAAkB,cAAc,OAAO,UAAU,SAAS,QAAQ;CAC5E;CACA,cAAc,UAAU,KAAK;EAAE,QAAQ;EAAY,UAAU;CAAE,CAAC;CAChE,eAAe,UAAU,MAAM,EAAE,UAAU,EAAE,CAAC;CAC9C,iBAAiB,SAAS,UAAU,QAAQ,EAAE,UAAU,EAAE,CAAC,KAAK,UAAU,aAAa,OAAO,CAAC;CAC/F,aAAa,WAAW,MAAM,KAAK,MAAM;CACzC,cAAc,WAAW,MAAM,MAAM,MAAM;CAC3C,gBAAgB,UAAU,WAAW,MAAM,QAAQ,MAAM;CACzD,MAAM,iBAAiB,WAAW,MAAM,WAAW,MAAM;CAEzD,MAAM,EAAE,MAAM,WAAW,OAAO,iBAAiB,cAAc;EAC7D,YAAY,CAAC,SAAS;EACtB,UAAU,SAAS;GAAC;GAAK;GAAM;EAAM,IAAI,CAAC,KAAK,IAAI;EACnD,eAAe,gBAAgB,CAAC,SAAS,IAAI,KAAA;EAC7C,OAAO,cAAc,gBAAgB;CACvC,CAAC;CAED,MAAM,OAAO,KAAmB,QAC9B,OAAO,IAAI,SAAS,QAAQ,IAAI,SAAS,KAAA,IAAY,OAAO,IAAI,IAAI,IAAI;CAE1E,MAAM,OAAgB,KACnB,QAAQ,QAAQ,CAAC,aAAa,IAAI,KAAK,GAAG,CAAC,CAAC,CAC5C,KAAK,SAAS;EACb,OAAO,IAAI,cAAc;EACzB,OAAO,gBAAgB,IAAI,cAAc,EAAE;EAC3C,KAAK,IAAI,KAAK,GAAG,KAAK;EACtB,MAAM,IAAI,KAAK,IAAI;EACnB,QAAQ,IAAI,KAAK,MAAM;CACzB,EAAE;CAEJ,MAAM,aAAa,KAAK,UAAU;CAElC,MAAM,WAAW,gBAAiB,QAAQ,cAAc,CAAC,IAAK,CAAC;CAC/D,MAAM,YAAY,UAAiB,SAAS,SAAS,KAAK,CAAC,SAAS,SAAS,MAAM,KAAK;CAExF,MAAM,kBAAkB,OAAe,UAAsB;EAE3D,MAAM,gBAAgB;EACtB,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,OAAO;EACZ,IAAI,MAAM,WAAW,MAAM,SACzB,UACE,WACA,SAAS,SAAS,MAAM,KAAK,IACzB,SAAS,QAAQ,UAAU,UAAU,MAAM,KAAK,IAChD,CAAC,GAAG,UAAU,MAAM,KAAK,CAC/B;OACK;GACL,MAAM,WAAW,SAAS,WAAW,KAAK,SAAS,OAAO,MAAM;GAChE,UAAU,WAAW,WAAW,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;EACpD;CACF;CAEA,MAAM,oBAAoB;EACxB,IAAI,SAAS,QAAQ,UAAU,WAAW,CAAC,CAAC;CAC9C;CAEA,MAAM,iBAAiB,UAAe;EACpC,MAAM,QAAQ,KAAK,MAAM;EACzB,IAAI,CAAC,OAAO,KAAK,OAAO;EACxB,MAAM,KAAK,OAAO,MAAM,CAAC,IAAI,OAAO,MAAM,KAAK,IAAI;EACnD,MAAM,QAAQ,CACZ,UAAU,MAAM,GAAG,GACnB,MAAM,WAAW,OAAO,OAAO,aAAa,MAAM,MAAM,CAC1D,CAAC,CAAC,QAAQ,SAAyB,CAAC,CAAC,IAAI;EACzC,MAAM,MAAM,OAAO,MAAM,CAAC,IAAI,IAAI,MAAM,SAAS;EACjD,MAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,KAAK,SAAS,KAAK,MAAM,CAAC,IAAI,MAAM;EACpE,OACE,qBAAC,KAAD,EAAA,UAAA,CACE,oBAAC,QAAD;GACE,GAAG,KAAK,QAAQ;GAChB,GAAG;GACI;GACP,QAAQ,MAAM,SAAS,KAAK;GAC5B,IAAI;GACJ,MAAK;EACN,CAAA,GACA,MAAM,KAAK,MAAM,MAChB,oBAAC,QAAD;GAEE,GAAG;GACH,GAAG,MAAM,KAAK,IAAI;GAClB,YAAW;GACX,MAAK;GACL,UAAU;GACV,YAAY;GAEX,UAAA;EACG,GATC,IASD,CACP,CACA,EAAA,CAAA;CAEP;CAEA,MAAM,kBAAkB,UAAe;EACrC,IAAI,MAAM,UAAU,QAAQ,MAAM,UAAU,KAAA,GAAW,OAAO;EAC9D,MAAM,OAAO,WAAW,OAAO,MAAM,KAAK,CAAC;EAC3C,MAAM,QAAQ,KAAK,SAAS,IAAI;EAChC,OACE,qBAAC,KAAD,EAAA,UAAA,CACE,oBAAC,QAAD;GACE,GAAG,MAAM,IAAI,QAAQ;GACrB,GAAG,MAAM,IAAI;GACN;GACP,QAAQ;GACR,IAAI;GACJ,MAAK;EACN,CAAA,GACD,oBAAC,QAAD;GACE,GAAG,MAAM;GACT,GAAG,MAAM,IAAI;GACb,YAAW;GACX,MAAK;GACL,UAAU;GACV,YAAY;GAEX,UAAA;EACG,CAAA,CACL,EAAA,CAAA;CAEP;CAEA,MAAM,gBAAgB,EAAE,QAAQ,cAAmB;EACjD,IAAI,CAAC,UAAU,CAAC,SAAS,QAAQ,OAAO;EACxC,MAAM,QAAe,QAAQ,EAAE,CAAC;EAChC,OACE,qBAAC,KAAD;GAAK,IAAI;IAAE,SAAS;IAAQ,QAAQ;IAAkB,GAAG;IAAG,UAAU;GAAG;GAAzE,UAAA;IACE,oBAAC,YAAD;KAAY,IAAI;MAAE,UAAU;MAAI,OAAO;KAAO;KAAI,UAAA;IAA2B,CAAA;IAC7E,oBAAC,YAAD;KAAY,IAAI;MAAE,YAAY;MAAK,UAAU;KAAG;KAAI,UAAA,MAAM;IAAkB,CAAA;IAC5E,qBAAC,OAAD,EAAA,UAAA;KACG;KAAS;KAAG,UAAU,MAAM,GAAG;IAC7B,EAAA,CAAA;IACJ,MAAM,WAAW,QAChB,qBAAC,OAAD,EAAA,UAAA;KACG;KAAY;KAAG,aAAa,MAAM,MAAM;IACtC,EAAA,CAAA;IAEP,qBAAC,OAAD,EAAA,UAAA;KACG;KAAU;KAAG,MAAM,SAAS,OAAO,KAAK,WAAW,MAAM,IAAI;IAC3D,EAAA,CAAA;GACF;;CAET;CAEA,MAAM,SAAS,CACb;EAAE,OAAO;EAAU,OAAO;CAAS,GACnC;EAAE,OAAO;EAAW,OAAO;CAAU,CACvC;CAEA,OACE,qBAAC,KAAD;EAAK,GAAI;EAAc,IAAI;GAAE,UAAU;GAAG,UAAU;EAAW;EAA/D,UAAA,CACE,qBAAC,KAAD;GAAK,IAAI;IAAE,SAAS;IAAQ,KAAK;IAAK,IAAI;IAAG,UAAU;IAAI,OAAO;GAAO;GAAzE,UAAA,CACG,OAAO,KAAK,SACX,qBAAC,KAAD;IAAsB,IAAI;KAAE,SAAS;KAAQ,YAAY;KAAU,KAAK;IAAI;IAA5E,UAAA,CACE,oBAAC,KAAD,EAAK,IAAI;KAAE,OAAO;KAAG,QAAQ;KAAG,cAAc;KAAO,SAAS,KAAK;IAAM,EAAI,CAAA,GAC5E,KAAK,KACH;GAHK,GAAA,KAAK,KAGV,CACN,GACA,aAAa,oBAAC,kBAAD;IAAkB,MAAM;IAAI,IAAI,EAAE,IAAI,OAAO;GAAI,CAAA,CAC5D;EACJ,CAAA,GAAA,QACC,oBAAC,KAAD;GACE,IAAI;IACF;IACA,SAAS;IACT,YAAY;IACZ,gBAAgB;IAChB,OAAO;GACT;GACD,UAAA;EAEI,CAAA,IACH,CAAC,KAAK,SACR,oBAAC,KAAD;GACE,IAAI;IACF;IACA,SAAS;IACT,YAAY;IACZ,gBAAgB;IAChB,OAAO;GACT;GAEC,UAAA,YAAY,gBAAgB;EAC1B,CAAA,IAEL,oBAAC,KAAD;GACE,SAAS,gBAAgB,cAAc,KAAA;GACvC,IAAI;IAAE;IAAQ,SAAS,YAAY,KAAM;IAAG,YAAY;GAAc;GAEtE,UAAA,oBAAC,qBAAD;IAAqB,OAAM;IAAO,QAAO;IACvC,UAAA,qBAAC,eAAD;KAAqB;KAAM,QAAQ;MAAE,KAAK,aAAa,KAAK;MAAI,OAAO;MAAG,MAAM;KAAE;KAAlF,UAAA;MACE,oBAAC,OAAD;OACE,SAAQ;OACR,UAAU;OACV,MAAM;QAAE,UAAU;QAAI,MAAM;OAAO;OACnC,UAAU;OACV,UAAU;MACX,CAAA;MACD,oBAAC,OAAD;OAAO,SAAQ;OAAM,MAAA;OAAK,QAAQ,CAAC,GAAG,MAAM;MAAI,CAAA;MAChD,oBAAC,OAAD;OAAO,SAAQ;OAAO,MAAA;OAAK,QAAQ;MAAa,CAAA;MAChD,oBAACC,WAAD,EAAS,SAAS,oBAAC,cAAD,CAAe,CAAA,EAAI,CAAA;MACrC,qBAAC,KAAD;OACE,SAAQ;OACR,SAAQ;OACR,MAAM;OACN,mBAAmB;OACnB,SACE,iBAAiB,MAAM,OAAO,UAAU,eAAe,OAAO,KAAK,IAAI,KAAA;OAEzE,QAAQ,gBAAgB,YAAY,KAAA;OARtC,UAAA,CAUG,iBACC,KAAK,KAAK,UACR,oBAAC,MAAD,EAAgC,aAAa,SAAS,KAAK,IAAI,MAAO,EAAI,GAA/D,OAAO,MAAM,KAAK,CAA6C,CAC3E,GACF,cAAc,oBAAC,WAAD;QAAW,SAAQ;QAAM,SAAS,oBAAC,eAAD,CAAgB,CAAA;OAAI,CAAA,CAClE;;MACL,oBAAC,MAAD;OACE,SAAQ;OACR,SAAQ;OACR,QAAQ;OACR,aAAa;OACb,iBAAgB;OAChB,KAAK;QAAE,GAAG;QAAG,MAAM;OAAU;OAC7B,cAAA;OACA,mBAAmB;OAElB,UAAA,cAAc,oBAAC,WAAD;QAAW,SAAQ;QAAO,SAAS,oBAAC,gBAAD,CAAiB,CAAA;OAAI,CAAA;MACnE,CAAA;KACO;;GACI,CAAA;EAClB,CAAA,CAEJ;;AAET;;;AChVA,MAAM,wBAAwB,CAAC;;;;;AAM/B,SAAgB,UACd,QACA,MACA,YACc;CACd,MAAM,EAAE,aAAa,aAAa;CAClC,MAAM,UAAU,UAAU;CAC1B,MAAM,iBAAiB,OAAO,KAAK,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG;CAE9D,gBACQ,SAAS,SAAS,QAAQ,MAAM,iBAAiB,eAAe,MAAM,GAAG,IAAI,CAAC,CAAC,GACrF;EAAC;EAAS;EAAQ;EAAM;CAAc,CACxC;CAGA,qBACE,SAAS,aAAa,iBAChB,SAAS,YAAY,SACrB,KAAA,CACR;CAEA,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,gBAAgB,WAAW,IAAI,GAAG,CAAC,CAAC;CACpC,OAAQ,WAAW,SAAS,QAAQ,MAAM,KAAM;AAClD;;;ACrBA,MAAM,4BAA4B,OAAO,WAAW,cAAc,YAAY;AAE9E,MAAM,qBAAqB,cAAc,KAAK;;AAG9C,MAAa,uBAAuB,WAAW,kBAAkB;;;;;;;;;;;;;;;;AAuBjE,SAAgB,gBAAgB,EAAE,QAAQ,YAAkC;CAC1E,MAAM,EAAE,WAAW,UAAU,QAAQ,UAAU,CAAC,CAAC;CACjD,MAAM,QAAQ,OAAuB,IAAI;CACzC,MAAM,QAAQ,OAAuB,IAAI;CAEzC,MAAM,CAAC,MAAM,WAAW,SAAwD,IAAI;CAEpF,gCAAgC;EAC9B,IAAI,CAAC,UAAU,CAAC,MAAM,WAAW,CAAC,MAAM,SAAS;EACjD,MAAM,eAAe,MAAM;EAC3B,MAAM,eAAe,MAAM;EAC3B,MAAM,gBAAgB;GACpB,MAAM,OAAO;IAAE,WAAW,aAAa;IAAa,SAAS,aAAa;GAAa;GAEvF,SAAS,YACP,SAAS,cAAc,KAAK,aAAa,QAAQ,YAAY,KAAK,UAAU,UAAU,IACxF;EACF;EACA,QAAQ;EACR,MAAM,WAAW,IAAI,eAAe,OAAO;EAC3C,SAAS,QAAQ,YAAY;EAC7B,SAAS,QAAQ,YAAY;EAC7B,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,MAAM,CAAC;CAEX,IAAI,CAAC,QAAQ,OAAO,oBAAA,UAAA,EAAG,SAAW,CAAA;CAElC,MAAM,QAAQ,OAAO,KAAK,YAAY,OAAO,QAAQ;CACrD,OACE,oBAAC,mBAAmB,UAApB;EAA6B,OAAA;EAC3B,UAAA,oBAAC,KAAD;GACE,KAAK;GACL,IAAI;IACF,OAAO;IACP,UAAU;IACV,QAAQ,OAAO,KAAK,UAAU,QAAQ,KAAA;GACxC;GAEA,UAAA,oBAAC,KAAD;IACE,KAAK;IACL,IAAI;KACF,OAAO,OAAO;KACd,WAAW,OAAO;KAClB,WAAW,SAAS,MAAM;KAC1B,iBAAiB;KAEjB,YAAY,OAAO,KAAA,IAAY;IACjC;IAEC;GACE,CAAA;EACF,CAAA;CACsB,CAAA;AAEjC;;;ACRA,MAAM,QAAkB,CAAC;AACzB,MAAM,WAAyB,CAAC;AAEhC,SAAS,QAAQ,GAAyB,GAAyB;CAEjE,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,OAAO,IAAI;CAC/D,OAAO,OAAO,CAAC,CAAC,CAAC,cAAc,OAAO,CAAC,GAAG,SAAS,EAAE,SAAS,KAAK,CAAC;AACtE;;;;;AAMA,SAAgB,UAAU,EACxB,aAAa,OACb,UACA,YAAY,OACZ,mBAAmB,CAAC,GACpB,YAAY,MACZ,QACA,gBAAgB,QAChB,gBAAgB,OAChB,SAAS,KACT,QACA,SAAS,kBACT,kBAAkB,GAClB,aACA,cAAc,UACd,cAAc,OACd,cAAc,WACd,OACA,eACA,cACiB;CACjB,MAAM,EAAE,SAAS,aAAa;CAC9B,MAAM,OAAO,cAAc,eAAe,WAAW,KAAK,IAAI,KAAK;CACnE,MAAM,iBAAiB,WAAW;CAClC,MAAM,gBAAgB,iBAAiB,iBAAiB,CAAC,cAAc,IAAI,KAAA;CAC3E,MAAM,gBAAgB,UAAU,QAAQ,YAAY,CAAC,SAAS,SAAS,OAAO,CAAC;CAG/E,MAAM,UAAU,CACd,GAAG,IAAI,IAAI,CAAC,QAAQ,GAAG,YAAY,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,OAAO,CAAa,CAC3F,CAAC,CAAC,QACC,UACC,CAAC,MAAM,WAAA,IAAkB,KACzB,CAAC,WAAW,SAAS,KAAK,KAC1B,CAAC,SAAS,SAAS,KAAK,KACxB,CAAC,cAAc,SAAS,KAAK,CACjC;CACA,MAAM,cAAc,QAAQ,SAAS,KAAK,CAAC;CAC3C,MAAM,kBAAkB,CAAC,GAAG,YAAY,GAAG,QAAQ,QAAQ,UAAU,MAAM,WAAW,MAAM,CAAC;CAC7F,MAAM,EAAE,MAAM,WAAW,OAAO,iBAAiB,cAAc;EAC7D,YAAY;EACZ,UAAU;GACR,GAAG;GACH,GAAG;GACH,GAAG,QAAQ,QAAQ,UAAU,MAAM,SAAS,UAAU,CAAC,KAAK,WAAW,MAAM;EAC/E;EACA;EACA,OAAO;EACP,MAAM;CACR,CAAC;CAED,MAAM,SAAS,cAAc;EAC3B;EACA;EACA,OAAO,GAAG,KAAK;EACf,MAAM,CAAC,aAAa,CAAC,WAAW;CAClC,CAAC;CACD,MAAM,SAAS,eAAe,gBAAgB,aAAa;CAE3D,MAAM,CAAC,MAAM,WAAW,SAAoD;EAC1E,IAAI;EACJ,WAAW;CACb,CAAC;CAED,MAAM,CAAC,YAAY,iBAAiB,SAAS,CAAC,QAAQ,aAAa,CAAC;CACpE,IAAI,WAAW,OAAO,UAAU,WAAW,OAAO,eAAe;EAC/D,cAAc,CAAC,QAAQ,aAAa,CAAC;EACrC,QAAQ;GAAE,IAAI;GAAQ,WAAW;EAAc,CAAC;CAClD;CAGA,MAAM,UAAU,KAAK,IAAI,WAAA,IAAkB,IAAI,KAAK,GAAG,MAAA,CAAoB,IAAI,KAAK;CACpF,MAAM,SAAS,UACX,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM;EACvB,MAAM,CAAC,GAAG,KAAK,CAAC,EAAE,UAAU,EAAE,QAAQ;EACtC,IAAI,MAAM,QAAQ,MAAM,KAAA,GAAW,OAAO;EAC1C,IAAI,MAAM,QAAQ,MAAM,KAAA,GAAW,OAAO;EAC1C,OAAO,KAAK,cAAc,QAAQ,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC;CAChE,CAAC,IACD;CAEJ,MAAM,UAAU,OAAO,YACrB,SAAS,KAAK,YAAY,CAAC,SAAS,iBAAiB,MAAM,SAAS,GAAG,gBAAgB,CAAC,CAAC,CAC3F;CACA,MAAM,iBAAiB,UACrB,UAAU,OAAO,KAAK,GAAG,aAAa,QAAQ,KAAK,eAAe,EAAE;CACtE,MAAM,iBAAiB,WAAmB,UACxC,UAAU,QAAQ,UAAU,KAAA,IACxB,aACC,iBAAiB,cAAc,OAAA,CAAQ,KAAK;CACnD,MAAM,WAAW,WAAmB,WAAW,MAAM,QAAQ,MAAM;CACnE,MAAM,YAAY,WAAmB;EACnC,IAAI,CAAC,OAAO,WAAA,IAAkB,GAAG,OAAO,QAAQ,MAAM;EACtD,MAAM,UAAU,OAAO,MAAA,CAAoB;EAC3C,OAAO,SAAS,SAAS,OAAO,IAAI,MAAM,KAAK,QAAQ,OAAO;CAChE;CAGA,MAAM,OAAO,OAAO,YAClB,UAAU,KAAK,YAAY,CACzB,SACA,KAAK,QAAQ,OAAO,QAAQ,SAAS,OAAO,IAAI,QAAQ,KAAK,IAAI,CAAC,CACpE,CAAC,CACH;CACA,MAAM,gBAAgB,KAAmB,YAAoB;EAC3D,MAAM,QAAQ,IAAI;EAClB,MAAM,QAAQ,KAAK;EACnB,OAAO,UAAU,QAAQ,UAAU,KAAA,KAAa,CAAC,QAAQ,OAAO,OAAO,KAAK,IAAI;CAClF;CAEA,MAAM,UAAU,aACd,CAAC,GAAG,YAAY,GAAG,QAAQ,GAC3B,UAAU,QAAQ,YAAY,CAAC,WAAW,SAAS,OAAO,CAAC,GAC3D,WACF;CAEA,MAAM,cAAc,QAA6D;EAC/E,IAAI,CAAC,YAAY,QAAQ,OAAO,KAAA;EAChC,MAAM,YAAY,EAAE,GAAG,IAAI;EAC3B,KAAK,MAAM,WAAW,WAAW,UAAU,cAAc,OAAO,KAAK,aAAa,KAAK,OAAO;EAC9F,OAAO,cAAc,aAAa,WAAW,OAAO;CACtD;CACA,MAAM,UAAU,UACd,SAAS;EACP,GAAI,MAAM,SAAS,EAAE,OAAO,MAAM,MAAM;EACxC,GAAI,MAAM,cAAc,EAAE,SAAS,MAAM,WAAW;EACpD,GAAI,MAAM,QAAQ,EAAE,YAAY,IAAI;EACpC,GAAI,MAAM,SAAS,EAAE,WAAW,MAAM,MAAM;EAC5C,GAAI,MAAM,iBAAiB,EAAE,eAAe,MAAM,cAAc;CAClE;CACF,MAAM,eAAe,WAAmB,WAAW,SAAS,MAAM;CAClE,MAAM,WAAW,WAAmB,QAAQ,YAAY,YAAY,MAAM,IAAI,SAAS;CACvF,MAAM,cAAc,WAAmB,gBAAgB,WAAW;CAElE,MAAM,mBAAmB,QAAQ,KAAK,WAAW;CACjD,MAAM,YAAY,KAAmB,WACnC,OAAO,WAAA,IAAkB,IACrB,cAAc,aAAa,KAAK,OAAO,MAAA,CAAoB,CAAC,CAAC,IAC7D,QAAQ,OAAO,GAAG,IAAI,OAAO;CAEnC,MAAM,cAAc,WAClB,SAAS,YACP,QAAQ,OAAO,SACX;EAAE,IAAI;EAAQ,WAAW,QAAQ,cAAc,QAAQ,SAAS;CAAM,IAEtE;EAAE,IAAI;EAAQ,WAAW,WAAW,SAAS,MAAM,IAAI,QAAQ;CAAO,CAC5E;CAEF,MAAM,WAAW,WAAW,SAAS,OAAO,KAAK,KAAK,KAAA;CACtD,MAAM,UAAU,aAAa;CAC7B,MAAM,cAAc,iBAAiB;EACnC,QAAQ;EACR;EACA,WAAW;EACX,OAAO,CAAC,KAAK;CACf,CAAC;CAED,MAAM,UAAU,QAAgB,YAC9B,oBAAC,WAAD;EAEE,OAAO,QAAQ,MAAM;EACrB,eAAe,KAAK,OAAO,SAAS,KAAK,YAAY;EACrD,IAAI;GACF,YAAY;GACZ,SAAS;GACT,YAAY;GACZ,eAAe,WAAW,MAAM;EAClC;EAEA,UAAA,oBAAC,gBAAD;GACE,QAAQ,KAAK,OAAO;GACpB,WAAW,KAAK,OAAO,SAAS,KAAK,YAAY,UAAU,SAAS;GACpE,eAAe,WAAW,MAAM;GAE/B,UAAA,SAAS,MAAM;EACF,CAAA;CACP,GAjBJ,MAiBI;CAGb,OACE,qBAAC,KAAD;EAAK,GAAI;EAAc,IAAI;GAAE,UAAU;GAAG,UAAU;EAAW;EAA/D,UAAA,CACG,WAAW,oBAAC,kBAAD;GAAkB,MAAM;GAAI,IAAI;IAAE,UAAU;IAAY,KAAK;IAAK,OAAO;GAAE;EAAI,CAAA,GAC1F,eACC,oBAAC,KAAD;GACE,IAAI;IACF,WAAW;IACX,UAAU;IACV,SAAS,UAAU,KAAM;IACzB,YAAY;GACd;GAEA,UAAA,qBAAC,OAAD;IACE,MAAK;IACL,cAAA;IACA,IAAI,EACF,cAAc;KACZ,UAAU;KACV,GAAI,eAAe,EAAE,QAAQ,aAAa,cAAc;IAC1D,EACF;IARF,UAAA,CAUE,oBAAC,WAAD,EAAA,UACE,oBAAC,UAAD,EAAA,UAAW,QAAQ,KAAK,WAAW,OAAO,QAAQ,CAAC,YAAY,MAAM,CAAC,CAAC,EAAY,CAAA,EAC1E,CAAA,GACX,qBAAC,WAAD,EAAA,UAAA,CACG,OAAO,KAAK,QAAQ;KACnB,MAAM,QAAQ,iBAAiB,IAAI,kBAAkB;KACrD,MAAM,YAAY,iBAAiB,UAAU,QAAQ,UAAU,KAAA;KAC/D,MAAM,SAAS,WAAW,GAAG;KAC7B,OACE,oBAAC,UAAD;MAEE,OAAA;MACA,SAAS,aAAa,UAAU,OAAO,OAAO,OAAO,KAAK,IAAI,KAAA;MAC9D,UAAU,aAAa,OAAO,SAAS,SAAS,KAAK;MACrD,IAAI;OACF,QAAQ,YAAY,YAAY,KAAA;OAChC,SAAS,aAAa,OAAO,SAAS,KAAK,IAAI,KAAM;MACvD;MAEC,UAAA,QAAQ,KAAK,WACZ,YAAY,MAAM,IAChB,oBAAC,WAAD;OAEE,OAAO,QAAQ,MAAM;OACrB,IAAI;QAAE,eAAe,WAAW,MAAM;QAAG,GAAG,OAAO,SAAS,OAAO;OAAE;OAEpE,UAAA,cAAc,QAAQ,IAAI,OAAO;MACzB,GALJ,MAKI,IAEX,oBAAC,WAAD;OAEE,OAAO,QAAQ,MAAM;OACrB,IAAI;QACF,YAAY;QACZ,eAAe,WAAW,MAAM;QAChC,GAAG,OAAO,SAAS,OAAO;OAC5B;OAEC,UAAA,SAAS,KAAK,MAAM;MACZ,GATJ,MASI,CAEf;KACQ,GAhCH,gBAAgB,KAAK,cAAc,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,IAAQ,CAgCrE;IAEd,CAAC,GACA,YACC,oBAAC,UAAD;KACE,IAAI,EACF,QAAQ;MACN,YAAY;MACZ,UAAU;MACV,QAAQ;MACR,SAAS;MACT,WAAW;KACb,EACF;KAEC,UAAA,QAAQ,KAAK,WACZ,YAAY,MAAM,IAChB,oBAAC,WAAD;MAEE,OAAO,QAAQ,MAAM;MACrB,IAAI,EAAE,eAAe,WAAW,MAAM,EAAE;MAEvC,UAAA,WAAW,mBAAmB,UAAU;KAChC,GALJ,MAKI,IAEX,oBAAC,WAAD;MAEE,OAAO,QAAQ,MAAM;MACrB,IAAI;OAAE,YAAY;OAAU,eAAe,WAAW,MAAM;MAAE;MAE7D,UAAA,OAAO,WAAA,IAAkB,IACtB,cAAc,KAAK,OAAO,MAAA,CAAoB,KAAK,IAAI,IAAI,IAC3D,QAAQ,OAAO,GAAG,SAAS,OAAO;KAC7B,GAPJ,MAOI,CAEf;IACQ,CAAA,CAEH,EAAA,CAAA,CACN;;EACJ,CAAA,CAEJ;;AAET;;;ACxVA,MAAM,SAAS;;;;;AAMf,SAAgB,WAAW,EACzB,WACA,SACA,YAAY,GACZ,kBAAkB,QAClB,gBAAgB,OAChB,SAAS,KACT,QACA,SACA,kBAAkB,GAClB,cACkB;CAClB,MAAM,EAAE,SAAS,aAAa;CAC9B,MAAM,EAAE,MAAM,WAAW,OAAO,iBAAiB,cAAc;EAC7D,YAAY,CAAC,SAAS;EACtB,UAAU,CAAC,OAAO;EAClB,eAAe,gBAAgB,CAAC,SAAS,IAAI,KAAA;EAC7C,OAAO,cAAc,gBAAgB;CACvC,CAAC;CACD,MAAM,SAAS,eAAe,WAAW,aAAa;CACtD,MAAM,SAAS,iBAAiB,MAAM,SAAS,GAAG,OAAO;CAEzD,MAAM,WAAW,KACd,KAAK,SAAS;EAAE,OAAO,IAAI,cAAc;EAAI,QAAQ,SAAS,KAAK,OAAO,KAAK;CAAE,EAAE,CAAC,CACpF,QAAQ,SAAS,KAAK,SAAS,CAAC,CAAC,CACjC,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;CACrC,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC;CAEhD,MAAM,OAAO,SAAS,SAAS,QAAQ,SAAS,MAAM,GAAG,QAAQ,CAAC,IAAI;CACtE,MAAM,OAAO,SAAS,MAAM,KAAK,MAAM;CAEvC,MAAM,SAAkB,KAAK,KAAK,MAAM,WAAW;EACjD,KAAK,OAAO,KAAK,KAAK;EACtB,OAAO,KAAK;EACZ,OAAO,gBAAgB,KAAK,KAAK;EACjC,QAAQ,KAAK;EACb,OAAO,YAAY,KAAK;CAC1B,EAAE;CACF,IAAI,KAAK,QACP,OAAO,KAAK;EACV,KAAK,SAAS;EACd,OAAO;EACP,OAAO,GAAG,OAAO,IAAI,KAAK,OAAO;EACjC,QAAQ,KAAK,QAAQ,OAAO,SAAS,QAAQ,KAAK,QAAQ,CAAC;EAC3D,OAAO;CACT,CAAC;CACH,MAAM,QAAQ,OAAO,QAAQ,KAAK,UAAU,MAAM,MAAM,QAAQ,CAAC;CACjE,MAAM,WAAW,WAAmB,GAAG,aAAc,SAAS,QAAS,KAAK,eAAe,EAAE;CAE7F,MAAM,cAAc,iBAAiB;EAAE;EAAQ;EAAO;EAAW,OAAO,CAAC,OAAO;CAAO,CAAC;CAExF,MAAM,UAAU,OAA0B,UAAmD;EAC3F,IAAI,OAAO,UAAU,QAAQ,OAAO,UAAU,KAAA,GAAW,OAAO,OAAO,MAAM,OAAO,KAAK;CAC3F;CACA,MAAM,UAAU,UACd,OAAO,SAAS,SAAS,MAAM,MAAM,UAAU,QAAQ,OAAO,SAAS,MAAM,KAAK;CAEpF,MAAM,gBAAgB,EAAE,QAAQ,cAAmB;EACjD,IAAI,CAAC,UAAU,CAAC,SAAS,QAAQ,OAAO;EACxC,MAAM,QAAe,QAAQ,EAAE,CAAC;EAChC,OACE,qBAAC,YAAD;GAAY,OAAO,MAAM;GAAO,SAAS,WAAW,MAAM,WAAW,MAAM;GAA3E,UAAA;IACG,WAAW,MAAM,SAAS,MAAM;IAAE;IAAG,OAAO,MAAM,MAAM;IAAE;IAAI,QAAQ,MAAM,MAAM;GACzE;;CAEhB;CAEA,OACE,oBAAC,KAAD;EAAK,GAAI;EAAc,IAAI;GAAE,UAAU;GAAG,UAAU;EAAW;EAC5D,UAAA,eACC,qBAAC,KAAD;GACE,IAAI;IACF;IACA,SAAS;IACT,YAAY;IACZ,KAAK;IACL,SAAS,YAAY,KAAM;IAC3B,YAAY;GACd;GARF,UAAA,CAUE,qBAAC,KAAD;IAAK,IAAI;KAAE,UAAU;KAAY,QAAQ;KAAQ,MAAM;KAAW,UAAU;IAAI;IAAhF,UAAA,CACE,oBAAC,qBAAD;KAAqB,OAAM;KAAO,QAAO;KACvC,UAAA,qBAAC,UAAD,EAAA,UAAA,CACE,oBAACC,WAAD,EAAS,SAAS,oBAAC,cAAD,CAAe,CAAA,EAAI,CAAA,GACrC,oBAAC,KAAD;MACE,MAAM;MACN,SAAQ;MACR,SAAQ;MACR,aAAY;MACZ,aAAY;MACZ,YAAY;MACZ,UAAU;MACV,QAAO;MACP,aAAa;MACb,mBAAmB;MACnB,UAAU,GAAG,OAAO,UAAU,OAAO,OAAO,QAAQ,KAAK;MACzD,QAAQ,gBAAgB,YAAY,KAAA;MAEnC,UAAA,OAAO,KAAK,UACX,oBAAC,MAAD;OAEE,MAAM,MAAM;OACZ,aAAa,OAAO,KAAK,IAAI,MAAO;MACrC,GAHM,MAAM,GAGZ,CACF;KACE,CAAA,CACG,EAAA,CAAA;IACS,CAAA,GAErB,qBAAC,KAAD;KACE,IAAI;MACF,UAAU;MACV,OAAO;MACP,SAAS;MACT,eAAe;MACf,YAAY;MACZ,gBAAgB;MAChB,eAAe;MACf,WAAW;KACb;KAVF,UAAA,CAYE,oBAAC,KAAD;MAAK,IAAI;OAAE,UAAU;OAAI,OAAO;MAAO;MAAG,UAAA;KAAU,CAAA,GACpD,oBAAC,KAAD;MAAK,IAAI;OAAE,UAAU;OAAI,YAAY;OAAK,OAAO;MAAO;MAAI,UAAA,OAAO,KAAK;KAAO,CAAA,CAC5E;IACF,CAAA,CAAA;GACL,CAAA,GAAA,oBAAC,KAAD;IACE,WAAU;IACV,IAAI;KACF,WAAW;KACX,GAAG;KACH,GAAG;KACH,UAAU;KACV,MAAM;KACN,UAAU;KACV,WAAW;IACb;IAEC,UAAA,OAAO,KAAK,UACX,qBAAC,KAAD;KACE,WAAU;KAEV,UAAU,UAAU,OAAO,OAAO,KAAK;KACvC,IAAI;MACF,SAAS;MACT,qBAAqB;MACrB,YAAY;MACZ,WAAW;MACX,IAAI;MACJ,UAAU;MACV,OAAO;MACP,SAAS,OAAO,KAAK,IAAI,MAAO;MAChC,QAAQ,iBAAiB,MAAM,UAAU,OAAO,YAAY,KAAA;KAC9D;KAdF,UAAA;MAgBE,oBAAC,KAAD,EAAK,IAAI;OAAE,OAAO;OAAI,QAAQ;OAAI,cAAc;OAAO,SAAS,MAAM;MAAM,EAAI,CAAA;MAChF,oBAAC,KAAD;OAAK,IAAI;QAAE,UAAU;QAAU,cAAc;QAAY,YAAY;OAAS;OAC3E,UAAA,MAAM;MACJ,CAAA;MACL,oBAAC,KAAD;OAAK,IAAI;QAAE,YAAY;QAAK,WAAW;OAAQ;OAAI,UAAA,QAAQ,MAAM,MAAM;MAAO,CAAA;MAC9E,oBAAC,KAAD,CAAM,CAAA;MACN,oBAAC,KAAD;OAAK,IAAI;QAAE,YAAY;QAAS,UAAU;QAAI,OAAO;OAAO;OACzD,UAAA,OAAO,MAAM,MAAM;MACjB,CAAA;KACF;IAvBE,GAAA,MAAM,GAuBR,CACN;GACE,CAAA,CACF;;CAEJ,CAAA;AAET;;;;;;;;AC/LA,SAAgB,QAAQ,EACtB,SACA,OACA,WACA,gBACA,QACA,SACA,cACe;CACf,MAAM,EAAE,SAAS,aAAa;CAC9B,MAAM,EAAE,MAAM,WAAW,OAAO,iBAAiB,cAAc;EAC7D,UAAU,YAAY,CAAC,SAAS,SAAS,IAAI,CAAC,OAAO;EACrD,OAAO,cAAc,aAAa;CACpC,CAAC;CACD,MAAM,MAAM,KAAK;CACjB,MAAM,QAAQ,MAAM,SAAS,KAAK,OAAO,IAAI;CAC7C,MAAM,QAAQ,OAAO,YAAY,SAAS,KAAK,SAAS,IAAI;CAC5D,UAAU,SAAS;CAEnB,OACE,qBAAC,KAAD;EAAK,GAAI;EAAc,IAAI;GAAE,UAAU;GAAG,UAAU;EAAW;EAA/D,UAAA;GACG,SAAS,oBAAC,KAAD;IAAK,IAAI;KAAE,UAAU;KAAI,OAAO;KAAQ,IAAI;IAAI;IAAI,UAAA;GAAW,CAAA;GACxE,aAAa,oBAAC,kBAAD;IAAkB,MAAM;IAAI,IAAI;KAAE,UAAU;KAAY,KAAK;KAAG,OAAO;IAAE;GAAI,CAAA;GAC3F,oBAAC,KAAD;IACE,IAAI;KACF,UAAU;KACV,YAAY;KACZ,YAAY;KACZ,OAAO,QAAQ,eAAe;KAC9B,oBAAoB;KACpB,YAAY;KACZ,UAAU;KACV,cAAc;KACd,SAAS,YAAY,KAAM;KAC3B,YAAY;IACd;IAEC,UAAA,QAAQ,SAAS,UAAU,OAAO,MAAM,iBAAiB,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,KAAK;GACvF,CAAA;GACJ,aACC,qBAAC,KAAD;IAAK,IAAI;KAAE,UAAU;KAAI,OAAO;KAAQ,IAAI;KAAM,WAAW;IAAG;IAAhE,UAAA;KACG,kBAAkB,WAAW,MAAM,WAAW,MAAM;KAAE;KAAE;KACzD,oBAAC,KAAD;MAAK,WAAU;MAAO,IAAI;OAAE,YAAY;OAAK,OAAO;MAAO;MACxD,UAAA,UAAU,OAAO,MAAM,iBAAiB,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,KAAK;KACxE,CAAA;IACF;;EAEJ;;AAET;;;ACrCA,SAAS,aAAa,EAAE,OAAO,MAAM,YAA6B;CAChE,MAAM,MAAM,UAA+B,UAAU,KAAA,IAAY,KAAA,IAAY,GAAG,MAAM;CACtF,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,UAAU;EAC1B,IAAI;GACF,GAAG,GAAG,KAAK,OAAO,KAAK;GACvB,UAAU;GACV,QAAQ;GACR,SAAS,KAAK;GACd,QAAQ,GAAG,KAAK,eAAe,EAAE;GACjC,aAAa,KAAK,eAAe;GACjC,cAAc,GAAG,KAAK,YAAY;EACpC;EAVF,UAAA,CAYG,SACC,oBAAC,YAAD;GACE,IAAI;IACF,YAAY;IACZ,IAAI;IACJ,OAAO,KAAK;IACZ,UAAU,GAAG,KAAK,SAAS;IAC3B,WAAW,KAAK;GAClB;GAEC,UAAA;EACS,CAAA,GAEb,QACI;;AAEX;;;;;;;;;;;AAYA,SAAgB,gBAAgB,EAC9B,QACA,aAAa,CAAC,GACd,OAAO,QAAQ,cACf,MAAM,OACiB;CACvB,MAAM,UAAU,UAAU,QAAQ,UAAU,UAAU;CACtD,MAAM,EAAE,WAAW;CAEnB,MAAM,QAAQ,eAAe;CAC7B,MAAM,UAAU;CAEhB,OACE,oBAAC,KAAD;EACE,IAAI;GACF,SAAS;GACT,KAAK,QAAQ,OAAO,QAAQ,KAAA,IAAY,MAAM,GAAG,QAAQ,MAAM,IAAI;GACnE,qBAAqB,QAAQ,UAAU;IAAE,IAAI;IAAO,IAAI;GAAQ;EAClE;EAEC,UAAA,OAAO,KAAK,UACX,oBAAC,KAAD;IAGK,wBAAwB,cAAc,OAAO,IAAI;IAAE,MAAM;IAAS,KAAK,MAAM;GAAG,CAAC;GAEpF,IAAI;IACF,UAAU;IACV,YAAY,QACR,QAAQ,MAAM,QAAA,OACd,EAAE,IAAI,QAAQ,MAAM,QAAA,KAAyB;GACnD;GAEA,UAAA,oBAAC,OAAD;IAAO,OAAO,MAAM;IAAc;IAAO,MAAM,eAAe,SAAS,KAAK;IAC1E,UAAA,oBAAC,OAAD;KAAc;KAAmB;IAAa,CAAA;GACzC,CAAA;EACJ,GAdE,MAAM,EAcR,CACN;CACE,CAAA;AAET;AAIA,SAAS,MAAM,EAAE,OAAO,cAA2D;CACjF,MAAM,EAAE,YAAY,oBAAoB,aAAa;CACrD,IAAI,CAAC,eAAe,KAAK,GAAG;EAC1B,MAAM,YAAY,gBAAgB,MAAM;EACxC,IAAI,WAAW,OAAO,oBAAC,WAAD,EAAW,GAAI,iBAAiB,OAAO,YAAY,UAAU,EAAI,CAAA;EACvF,OAAO,oBAAC,cAAD,EAAc,MAAM,MAAM,KAAO,CAAA;CAC1C;CACA,MAAM,aAAa,GAAG,MAAM,SAAS,MAAM,GAAG,KAAK,MAAM;CACzD,MAAM,aAAa,SAAmB,OAAO,WAAW,QAAQ,KAAA;CAChE,QAAQ,MAAM,MAAd;EACE,KAAK,OAAO;GACV,MAAM,EAAE,IAAI,MAAM,OAAO,MAAM,MAAM,GAAG,UAAU;GAClD,OAAO,oBAAC,SAAD;IAAS,GAAI;IAAmB;GAAa,CAAA;EACtD;EACA,KAAK,SAAS;GACZ,MAAM,EAAE,IAAI,MAAM,OAAO,MAAM,MAAM,iBAAiB,GAAG,UAAU;GACnE,OACE,oBAAC,YAAD;IACE,GAAI;IACQ;IACZ,iBAAiB,UAAU,eAAe;GAC3C,CAAA;EAEL;EACA,KAAK,OAAO;GACV,MAAM,EAAE,IAAI,MAAM,OAAO,MAAM,MAAM,iBAAiB,cAAc,GAAG,UAAU;GACjF,OACE,oBAAC,UAAD;IACE,GAAI;IACQ;IACZ,iBAAiB,UAAU,eAAe;IAC1C,cAAc,UAAU,YAAY;GACrC,CAAA;EAEL;EACA,KAAK,SAAS;GACZ,MAAM,EAAE,IAAI,MAAM,OAAO,MAAM,MAAM,iBAAiB,GAAG,UAAU;GACnE,OACE,oBAAC,YAAD;IACE,GAAI;IACQ;IACZ,iBAAiB,UAAU,eAAe;GAC3C,CAAA;EAEL;EACA,KAAK,SAAS;GACZ,MAAM,EAAE,IAAI,MAAM,OAAO,MAAM,MAAM,kBAAkB,GAAG,UAAU;GACpE,MAAM,WAAuB,CAAC;GAC9B,KAAK,MAAM,CAAC,WAAW,SAAS,OAAO,QAAQ,oBAAoB,CAAC,CAAC,GAAG;IACtE,MAAM,SAAS,UAAU,IAAI;IAC7B,IAAI,QAAQ,SAAS,aAAa;GACpC;GACA,OAAO,oBAAC,WAAD;IAAW,GAAI;IAAmB;IAAY,kBAAkB;GAAW,CAAA;EACpF;EACA,SACE,OAAO,oBAAC,cAAD,EAAc,MAAO,MAA4B,KAAO,CAAA;CACnE;AACF;AAEA,SAAS,aAAa,EAAE,QAA2B;CACjD,OACE,qBAAC,KAAD;EAAK,IAAI;GAAE,OAAO;GAAc,GAAG;EAAE;EAArC,UAAA;GAAwC;GACP,OAAO,IAAI;GAAE;GAAsB;GAClE,oBAAC,QAAD,EAAA,UAAO,6BAAmC,CAAA;GAAC;EACxC;;AAET;;;;;;;;ACxKA,SAAgB,aAAa,EAC3B,WACA,OACA,cAAc,QACd,QAAQ,OACY;CACpB,MAAM,EAAE,SAAS,WAAW,SAAS,aAAa;CAClD,UAAU,MAAM,WAAW,UAAU,EAAE,SAAS;CAChD,MAAM,EAAE,MAAM,iBAAiB,cAAc;EAC3C,YAAY,CAAC,SAAS;EACtB,eAAe,CAAC,SAAS;EACzB,OAAO,kBAAkB;CAC3B,CAAC;CAED,MAAM,WAAW,QAAQ,cAAc,CAAC;CACxC,MAAM,UAAU,KACb,KAAK,QAAQ,IAAI,UAAU,CAAC,CAC5B,QAAQ,UAAgC,UAAU,QAAQ,UAAU,EAAE;CAEzE,KAAK,MAAM,SAAS,UAAU,IAAI,CAAC,QAAQ,SAAS,KAAK,GAAG,QAAQ,KAAK,KAAK;CAE9E,OACE,qBAAC,aAAD;EAAa,GAAI;EAAc,MAAK;EAAQ,IAAI,EAAE,MAAM;EAAxD,UAAA,CACE,oBAAC,YAAD;GAAY,QAAA;GAAQ,UAAA;EAAkB,CAAA,GACtC,oBAAC,QAAD;GACE,UAAA;GACA,cAAA;GACA,OAAO;GACP,WAAW,UAAU,UAAU,WAAW,MAAM,OAAO,KAAsB;GAC7E,OAAO,oBAAC,eAAD;IAAe,SAAA;IAAe;GAAQ,CAAA;GAC7C,cAAc,WAAY,OAAO,SAAS,OAAO,IAAI,WAAW,CAAC,CAAC,KAAK,IAAI,IAAI;GAC/E,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,IAAI,EAAE,EAAE,EAAE;GAC9D,IAAI,EAAE,SAAS,OAAO;GAErB,UAAA,QAAQ,KAAK,WACZ,qBAAC,UAAD;IAAuB,OAAO;IAAQ,OAAA;IAAtC,UAAA,CACE,oBAAC,UAAD;KAAU,MAAK;KAAQ,SAAS,SAAS,SAAS,MAAM;KAAG,IAAI;MAAE,GAAG;MAAK,IAAI;KAAE;IAAI,CAAA,GACnF,oBAAC,cAAD,EAAc,SAAS,YAAY,MAAM,EAAI,CAAA,CACrC;GAHK,GAAA,MAGL,CACX;EACK,CAAA,CACG;;AAEjB;;;;;;;AClDA,SAAgB,iBAAiB,EAAE,QAAQ,aAAa,CAAC,GAAG,MAAM,KAA4B;CAC5F,MAAM,EAAE,UAAU,CAAC,MAAM,UAAU,QAAQ,WAAW,UAAU;CAChE,OACE,oBAAC,KAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,UAAU;GAAQ;EAAI;EAC/C,UAAA,QAAQ,KAAK,WACZ,oBAAC,KAAD;IAGK,wBAAwB,cAAc,OAAO,IAAI;IAChD,MAAM;IACN,KAAK,OAAO;GACd,CAAC;GAGH,UAAA,oBAAC,cAAD;IACE,WAAW,OAAO;IAClB,OAAO,OAAO;IACd,OAAO,OAAO;IACd,aAAa,OAAO,cAAc,WAAW,OAAO,eAAe,KAAA;GACpE,CAAA;EACE,GAdE,OAAO,SAcT,CACN;CACE,CAAA;AAET"}
|
|
@@ -374,11 +374,22 @@ type ComboChartDef = BaseChartDef & ColumnsDisplay & {
|
|
|
374
374
|
type BarChartDef = BaseChartDef & ColumnsDisplay & {
|
|
375
375
|
type: 'bar';
|
|
376
376
|
dimension: string;
|
|
377
|
-
/** Uma série por medida. */
|
|
377
|
+
/** Uma série por medida (ou, com `series`, só a primeira medida). */
|
|
378
378
|
measures: string[];
|
|
379
|
+
/**
|
|
380
|
+
* Dimensão da legenda: quebra a medida pelos valores dela, uma série por valor (a "Legenda" do
|
|
381
|
+
* Power BI). Usa só a primeira medida.
|
|
382
|
+
*/
|
|
383
|
+
series?: string;
|
|
384
|
+
formatSeries?: string;
|
|
385
|
+
/** Séries além dessa quantidade viram "Outros" (com `series`). */
|
|
386
|
+
maxSeries?: number;
|
|
379
387
|
orientation?: 'vertical' | 'horizontal';
|
|
380
388
|
stacked?: boolean;
|
|
381
|
-
/**
|
|
389
|
+
/**
|
|
390
|
+
* `dimension` = ordem da dimensão; `desc`/`asc` = pela primeira medida (com `series`, pelo
|
|
391
|
+
* total da barra).
|
|
392
|
+
*/
|
|
382
393
|
sort?: 'dimension' | 'desc' | 'asc';
|
|
383
394
|
/** Só os N primeiros depois de ordenar. */
|
|
384
395
|
limit?: number;
|
|
@@ -545,9 +556,13 @@ type FieldSpec = {
|
|
|
545
556
|
kind: 'measures';
|
|
546
557
|
percent?: boolean;
|
|
547
558
|
} |
|
|
548
|
-
/**
|
|
559
|
+
/**
|
|
560
|
+
* Nome de um formatter do `<DashboardCharts formatters>`. `of`: campo `dimension` que ele formata
|
|
561
|
+
* (o devtools edita no ⚙ daquela dimensão); dispensável com uma dimensão e um formatter só.
|
|
562
|
+
*/
|
|
549
563
|
{
|
|
550
564
|
kind: 'formatter';
|
|
565
|
+
of?: string;
|
|
551
566
|
} |
|
|
552
567
|
/** `{ dimensão: formatter }`. */
|
|
553
568
|
{
|
|
@@ -632,4 +647,4 @@ declare function validateLayout(layout: ChartsLayout, types?: ChartTypes): strin
|
|
|
632
647
|
declare function layoutModelWarnings(layout: ChartsLayout, model: Pick<ModelDef, 'dimensions' | 'measures'>, types?: ChartTypes): string[];
|
|
633
648
|
//#endregion
|
|
634
649
|
export { TableDef as $, DashboardQueryDebug as A, SchemaTable as B, ColumnVerticalAlign as C, DashboardDevtoolsRequest as D, DashboardBatchResult as E, FilterValue as F, FormulaMeasure as G, Aggregation as H, ModelColumns as I, ModelDef as J, MeasureDef as K, ModelValidation as L, DashboardRow as M, DashboardSnapshot as N, DashboardFilters as O, DevtoolsCapabilities as P, SumMeasure as Q, ProfileStep as R, ColumnAlign as S, DashboardBatchQuery as T, DimensionDef as U, AggregateMeasure as V, FieldMeta as W, RatioMeasure as X, ModelMeta as Y, RelationshipDef as Z, KpiChartDef as _, CardsStyle as a, resolveChartTypes as b, ChartType as c, ChartsLayout as d, ValueFormat as et, ComboChartDef as f, FilterDef as g, FieldSpec as h, CardStyle as i, DashboardResult as j, DashboardQuery as k, ChartTypeSpec as l, DonutChartDef as m, BuiltinChartDef as n, validateModel as nt, ChartDef as o, CustomChartDef as p, MeasureMeta as q, CanvasDef as r, ChartNumberFormat as s, BarChartDef as t, modelMeta as tt, ChartTypes as u, TableChartDef as v, FormatRule as w, validateLayout as x, layoutModelWarnings as y, SaveModelResult as z };
|
|
635
|
-
//# sourceMappingURL=layout-
|
|
650
|
+
//# sourceMappingURL=layout-CoGyGWYM.d.ts.map
|