@apipass/design-system 5.2.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/lib/charts.index.cjs +1 -1
  2. package/dist/lib/charts.index.js +10 -6
  3. package/dist/lib/charts.index.js.map +1 -1
  4. package/dist/lib/embedded-styles.js +2 -2
  5. package/dist/lib/style.css +1 -1
  6. package/dist/lib/ui/components/charts/BarChart/BarChart.cjs +1 -1
  7. package/dist/lib/ui/components/charts/BarChart/BarChart.cjs.map +1 -1
  8. package/dist/lib/ui/components/charts/BarChart/BarChart.js +66 -48
  9. package/dist/lib/ui/components/charts/BarChart/BarChart.js.map +1 -1
  10. package/dist/lib/ui/components/charts/BarChart/bar-chart-option.cjs +1 -1
  11. package/dist/lib/ui/components/charts/BarChart/bar-chart-option.cjs.map +1 -1
  12. package/dist/lib/ui/components/charts/BarChart/bar-chart-option.js +71 -81
  13. package/dist/lib/ui/components/charts/BarChart/bar-chart-option.js.map +1 -1
  14. package/dist/lib/ui/components/charts/ChartColorPicker/ChartColorPicker.cjs +2 -0
  15. package/dist/lib/ui/components/charts/ChartColorPicker/ChartColorPicker.cjs.map +1 -0
  16. package/dist/lib/ui/components/charts/ChartColorPicker/ChartColorPicker.js +99 -0
  17. package/dist/lib/ui/components/charts/ChartColorPicker/ChartColorPicker.js.map +1 -0
  18. package/dist/lib/ui/components/charts/ChartLegend/ChartLegend.cjs +2 -0
  19. package/dist/lib/ui/components/charts/ChartLegend/ChartLegend.cjs.map +1 -0
  20. package/dist/lib/ui/components/charts/ChartLegend/ChartLegend.js +47 -0
  21. package/dist/lib/ui/components/charts/ChartLegend/ChartLegend.js.map +1 -0
  22. package/dist/lib/ui/components/charts/ChartLegend/use-chart-legend.cjs +2 -0
  23. package/dist/lib/ui/components/charts/ChartLegend/use-chart-legend.cjs.map +1 -0
  24. package/dist/lib/ui/components/charts/ChartLegend/use-chart-legend.js +34 -0
  25. package/dist/lib/ui/components/charts/ChartLegend/use-chart-legend.js.map +1 -0
  26. package/dist/lib/ui/components/charts/TimeSeriesChart/TimeSeriesChart.cjs +1 -1
  27. package/dist/lib/ui/components/charts/TimeSeriesChart/TimeSeriesChart.cjs.map +1 -1
  28. package/dist/lib/ui/components/charts/TimeSeriesChart/TimeSeriesChart.js +63 -45
  29. package/dist/lib/ui/components/charts/TimeSeriesChart/TimeSeriesChart.js.map +1 -1
  30. package/dist/lib/ui/components/charts/TimeSeriesChart/time-series-option.cjs +1 -1
  31. package/dist/lib/ui/components/charts/TimeSeriesChart/time-series-option.cjs.map +1 -1
  32. package/dist/lib/ui/components/charts/TimeSeriesChart/time-series-option.js +31 -41
  33. package/dist/lib/ui/components/charts/TimeSeriesChart/time-series-option.js.map +1 -1
  34. package/dist/lib/ui/primitives/Table/Table.cjs +1 -1
  35. package/dist/lib/ui/primitives/Table/Table.cjs.map +1 -1
  36. package/dist/lib/ui/primitives/Table/Table.js +68 -52
  37. package/dist/lib/ui/primitives/Table/Table.js.map +1 -1
  38. package/dist/types/charts.index.d.ts +2 -0
  39. package/dist/types/ui/components/charts/BarChart/BarChart.d.ts +4 -1
  40. package/dist/types/ui/components/charts/BarChart/bar-chart-option.d.ts +0 -1
  41. package/dist/types/ui/components/charts/ChartColorPicker/ChartColorPicker.d.ts +18 -0
  42. package/dist/types/ui/components/charts/ChartLegend/ChartLegend.d.ts +21 -0
  43. package/dist/types/ui/components/charts/ChartLegend/use-chart-legend.d.ts +14 -0
  44. package/dist/types/ui/components/charts/TimeSeriesChart/TimeSeriesChart.d.ts +4 -1
  45. package/dist/types/ui/components/charts/TimeSeriesChart/time-series-option.d.ts +0 -1
  46. package/dist/types/ui/primitives/Table/Table.d.ts +2 -1
  47. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"bar-chart-option.js","sources":["../../../../../../src/ui/components/charts/BarChart/bar-chart-option.ts"],"sourcesContent":["import type { ChartTheme } from \"../chart-theme\";\n\nexport interface BarChartPoint {\n category: string;\n value: number | null;\n}\n\nexport interface BarChartSeriesData {\n id: string;\n name: string;\n points: BarChartPoint[];\n // Nome de token, nunca hex: é o que mantém a cor válida nos dois temas. Sem ele a série\n // recebe a próxima cor da paleta.\n colorToken?: string;\n}\n\nexport type BarChartOrientation = \"vertical\" | \"horizontal\";\n\nexport type BarChartStacking = \"off\" | \"stacked\" | \"percent\";\n\nexport type BarChartValueLabel = \"auto\" | \"always\" | \"never\";\n\nexport type BarChartLegendMode = \"inline\" | \"none\";\n\nexport type BarChartAxisScale = \"linear\" | \"log\";\n\nexport interface BarChartValueAxisOptions {\n scale?: BarChartAxisScale;\n min?: number;\n max?: number;\n includeZero?: boolean;\n}\n\nexport interface BarChartOptionInput {\n categories: string[];\n series: BarChartSeriesData[];\n orientation: BarChartOrientation;\n stacking: BarChartStacking;\n valueLabel: BarChartValueLabel;\n legend: BarChartLegendMode;\n valueAxis: BarChartValueAxisOptions;\n theme: ChartTheme;\n seriesColorOverrides: Record<string, string>;\n valueFormatter?: (value: number) => string;\n}\n\nconst LEGEND_HEIGHT_PX: number = 32;\n\nconst GRID_WITHOUT_LEGEND = { top: 16, right: 16, bottom: 16, left: 16 } as const;\n\n// Na horizontal o rótulo da categoria disputa largura com a própria barra; na vertical ele fica\n// sob a barra e uma faixa mais estreita já dá conta.\nconst CATEGORY_LABEL_MAX_WIDTH_PX: Record<BarChartOrientation, number> = {\n vertical: 140,\n horizontal: 200,\n};\n\nconst BAR_MAX_WIDTH_PX: number = 48;\n\nconst STACK_ID: string = \"total\";\n\nconst PERCENT_SCALE: number = 100;\n\n// O rótulo dentro da barra é lido contra a cor da série, não contra o fundo da página: a paleta\n// de séries é a mesma nos dois temas, então quem decide entre texto claro e escuro é o\n// preenchimento. O branco que o ECharts usa por padrão reprova no contraste em toda a paleta —\n// 2,24:1 sobre a `yellow-500`.\nconst LABEL_ON_DARK_FILL: string = \"#ffffff\";\n\nconst LABEL_ON_LIGHT_FILL: string = \"#1e1e1e\";\n\nconst LABEL_ON_LIGHT_FILL_LUMINANCE: number = 0.0144;\n\nconst WHITE_LUMINANCE: number = 1;\n\nfunction channelLuminance(channel: number): number {\n const normalized: number = channel / 255;\n return normalized <= 0.03928\n ? normalized / 12.92\n : Math.pow((normalized + 0.055) / 1.055, 2.4);\n}\n\nfunction parseColorChannels(color: string): [number, number, number] | undefined {\n const hexMatch: RegExpMatchArray | null = color\n .trim()\n .match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);\n if (hexMatch) {\n const digits: string = hexMatch[1];\n const expanded: string =\n digits.length === 3\n ? digits\n .split(\"\")\n .map((digit: string) => digit + digit)\n .join(\"\")\n : digits;\n return [0, 2, 4].map((start: number) => parseInt(expanded.slice(start, start + 2), 16)) as [\n number,\n number,\n number,\n ];\n }\n\n const rgbMatch: RegExpMatchArray | null = color\n .trim()\n .match(/^rgba?\\(\\s*(\\d+)[\\s,]+(\\d+)[\\s,]+(\\d+)/i);\n if (rgbMatch) {\n return [Number(rgbMatch[1]), Number(rgbMatch[2]), Number(rgbMatch[3])];\n }\n\n return undefined;\n}\n\nfunction relativeLuminance(color: string): number | undefined {\n const channels: [number, number, number] | undefined = parseColorChannels(color);\n if (!channels) return undefined;\n const [red, green, blue] = channels.map(channelLuminance);\n return 0.2126 * red + 0.7152 * green + 0.0722 * blue;\n}\n\nfunction contrastRatio(lighter: number, darker: number): number {\n return (lighter + 0.05) / (darker + 0.05);\n}\n\nfunction labelColorOnFill(fillColor: string): string {\n const luminance: number | undefined = relativeLuminance(fillColor);\n if (luminance === undefined) return LABEL_ON_DARK_FILL;\n const againstLightText: number = contrastRatio(WHITE_LUMINANCE, luminance);\n const againstDarkText: number = contrastRatio(luminance, LABEL_ON_LIGHT_FILL_LUMINANCE);\n return againstDarkText >= againstLightText ? LABEL_ON_LIGHT_FILL : LABEL_ON_DARK_FILL;\n}\n\nconst PERCENT_LABEL: Intl.NumberFormat = new Intl.NumberFormat(undefined, {\n style: \"percent\",\n maximumFractionDigits: 1,\n});\n\nfunction formatPercent(value: number): string {\n return PERCENT_LABEL.format(value / PERCENT_SCALE);\n}\n\n// Em `percent` o valor desenhado é a participação na categoria, e não mais o dado do consumidor:\n// aplicar ali o formatador dele escreveria \"31 ms\" numa barra que vale 31%.\nfunction resolveValueFormatter(input: BarChartOptionInput): ((value: number) => string) | undefined {\n return input.stacking === \"percent\" ? formatPercent : input.valueFormatter;\n}\n\n// Categoria sem valor chega ao formatter como `null` — o ECharts formata o vazio junto com o\n// resto. O tipo público promete `number` ao consumidor, e é esta guarda que mantém a promessa.\nfunction nullSafeValueFormatter(\n input: BarChartOptionInput,\n): ((value: number | null) => string) | undefined {\n const formatValue: ((value: number) => string) | undefined = resolveValueFormatter(input);\n if (!formatValue) return undefined;\n return (value: number | null) => (value === null ? \"\" : formatValue(value));\n}\n\nfunction alignValuesToCategories(\n data: BarChartSeriesData,\n categories: string[],\n): Array<number | null> {\n const valueByCategory: Map<string, number | null> = new Map(\n data.points.map((point: BarChartPoint) => [point.category, point.value]),\n );\n return categories.map((category: string) => valueByCategory.get(category) ?? null);\n}\n\nfunction toShareOfCategoryTotal(\n valuesBySeries: Array<Array<number | null>>,\n categoryCount: number,\n): Array<Array<number | null>> {\n const categoryTotals: number[] = Array.from(\n { length: categoryCount },\n (_unused, categoryIndex: number) =>\n valuesBySeries.reduce(\n (total: number, values: Array<number | null>) => total + (values[categoryIndex] ?? 0),\n 0,\n ),\n );\n return valuesBySeries.map((values: Array<number | null>) =>\n values.map((value: number | null, categoryIndex: number) => {\n const categoryTotal: number = categoryTotals[categoryIndex];\n if (value === null || categoryTotal === 0) return null;\n return (value / categoryTotal) * PERCENT_SCALE;\n }),\n );\n}\n\nfunction labelPosition(input: BarChartOptionInput): string {\n if (input.stacking !== \"off\") return \"inside\";\n return input.orientation === \"horizontal\" ? \"right\" : \"top\";\n}\n\ninterface LabelLayoutParams {\n rect: { width: number; height: number };\n labelRect: { width: number; height: number };\n}\n\ninterface LabelLayout {\n hideOverlap: boolean;\n fontSize?: number;\n}\n\ntype SeriesLabelLayout = LabelLayout | ((params: LabelLayoutParams) => LabelLayout);\n\nfunction fitsInsideBar(params: LabelLayoutParams): boolean {\n return (\n params.labelRect.width <= params.rect.width && params.labelRect.height <= params.rect.height\n );\n}\n\n// `hideOverlap` resolve rótulo que encosta em rótulo, mas não rótulo maior que a própria fatia:\n// numa barra empilhada o ECharts desenha o número por cima das fatias vizinhas. `fontSize: 0` é\n// o que o `labelLayout` oferece para sumir com um rótulo caso a caso.\nfunction seriesLabelLayout(input: BarChartOptionInput): SeriesLabelLayout {\n const hideOverlap: boolean = input.valueLabel === \"auto\";\n if (!hideOverlap || labelPosition(input) !== \"inside\") return { hideOverlap };\n return (params: LabelLayoutParams) => ({\n hideOverlap,\n fontSize: fitsInsideBar(params) ? undefined : 0,\n });\n}\n\nfunction seriesLabel(input: BarChartOptionInput, fillColor: string): Record<string, unknown> {\n const position: string = labelPosition(input);\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n return {\n show: input.valueLabel !== \"never\",\n position,\n color: position === \"inside\" ? labelColorOnFill(fillColor) : input.theme.labelColor,\n formatter: formatValue\n ? (params: { value: number | null }) => formatValue(params.value)\n : undefined,\n };\n}\n\nfunction categoryAxis(input: BarChartOptionInput): Record<string, unknown> {\n const { categories, theme, orientation } = input;\n return {\n type: \"category\",\n data: categories,\n // Na horizontal o ECharts empilha a categoria de baixo para cima, invertendo a ordem que o\n // app escolheu ao ordenar as barras.\n inverse: orientation === \"horizontal\",\n axisLine: { lineStyle: { color: theme.axisLineColor } },\n axisTick: { show: false },\n axisLabel: {\n color: theme.labelColor,\n hideOverlap: true,\n width: CATEGORY_LABEL_MAX_WIDTH_PX[orientation],\n overflow: \"truncate\",\n },\n splitLine: { show: false },\n };\n}\n\nfunction valueAxis(input: BarChartOptionInput): Record<string, unknown> {\n const { valueAxis: options, stacking, theme } = input;\n const isPercent: boolean = stacking === \"percent\";\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n return {\n type: options.scale === \"log\" ? \"log\" : \"value\",\n // Barra mede por comprimento: eixo cortado mente sobre a proporção entre as barras, então\n // aqui o zero entra por padrão — ao contrário da série temporal, que só mostra variação.\n scale: !isPercent && options.includeZero === false,\n min: isPercent ? 0 : options.min,\n max: isPercent ? PERCENT_SCALE : options.max,\n axisLine: { show: false },\n axisLabel: { color: theme.labelColor, formatter: formatValue },\n splitLine: { lineStyle: { color: theme.splitLineColor } },\n };\n}\n\n// O retorno é `Record<string, unknown>` de propósito, e não `EChartsOption`: é o que impede\n// um tipo da biblioteca de vazar para o resto do design system.\nexport function buildBarChartOption(input: BarChartOptionInput): Record<string, unknown> {\n const { categories, series, orientation, stacking, legend, theme } = input;\n const isLegendVisible: boolean = legend !== \"none\" && series.length > 0;\n const isHorizontal: boolean = orientation === \"horizontal\";\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n\n const alignedValues: Array<Array<number | null>> = series.map((data: BarChartSeriesData) =>\n alignValuesToCategories(data, categories),\n );\n // O ECharts não tem empilhamento 100%: a participação precisa chegar calculada no dado.\n const plottedValues: Array<Array<number | null>> =\n stacking === \"percent\"\n ? toShareOfCategoryTotal(alignedValues, categories.length)\n : alignedValues;\n\n const labelLayout: SeriesLabelLayout = seriesLabelLayout(input);\n const categoryAxisOption: Record<string, unknown> = categoryAxis(input);\n const valueAxisOption: Record<string, unknown> = valueAxis(input);\n\n return {\n animation: false,\n color: theme.seriesColors,\n textStyle: { fontFamily: theme.fontFamily, color: theme.labelColor },\n grid: {\n ...GRID_WITHOUT_LEGEND,\n top: isLegendVisible ? GRID_WITHOUT_LEGEND.top + LEGEND_HEIGHT_PX : GRID_WITHOUT_LEGEND.top,\n containLabel: true,\n },\n legend: isLegendVisible\n ? {\n type: \"scroll\",\n top: 0,\n left: 0,\n icon: \"roundRect\",\n itemHeight: 8,\n itemWidth: 12,\n textStyle: { color: theme.labelColor },\n }\n : { show: false },\n tooltip: {\n trigger: \"axis\",\n axisPointer: { type: \"shadow\" },\n backgroundColor: theme.tooltipBackgroundColor,\n borderColor: theme.tooltipBorderColor,\n textStyle: { color: theme.labelColor },\n valueFormatter: formatValue,\n },\n xAxis: isHorizontal ? valueAxisOption : categoryAxisOption,\n yAxis: isHorizontal ? categoryAxisOption : valueAxisOption,\n series: series.map((data: BarChartSeriesData, index: number) => {\n const fillColor: string =\n input.seriesColorOverrides[data.id] ??\n theme.seriesColors[index % theme.seriesColors.length];\n return {\n id: data.id,\n name: data.name,\n type: \"bar\",\n stack: stacking === \"off\" ? undefined : STACK_ID,\n barMaxWidth: BAR_MAX_WIDTH_PX,\n data: plottedValues[index],\n itemStyle: { color: fillColor },\n label: seriesLabel(input, fillColor),\n labelLayout,\n };\n }),\n };\n}\n"],"names":["GRID_WITHOUT_LEGEND","CATEGORY_LABEL_MAX_WIDTH_PX","BAR_MAX_WIDTH_PX","STACK_ID","PERCENT_SCALE","LABEL_ON_DARK_FILL","LABEL_ON_LIGHT_FILL","LABEL_ON_LIGHT_FILL_LUMINANCE","WHITE_LUMINANCE","channelLuminance","channel","normalized","parseColorChannels","color","hexMatch","digits","expanded","digit","start","rgbMatch","relativeLuminance","channels","red","green","blue","contrastRatio","lighter","darker","labelColorOnFill","fillColor","luminance","againstLightText","PERCENT_LABEL","formatPercent","value","resolveValueFormatter","input","nullSafeValueFormatter","formatValue","alignValuesToCategories","data","categories","valueByCategory","point","category","toShareOfCategoryTotal","valuesBySeries","categoryCount","categoryTotals","_unused","categoryIndex","total","values","categoryTotal","labelPosition","fitsInsideBar","params","seriesLabelLayout","hideOverlap","seriesLabel","position","categoryAxis","theme","orientation","valueAxis","options","stacking","isPercent","buildBarChartOption","series","legend","isLegendVisible","isHorizontal","alignedValues","plottedValues","labelLayout","categoryAxisOption","valueAxisOption","index"],"mappings":"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"}
1
+ {"version":3,"file":"bar-chart-option.js","sources":["../../../../../../src/ui/components/charts/BarChart/bar-chart-option.ts"],"sourcesContent":["import type { ChartTheme } from \"../chart-theme\";\n\nexport interface BarChartPoint {\n category: string;\n value: number | null;\n}\n\nexport interface BarChartSeriesData {\n id: string;\n name: string;\n points: BarChartPoint[];\n // Nome de token, nunca hex: é o que mantém a cor válida nos dois temas. Sem ele a série\n // recebe a próxima cor da paleta.\n colorToken?: string;\n}\n\nexport type BarChartOrientation = \"vertical\" | \"horizontal\";\n\nexport type BarChartStacking = \"off\" | \"stacked\" | \"percent\";\n\nexport type BarChartValueLabel = \"auto\" | \"always\" | \"never\";\n\nexport type BarChartLegendMode = \"inline\" | \"none\";\n\nexport type BarChartAxisScale = \"linear\" | \"log\";\n\nexport interface BarChartValueAxisOptions {\n scale?: BarChartAxisScale;\n min?: number;\n max?: number;\n includeZero?: boolean;\n}\n\nexport interface BarChartOptionInput {\n categories: string[];\n series: BarChartSeriesData[];\n orientation: BarChartOrientation;\n stacking: BarChartStacking;\n valueLabel: BarChartValueLabel;\n valueAxis: BarChartValueAxisOptions;\n theme: ChartTheme;\n seriesColorOverrides: Record<string, string>;\n valueFormatter?: (value: number) => string;\n}\n\n// A legenda saiu do canvas e virou HTML (`ChartLegend`), entao a grade nao reserva mais faixa\n// para ela: quem divide a altura agora e o flex do componente.\nconst GRID_PADDING = { top: 16, right: 16, bottom: 16, left: 16 } as const;\n\n// Na horizontal o rótulo da categoria disputa largura com a própria barra; na vertical ele fica\n// sob a barra e uma faixa mais estreita já dá conta.\nconst CATEGORY_LABEL_MAX_WIDTH_PX: Record<BarChartOrientation, number> = {\n vertical: 140,\n horizontal: 200,\n};\n\nconst BAR_MAX_WIDTH_PX: number = 48;\n\nconst STACK_ID: string = \"total\";\n\nconst PERCENT_SCALE: number = 100;\n\n// O rótulo dentro da barra é lido contra a cor da série, não contra o fundo da página: a paleta\n// de séries é a mesma nos dois temas, então quem decide entre texto claro e escuro é o\n// preenchimento. O branco que o ECharts usa por padrão reprova no contraste em toda a paleta —\n// 2,24:1 sobre a `yellow-500`.\nconst LABEL_ON_DARK_FILL: string = \"#ffffff\";\n\nconst LABEL_ON_LIGHT_FILL: string = \"#1e1e1e\";\n\nconst LABEL_ON_LIGHT_FILL_LUMINANCE: number = 0.0144;\n\nconst WHITE_LUMINANCE: number = 1;\n\nfunction channelLuminance(channel: number): number {\n const normalized: number = channel / 255;\n return normalized <= 0.03928\n ? normalized / 12.92\n : Math.pow((normalized + 0.055) / 1.055, 2.4);\n}\n\nfunction parseColorChannels(color: string): [number, number, number] | undefined {\n const hexMatch: RegExpMatchArray | null = color\n .trim()\n .match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);\n if (hexMatch) {\n const digits: string = hexMatch[1];\n const expanded: string =\n digits.length === 3\n ? digits\n .split(\"\")\n .map((digit: string) => digit + digit)\n .join(\"\")\n : digits;\n return [0, 2, 4].map((start: number) => parseInt(expanded.slice(start, start + 2), 16)) as [\n number,\n number,\n number,\n ];\n }\n\n const rgbMatch: RegExpMatchArray | null = color\n .trim()\n .match(/^rgba?\\(\\s*(\\d+)[\\s,]+(\\d+)[\\s,]+(\\d+)/i);\n if (rgbMatch) {\n return [Number(rgbMatch[1]), Number(rgbMatch[2]), Number(rgbMatch[3])];\n }\n\n return undefined;\n}\n\nfunction relativeLuminance(color: string): number | undefined {\n const channels: [number, number, number] | undefined = parseColorChannels(color);\n if (!channels) return undefined;\n const [red, green, blue] = channels.map(channelLuminance);\n return 0.2126 * red + 0.7152 * green + 0.0722 * blue;\n}\n\nfunction contrastRatio(lighter: number, darker: number): number {\n return (lighter + 0.05) / (darker + 0.05);\n}\n\nfunction labelColorOnFill(fillColor: string): string {\n const luminance: number | undefined = relativeLuminance(fillColor);\n if (luminance === undefined) return LABEL_ON_DARK_FILL;\n const againstLightText: number = contrastRatio(WHITE_LUMINANCE, luminance);\n const againstDarkText: number = contrastRatio(luminance, LABEL_ON_LIGHT_FILL_LUMINANCE);\n return againstDarkText >= againstLightText ? LABEL_ON_LIGHT_FILL : LABEL_ON_DARK_FILL;\n}\n\nconst PERCENT_LABEL: Intl.NumberFormat = new Intl.NumberFormat(undefined, {\n style: \"percent\",\n maximumFractionDigits: 1,\n});\n\nfunction formatPercent(value: number): string {\n return PERCENT_LABEL.format(value / PERCENT_SCALE);\n}\n\n// Em `percent` o valor desenhado é a participação na categoria, e não mais o dado do consumidor:\n// aplicar ali o formatador dele escreveria \"31 ms\" numa barra que vale 31%.\nfunction resolveValueFormatter(input: BarChartOptionInput): ((value: number) => string) | undefined {\n return input.stacking === \"percent\" ? formatPercent : input.valueFormatter;\n}\n\n// Categoria sem valor chega ao formatter como `null` — o ECharts formata o vazio junto com o\n// resto. O tipo público promete `number` ao consumidor, e é esta guarda que mantém a promessa.\nfunction nullSafeValueFormatter(\n input: BarChartOptionInput,\n): ((value: number | null) => string) | undefined {\n const formatValue: ((value: number) => string) | undefined = resolveValueFormatter(input);\n if (!formatValue) return undefined;\n return (value: number | null) => (value === null ? \"\" : formatValue(value));\n}\n\nfunction alignValuesToCategories(\n data: BarChartSeriesData,\n categories: string[],\n): Array<number | null> {\n const valueByCategory: Map<string, number | null> = new Map(\n data.points.map((point: BarChartPoint) => [point.category, point.value]),\n );\n return categories.map((category: string) => valueByCategory.get(category) ?? null);\n}\n\nfunction toShareOfCategoryTotal(\n valuesBySeries: Array<Array<number | null>>,\n categoryCount: number,\n): Array<Array<number | null>> {\n const categoryTotals: number[] = Array.from(\n { length: categoryCount },\n (_unused, categoryIndex: number) =>\n valuesBySeries.reduce(\n (total: number, values: Array<number | null>) => total + (values[categoryIndex] ?? 0),\n 0,\n ),\n );\n return valuesBySeries.map((values: Array<number | null>) =>\n values.map((value: number | null, categoryIndex: number) => {\n const categoryTotal: number = categoryTotals[categoryIndex];\n if (value === null || categoryTotal === 0) return null;\n return (value / categoryTotal) * PERCENT_SCALE;\n }),\n );\n}\n\nfunction labelPosition(input: BarChartOptionInput): string {\n if (input.stacking !== \"off\") return \"inside\";\n return input.orientation === \"horizontal\" ? \"right\" : \"top\";\n}\n\ninterface LabelLayoutParams {\n rect: { width: number; height: number };\n labelRect: { width: number; height: number };\n}\n\ninterface LabelLayout {\n hideOverlap: boolean;\n fontSize?: number;\n}\n\ntype SeriesLabelLayout = LabelLayout | ((params: LabelLayoutParams) => LabelLayout);\n\nfunction fitsInsideBar(params: LabelLayoutParams): boolean {\n return (\n params.labelRect.width <= params.rect.width && params.labelRect.height <= params.rect.height\n );\n}\n\n// `hideOverlap` resolve rótulo que encosta em rótulo, mas não rótulo maior que a própria fatia:\n// numa barra empilhada o ECharts desenha o número por cima das fatias vizinhas. `fontSize: 0` é\n// o que o `labelLayout` oferece para sumir com um rótulo caso a caso.\nfunction seriesLabelLayout(input: BarChartOptionInput): SeriesLabelLayout {\n const hideOverlap: boolean = input.valueLabel === \"auto\";\n if (!hideOverlap || labelPosition(input) !== \"inside\") return { hideOverlap };\n return (params: LabelLayoutParams) => ({\n hideOverlap,\n fontSize: fitsInsideBar(params) ? undefined : 0,\n });\n}\n\nfunction seriesLabel(input: BarChartOptionInput, fillColor: string): Record<string, unknown> {\n const position: string = labelPosition(input);\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n return {\n show: input.valueLabel !== \"never\",\n position,\n color: position === \"inside\" ? labelColorOnFill(fillColor) : input.theme.labelColor,\n formatter: formatValue\n ? (params: { value: number | null }) => formatValue(params.value)\n : undefined,\n };\n}\n\nfunction categoryAxis(input: BarChartOptionInput): Record<string, unknown> {\n const { categories, theme, orientation } = input;\n return {\n type: \"category\",\n data: categories,\n // Na horizontal o ECharts empilha a categoria de baixo para cima, invertendo a ordem que o\n // app escolheu ao ordenar as barras.\n inverse: orientation === \"horizontal\",\n axisLine: { lineStyle: { color: theme.axisLineColor } },\n axisTick: { show: false },\n axisLabel: {\n color: theme.labelColor,\n hideOverlap: true,\n width: CATEGORY_LABEL_MAX_WIDTH_PX[orientation],\n overflow: \"truncate\",\n },\n splitLine: { show: false },\n };\n}\n\nfunction valueAxis(input: BarChartOptionInput): Record<string, unknown> {\n const { valueAxis: options, stacking, theme } = input;\n const isPercent: boolean = stacking === \"percent\";\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n return {\n type: options.scale === \"log\" ? \"log\" : \"value\",\n // Barra mede por comprimento: eixo cortado mente sobre a proporção entre as barras, então\n // aqui o zero entra por padrão — ao contrário da série temporal, que só mostra variação.\n scale: !isPercent && options.includeZero === false,\n min: isPercent ? 0 : options.min,\n max: isPercent ? PERCENT_SCALE : options.max,\n axisLine: { show: false },\n axisLabel: { color: theme.labelColor, formatter: formatValue },\n splitLine: { lineStyle: { color: theme.splitLineColor } },\n };\n}\n\n// O retorno é `Record<string, unknown>` de propósito, e não `EChartsOption`: é o que impede\n// um tipo da biblioteca de vazar para o resto do design system.\nexport function buildBarChartOption(input: BarChartOptionInput): Record<string, unknown> {\n const { categories, series, orientation, stacking, theme } = input;\n const isHorizontal: boolean = orientation === \"horizontal\";\n const formatValue: ((value: number | null) => string) | undefined = nullSafeValueFormatter(input);\n\n const alignedValues: Array<Array<number | null>> = series.map((data: BarChartSeriesData) =>\n alignValuesToCategories(data, categories),\n );\n // O ECharts não tem empilhamento 100%: a participação precisa chegar calculada no dado.\n const plottedValues: Array<Array<number | null>> =\n stacking === \"percent\"\n ? toShareOfCategoryTotal(alignedValues, categories.length)\n : alignedValues;\n\n const labelLayout: SeriesLabelLayout = seriesLabelLayout(input);\n const categoryAxisOption: Record<string, unknown> = categoryAxis(input);\n const valueAxisOption: Record<string, unknown> = valueAxis(input);\n\n return {\n animation: false,\n color: theme.seriesColors,\n textStyle: { fontFamily: theme.fontFamily, color: theme.labelColor },\n grid: {\n ...GRID_PADDING,\n containLabel: true,\n },\n tooltip: {\n trigger: \"axis\",\n axisPointer: { type: \"shadow\" },\n backgroundColor: theme.tooltipBackgroundColor,\n borderColor: theme.tooltipBorderColor,\n textStyle: { color: theme.labelColor },\n valueFormatter: formatValue,\n },\n xAxis: isHorizontal ? valueAxisOption : categoryAxisOption,\n yAxis: isHorizontal ? categoryAxisOption : valueAxisOption,\n series: series.map((data: BarChartSeriesData, index: number) => {\n const fillColor: string =\n input.seriesColorOverrides[data.id] ??\n theme.seriesColors[index % theme.seriesColors.length];\n return {\n id: data.id,\n name: data.name,\n type: \"bar\",\n stack: stacking === \"off\" ? undefined : STACK_ID,\n barMaxWidth: BAR_MAX_WIDTH_PX,\n data: plottedValues[index],\n itemStyle: { color: fillColor },\n label: seriesLabel(input, fillColor),\n labelLayout,\n };\n }),\n };\n}\n"],"names":["GRID_PADDING","CATEGORY_LABEL_MAX_WIDTH_PX","BAR_MAX_WIDTH_PX","STACK_ID","PERCENT_SCALE","LABEL_ON_DARK_FILL","LABEL_ON_LIGHT_FILL","LABEL_ON_LIGHT_FILL_LUMINANCE","WHITE_LUMINANCE","channelLuminance","channel","normalized","parseColorChannels","color","hexMatch","digits","expanded","digit","start","rgbMatch","relativeLuminance","channels","red","green","blue","contrastRatio","lighter","darker","labelColorOnFill","fillColor","luminance","againstLightText","PERCENT_LABEL","formatPercent","value","resolveValueFormatter","input","nullSafeValueFormatter","formatValue","alignValuesToCategories","data","categories","valueByCategory","point","category","toShareOfCategoryTotal","valuesBySeries","categoryCount","categoryTotals","_unused","categoryIndex","total","values","categoryTotal","labelPosition","fitsInsideBar","params","seriesLabelLayout","hideOverlap","seriesLabel","position","categoryAxis","theme","orientation","valueAxis","options","stacking","isPercent","buildBarChartOption","series","isHorizontal","alignedValues","plottedValues","labelLayout","categoryAxisOption","valueAxisOption","index"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),S=require("react"),l=require("react-aria-components"),C=require("../chart-palette.cjs");;/* empty css */const _=require("../../../hooks/useOverlayPortal.cjs"),m={palette:"Color palette",colorOption:e=>`Color ${e}`,automaticColor:"Automatic color"};function d(e){try{return l.parseColor(e).toString("hex")}catch{return e}}function E(e,c){const o=c.toString("hex"),n=e.findIndex(r=>d(r)===o);return n<0?void 0:C.CHART_SERIES_COLOR_TOKENS[n]}function R(e){const c=window.getComputedStyle(e);return C.CHART_SERIES_COLOR_TOKENS.map(o=>c.getPropertyValue(o).trim())}const f=[];function P({colorToken:e,isResettable:c,labels:o,onChoose:n}){const[r,h]=S.useState(f),i=S.useRef(null);S.useLayoutEffect(()=>{const a=i.current;a&&r.length===0&&h(R(a))},[r]);const u=e?C.CHART_SERIES_COLOR_TOKENS.indexOf(e):-1,p=u<0?void 0:r[u];return t.jsxs("div",{ref:i,className:"chart-color-picker",children:[t.jsx(l.ColorSwatchPicker,{className:"chart-color-picker__colors","aria-label":o.palette,value:p,onChange:a=>{const s=E(r,a);s&&n(s)},children:r.map((a,s)=>t.jsx(l.ColorSwatchPickerItem,{color:a,className:"chart-color-picker__color",children:t.jsx(l.ColorSwatch,{"aria-label":o.colorOption(s+1)})},C.CHART_SERIES_COLOR_TOKENS[s]))}),c&&t.jsx(l.Button,{className:"chart-color-picker__reset",onPress:()=>n(null),children:o.automaticColor})]})}function x({colorToken:e,onChange:c,isResettable:o=!0,labels:n,triggerLabel:r,triggerClassName:h,triggerStyle:i,children:u}){const p=_.useOverlayPortalContainer(),a={...m,...n};return t.jsxs(l.DialogTrigger,{children:[t.jsx(l.Button,{className:h,style:i,"aria-label":r,children:u}),t.jsx(l.Popover,{className:"chart-color-picker-popover",placement:"bottom start",UNSTABLE_portalContainer:p,children:t.jsx(l.Dialog,{className:"chart-color-picker-dialog","aria-label":a.palette,children:({close:s})=>t.jsx(P,{colorToken:e,isResettable:o,labels:a,onChoose:O=>{s(),c(O)}})})})]})}exports.ChartColorPicker=x;
2
+ //# sourceMappingURL=ChartColorPicker.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartColorPicker.cjs","sources":["../../../../../../src/ui/components/charts/ChartColorPicker/ChartColorPicker.tsx"],"sourcesContent":["import { useOverlayPortalContainer } from \"hooks\";\nimport { useLayoutEffect, useRef, useState, type ReactNode } from \"react\";\nimport {\n Button as RACButton,\n ColorSwatch,\n ColorSwatchPicker,\n ColorSwatchPickerItem,\n Dialog,\n DialogTrigger,\n Popover as RACPopover,\n parseColor,\n type Color,\n} from \"react-aria-components\";\nimport { CHART_SERIES_COLOR_TOKENS } from \"../chart-palette\";\nimport \"./chart-color-picker.css\";\n\nexport interface ChartColorPickerLabels {\n palette: string;\n colorOption: (position: number) => string;\n automaticColor: string;\n}\n\nconst DEFAULT_LABELS: ChartColorPickerLabels = {\n palette: \"Color palette\",\n colorOption: (position: number) => `Color ${position}`,\n automaticColor: \"Automatic color\",\n};\n\nexport interface ChartColorPickerProps {\n // O token escolhido, que é o que se persiste. A resolução para cor acontece aqui dentro: o\n // `ColorSwatchPicker` compara cor, e um `var(--token)` não é cor que ele saiba ler.\n colorToken?: string;\n // `null` desfaz a escolha e devolve a série à cor que a paleta daria sozinha.\n onChange: (colorToken: string | null) => void;\n // Nem todo uso tem estado automático para voltar: a cor de uma query, por exemplo, é sempre\n // alguma — quem não escolheu vale a que a paleta daria àquela posição, e desfazer não muda nada.\n isResettable?: boolean;\n labels?: Partial<ChartColorPickerLabels>;\n // O gatilho é do consumidor: a legenda usa o próprio marcador da série, e um formulário usa um\n // botão com o nome da cor ao lado. Daqui sai só o comportamento de abrir.\n triggerLabel: string;\n triggerClassName?: string;\n triggerStyle?: React.CSSProperties;\n children?: ReactNode;\n}\n\n// O seletor devolve cor, e a persistência é por token: a volta é por igualdade de cor, e o hexa é\n// a forma canônica que faz `rgb(33, 150, 243)` e `#2196f3` casarem.\nfunction canonicalColor(color: string): string {\n try {\n return parseColor(color).toString(\"hex\");\n } catch {\n return color;\n }\n}\n\nfunction tokenOfColor(paletteColors: string[], color: Color): string | undefined {\n const chosen: string = color.toString(\"hex\");\n const position: number = paletteColors.findIndex(\n (paletteColor: string) => canonicalColor(paletteColor) === chosen,\n );\n return position < 0 ? undefined : CHART_SERIES_COLOR_TOKENS[position];\n}\n\n// O `ColorSwatchPicker` compara cor, e `var(--token)` não é cor que ele saiba ler: o valor precisa\n// ser lido do elemento, contra o qual o tema em escopo menor que `:root` continua valendo.\nfunction resolvePaletteColors(element: HTMLElement): string[] {\n const styles: CSSStyleDeclaration = window.getComputedStyle(element);\n return CHART_SERIES_COLOR_TOKENS.map((token: string) => styles.getPropertyValue(token).trim());\n}\n\nconst NO_PALETTE_COLORS: string[] = [];\n\ninterface ChartColorPaletteProps {\n colorToken?: string;\n isResettable: boolean;\n labels: ChartColorPickerLabels;\n onChoose: (colorToken: string | null) => void;\n}\n\n// Monta a cada abertura, e é isso que faz a cor de cada token ser relida: a troca de tema muda o\n// que eles resolvem, e uma leitura única ficaria velha.\nfunction ChartColorPalette({ colorToken, isResettable, labels, onChoose }: ChartColorPaletteProps) {\n const [paletteColors, setPaletteColors] = useState<string[]>(NO_PALETTE_COLORS);\n const paletteRef = useRef<HTMLDivElement | null>(null);\n\n useLayoutEffect(() => {\n const palette: HTMLDivElement | null = paletteRef.current;\n if (palette && paletteColors.length === 0) setPaletteColors(resolvePaletteColors(palette));\n }, [paletteColors]);\n\n // A amostra escolhida sai da mesma lista que o seletor mostra: comparar o token pela posição\n // dispensa uma segunda conta da mesma cor.\n const chosenPosition: number = colorToken ? CHART_SERIES_COLOR_TOKENS.indexOf(colorToken) : -1;\n const chosenColor: string | undefined =\n chosenPosition < 0 ? undefined : paletteColors[chosenPosition];\n\n return (\n <div ref={paletteRef} className=\"chart-color-picker\">\n {/* Cinco colunas, que é a matiz, e duas linhas, que é a tonalidade: a paleta são cinco cores\n em dois tons, e nessa forma a estrutura dela fica visível. Numa fileira só o tom escuro\n parece repetição do claro. */}\n <ColorSwatchPicker\n className=\"chart-color-picker__colors\"\n aria-label={labels.palette}\n value={chosenColor}\n onChange={(color: Color) => {\n const token: string | undefined = tokenOfColor(paletteColors, color);\n // Cor fora da paleta não tem token para guardar, e gravar o hexa perderia o tema: a\n // escolha é ignorada em vez de virar uma cor que só vale em um dos dois.\n if (token) onChoose(token);\n }}\n >\n {paletteColors.map((color: string, position: number) => (\n <ColorSwatchPickerItem\n key={CHART_SERIES_COLOR_TOKENS[position]}\n color={color}\n className=\"chart-color-picker__color\"\n >\n <ColorSwatch aria-label={labels.colorOption(position + 1)} />\n </ColorSwatchPickerItem>\n ))}\n </ColorSwatchPicker>\n\n {isResettable && (\n <RACButton className=\"chart-color-picker__reset\" onPress={() => onChoose(null)}>\n {labels.automaticColor}\n </RACButton>\n )}\n </div>\n );\n}\n\nexport function ChartColorPicker({\n colorToken,\n onChange,\n isResettable = true,\n labels,\n triggerLabel,\n triggerClassName,\n triggerStyle,\n children,\n}: ChartColorPickerProps) {\n // Sem container explícito o popover faz portal no `document.body` — fora da shadow root do MFE,\n // sem CSS. É o mesmo caminho do `Select`; ver `ui/hooks/useOverlayPortal`.\n const portalContainer: Element | undefined = useOverlayPortalContainer();\n const resolvedLabels: ChartColorPickerLabels = { ...DEFAULT_LABELS, ...labels };\n\n return (\n <DialogTrigger>\n <RACButton className={triggerClassName} style={triggerStyle} aria-label={triggerLabel}>\n {children}\n </RACButton>\n\n {/* O posicionamento é do react-aria, como no `Select`: ele ancora no gatilho, vira quando não\n cabe e acompanha a rolagem. Fazer isso à mão aqui era refazer o mesmo, pior. */}\n <RACPopover\n className=\"chart-color-picker-popover\"\n placement=\"bottom start\"\n UNSTABLE_portalContainer={portalContainer}\n >\n <Dialog className=\"chart-color-picker-dialog\" aria-label={resolvedLabels.palette}>\n {({ close }: { close: () => void }) => (\n <ChartColorPalette\n colorToken={colorToken}\n isResettable={isResettable}\n labels={resolvedLabels}\n onChoose={(chosenColorToken: string | null) => {\n close();\n onChange(chosenColorToken);\n }}\n />\n )}\n </Dialog>\n </RACPopover>\n </DialogTrigger>\n );\n}\n"],"names":["DEFAULT_LABELS","position","canonicalColor","color","parseColor","tokenOfColor","paletteColors","chosen","paletteColor","CHART_SERIES_COLOR_TOKENS","resolvePaletteColors","element","styles","token","NO_PALETTE_COLORS","ChartColorPalette","colorToken","isResettable","labels","onChoose","setPaletteColors","useState","paletteRef","useRef","useLayoutEffect","palette","chosenPosition","chosenColor","jsxs","jsx","ColorSwatchPicker","ColorSwatchPickerItem","ColorSwatch","RACButton","ChartColorPicker","onChange","triggerLabel","triggerClassName","triggerStyle","children","portalContainer","useOverlayPortalContainer","resolvedLabels","DialogTrigger","RACPopover","Dialog","close","chosenColorToken"],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ import { jsxs as h, jsx as l } from "react/jsx-runtime";
2
+ import { useState as d, useRef as S, useLayoutEffect as _ } from "react";
3
+ import { DialogTrigger as P, Button as C, Popover as g, Dialog as O, ColorSwatchPicker as k, ColorSwatchPickerItem as N, ColorSwatch as v, parseColor as E } from "react-aria-components";
4
+ import { CHART_SERIES_COLOR_TOKENS as p } from "../chart-palette.js";
5
+ /* empty css */
6
+ import { useOverlayPortalContainer as L } from "../../../hooks/useOverlayPortal.js";
7
+ const x = {
8
+ palette: "Color palette",
9
+ colorOption: (o) => `Color ${o}`,
10
+ automaticColor: "Automatic color"
11
+ };
12
+ function y(o) {
13
+ try {
14
+ return E(o).toString("hex");
15
+ } catch {
16
+ return o;
17
+ }
18
+ }
19
+ function A(o, a) {
20
+ const t = a.toString("hex"), c = o.findIndex(
21
+ (r) => y(r) === t
22
+ );
23
+ return c < 0 ? void 0 : p[c];
24
+ }
25
+ function R(o) {
26
+ const a = window.getComputedStyle(o);
27
+ return p.map((t) => a.getPropertyValue(t).trim());
28
+ }
29
+ const T = [];
30
+ function b({ colorToken: o, isResettable: a, labels: t, onChoose: c }) {
31
+ const [r, m] = d(T), i = S(null);
32
+ _(() => {
33
+ const e = i.current;
34
+ e && r.length === 0 && m(R(e));
35
+ }, [r]);
36
+ const s = o ? p.indexOf(o) : -1, u = s < 0 ? void 0 : r[s];
37
+ return /* @__PURE__ */ h("div", { ref: i, className: "chart-color-picker", children: [
38
+ /* @__PURE__ */ l(
39
+ k,
40
+ {
41
+ className: "chart-color-picker__colors",
42
+ "aria-label": t.palette,
43
+ value: u,
44
+ onChange: (e) => {
45
+ const n = A(r, e);
46
+ n && c(n);
47
+ },
48
+ children: r.map((e, n) => /* @__PURE__ */ l(
49
+ N,
50
+ {
51
+ color: e,
52
+ className: "chart-color-picker__color",
53
+ children: /* @__PURE__ */ l(v, { "aria-label": t.colorOption(n + 1) })
54
+ },
55
+ p[n]
56
+ ))
57
+ }
58
+ ),
59
+ a && /* @__PURE__ */ l(C, { className: "chart-color-picker__reset", onPress: () => c(null), children: t.automaticColor })
60
+ ] });
61
+ }
62
+ function F({
63
+ colorToken: o,
64
+ onChange: a,
65
+ isResettable: t = !0,
66
+ labels: c,
67
+ triggerLabel: r,
68
+ triggerClassName: m,
69
+ triggerStyle: i,
70
+ children: s
71
+ }) {
72
+ const u = L(), e = { ...x, ...c };
73
+ return /* @__PURE__ */ h(P, { children: [
74
+ /* @__PURE__ */ l(C, { className: m, style: i, "aria-label": r, children: s }),
75
+ /* @__PURE__ */ l(
76
+ g,
77
+ {
78
+ className: "chart-color-picker-popover",
79
+ placement: "bottom start",
80
+ UNSTABLE_portalContainer: u,
81
+ children: /* @__PURE__ */ l(O, { className: "chart-color-picker-dialog", "aria-label": e.palette, children: ({ close: n }) => /* @__PURE__ */ l(
82
+ b,
83
+ {
84
+ colorToken: o,
85
+ isResettable: t,
86
+ labels: e,
87
+ onChoose: (f) => {
88
+ n(), a(f);
89
+ }
90
+ }
91
+ ) })
92
+ }
93
+ )
94
+ ] });
95
+ }
96
+ export {
97
+ F as ChartColorPicker
98
+ };
99
+ //# sourceMappingURL=ChartColorPicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartColorPicker.js","sources":["../../../../../../src/ui/components/charts/ChartColorPicker/ChartColorPicker.tsx"],"sourcesContent":["import { useOverlayPortalContainer } from \"hooks\";\nimport { useLayoutEffect, useRef, useState, type ReactNode } from \"react\";\nimport {\n Button as RACButton,\n ColorSwatch,\n ColorSwatchPicker,\n ColorSwatchPickerItem,\n Dialog,\n DialogTrigger,\n Popover as RACPopover,\n parseColor,\n type Color,\n} from \"react-aria-components\";\nimport { CHART_SERIES_COLOR_TOKENS } from \"../chart-palette\";\nimport \"./chart-color-picker.css\";\n\nexport interface ChartColorPickerLabels {\n palette: string;\n colorOption: (position: number) => string;\n automaticColor: string;\n}\n\nconst DEFAULT_LABELS: ChartColorPickerLabels = {\n palette: \"Color palette\",\n colorOption: (position: number) => `Color ${position}`,\n automaticColor: \"Automatic color\",\n};\n\nexport interface ChartColorPickerProps {\n // O token escolhido, que é o que se persiste. A resolução para cor acontece aqui dentro: o\n // `ColorSwatchPicker` compara cor, e um `var(--token)` não é cor que ele saiba ler.\n colorToken?: string;\n // `null` desfaz a escolha e devolve a série à cor que a paleta daria sozinha.\n onChange: (colorToken: string | null) => void;\n // Nem todo uso tem estado automático para voltar: a cor de uma query, por exemplo, é sempre\n // alguma — quem não escolheu vale a que a paleta daria àquela posição, e desfazer não muda nada.\n isResettable?: boolean;\n labels?: Partial<ChartColorPickerLabels>;\n // O gatilho é do consumidor: a legenda usa o próprio marcador da série, e um formulário usa um\n // botão com o nome da cor ao lado. Daqui sai só o comportamento de abrir.\n triggerLabel: string;\n triggerClassName?: string;\n triggerStyle?: React.CSSProperties;\n children?: ReactNode;\n}\n\n// O seletor devolve cor, e a persistência é por token: a volta é por igualdade de cor, e o hexa é\n// a forma canônica que faz `rgb(33, 150, 243)` e `#2196f3` casarem.\nfunction canonicalColor(color: string): string {\n try {\n return parseColor(color).toString(\"hex\");\n } catch {\n return color;\n }\n}\n\nfunction tokenOfColor(paletteColors: string[], color: Color): string | undefined {\n const chosen: string = color.toString(\"hex\");\n const position: number = paletteColors.findIndex(\n (paletteColor: string) => canonicalColor(paletteColor) === chosen,\n );\n return position < 0 ? undefined : CHART_SERIES_COLOR_TOKENS[position];\n}\n\n// O `ColorSwatchPicker` compara cor, e `var(--token)` não é cor que ele saiba ler: o valor precisa\n// ser lido do elemento, contra o qual o tema em escopo menor que `:root` continua valendo.\nfunction resolvePaletteColors(element: HTMLElement): string[] {\n const styles: CSSStyleDeclaration = window.getComputedStyle(element);\n return CHART_SERIES_COLOR_TOKENS.map((token: string) => styles.getPropertyValue(token).trim());\n}\n\nconst NO_PALETTE_COLORS: string[] = [];\n\ninterface ChartColorPaletteProps {\n colorToken?: string;\n isResettable: boolean;\n labels: ChartColorPickerLabels;\n onChoose: (colorToken: string | null) => void;\n}\n\n// Monta a cada abertura, e é isso que faz a cor de cada token ser relida: a troca de tema muda o\n// que eles resolvem, e uma leitura única ficaria velha.\nfunction ChartColorPalette({ colorToken, isResettable, labels, onChoose }: ChartColorPaletteProps) {\n const [paletteColors, setPaletteColors] = useState<string[]>(NO_PALETTE_COLORS);\n const paletteRef = useRef<HTMLDivElement | null>(null);\n\n useLayoutEffect(() => {\n const palette: HTMLDivElement | null = paletteRef.current;\n if (palette && paletteColors.length === 0) setPaletteColors(resolvePaletteColors(palette));\n }, [paletteColors]);\n\n // A amostra escolhida sai da mesma lista que o seletor mostra: comparar o token pela posição\n // dispensa uma segunda conta da mesma cor.\n const chosenPosition: number = colorToken ? CHART_SERIES_COLOR_TOKENS.indexOf(colorToken) : -1;\n const chosenColor: string | undefined =\n chosenPosition < 0 ? undefined : paletteColors[chosenPosition];\n\n return (\n <div ref={paletteRef} className=\"chart-color-picker\">\n {/* Cinco colunas, que é a matiz, e duas linhas, que é a tonalidade: a paleta são cinco cores\n em dois tons, e nessa forma a estrutura dela fica visível. Numa fileira só o tom escuro\n parece repetição do claro. */}\n <ColorSwatchPicker\n className=\"chart-color-picker__colors\"\n aria-label={labels.palette}\n value={chosenColor}\n onChange={(color: Color) => {\n const token: string | undefined = tokenOfColor(paletteColors, color);\n // Cor fora da paleta não tem token para guardar, e gravar o hexa perderia o tema: a\n // escolha é ignorada em vez de virar uma cor que só vale em um dos dois.\n if (token) onChoose(token);\n }}\n >\n {paletteColors.map((color: string, position: number) => (\n <ColorSwatchPickerItem\n key={CHART_SERIES_COLOR_TOKENS[position]}\n color={color}\n className=\"chart-color-picker__color\"\n >\n <ColorSwatch aria-label={labels.colorOption(position + 1)} />\n </ColorSwatchPickerItem>\n ))}\n </ColorSwatchPicker>\n\n {isResettable && (\n <RACButton className=\"chart-color-picker__reset\" onPress={() => onChoose(null)}>\n {labels.automaticColor}\n </RACButton>\n )}\n </div>\n );\n}\n\nexport function ChartColorPicker({\n colorToken,\n onChange,\n isResettable = true,\n labels,\n triggerLabel,\n triggerClassName,\n triggerStyle,\n children,\n}: ChartColorPickerProps) {\n // Sem container explícito o popover faz portal no `document.body` — fora da shadow root do MFE,\n // sem CSS. É o mesmo caminho do `Select`; ver `ui/hooks/useOverlayPortal`.\n const portalContainer: Element | undefined = useOverlayPortalContainer();\n const resolvedLabels: ChartColorPickerLabels = { ...DEFAULT_LABELS, ...labels };\n\n return (\n <DialogTrigger>\n <RACButton className={triggerClassName} style={triggerStyle} aria-label={triggerLabel}>\n {children}\n </RACButton>\n\n {/* O posicionamento é do react-aria, como no `Select`: ele ancora no gatilho, vira quando não\n cabe e acompanha a rolagem. Fazer isso à mão aqui era refazer o mesmo, pior. */}\n <RACPopover\n className=\"chart-color-picker-popover\"\n placement=\"bottom start\"\n UNSTABLE_portalContainer={portalContainer}\n >\n <Dialog className=\"chart-color-picker-dialog\" aria-label={resolvedLabels.palette}>\n {({ close }: { close: () => void }) => (\n <ChartColorPalette\n colorToken={colorToken}\n isResettable={isResettable}\n labels={resolvedLabels}\n onChoose={(chosenColorToken: string | null) => {\n close();\n onChange(chosenColorToken);\n }}\n />\n )}\n </Dialog>\n </RACPopover>\n </DialogTrigger>\n );\n}\n"],"names":["DEFAULT_LABELS","position","canonicalColor","color","parseColor","tokenOfColor","paletteColors","chosen","paletteColor","CHART_SERIES_COLOR_TOKENS","resolvePaletteColors","element","styles","token","NO_PALETTE_COLORS","ChartColorPalette","colorToken","isResettable","labels","onChoose","setPaletteColors","useState","paletteRef","useRef","useLayoutEffect","palette","chosenPosition","chosenColor","jsxs","jsx","ColorSwatchPicker","ColorSwatchPickerItem","ColorSwatch","RACButton","ChartColorPicker","onChange","triggerLabel","triggerClassName","triggerStyle","children","portalContainer","useOverlayPortalContainer","resolvedLabels","DialogTrigger","RACPopover","Dialog","close","chosenColorToken"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react/jsx-runtime"),t=require("../../../../vendor/clsx/dist/clsx.cjs"),_=require("../ChartColorPicker/ChartColorPicker.cjs");;/* empty css */const a={toggleSeries:o=>`Show or hide ${o}`,chooseColor:o=>`Choose the color of ${o}`},u={};function S({items:o,onToggle:d,onColorChange:n,colorTokensBySeriesId:g=u,labels:r,className:i,...l}){const h=(r==null?void 0:r.toggleSeries)??a.toggleSeries,s=(r==null?void 0:r.chooseColor)??a.chooseColor;return c.jsx("div",{className:t.clsx("chart-legend",i),...l,children:o.map(e=>c.jsxs("span",{className:"chart-legend__item",children:[n?c.jsx(_.ChartColorPicker,{colorToken:g[e.id],onChange:C=>n(e.id,C),labels:{...r,palette:s(e.name)},triggerLabel:s(e.name),triggerClassName:"chart-legend__swatch chart-legend__swatch--interactive",triggerStyle:{backgroundColor:e.color}}):c.jsx("span",{className:"chart-legend__swatch",style:{backgroundColor:e.color}}),c.jsx("button",{type:"button",className:t.clsx("chart-legend__name",e.isHidden&&"chart-legend__name--hidden"),"aria-label":h(e.name),"aria-pressed":!e.isHidden,onClick:()=>d(e.id),children:e.name})]},e.id))})}exports.ChartLegend=S;
2
+ //# sourceMappingURL=ChartLegend.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartLegend.cjs","sources":["../../../../../../src/ui/components/charts/ChartLegend/ChartLegend.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport {\n ChartColorPicker,\n type ChartColorPickerLabels,\n} from \"../ChartColorPicker/ChartColorPicker\";\nimport \"./chart-legend.css\";\n\nexport interface ChartLegendItem {\n id: string;\n name: string;\n // Já resolvida, e não o token: é o mesmo valor que o canvas desenha, e é o que o seletor de cor\n // consegue comparar para marcar qual das amostras está escolhida. O tema volta a ser lido quando\n // `prefers-color-scheme` muda, e a legenda se repinta junto com o gráfico.\n color: string;\n isHidden: boolean;\n}\n\nexport interface ChartLegendLabels extends ChartColorPickerLabels {\n toggleSeries: (seriesName: string) => string;\n chooseColor: (seriesName: string) => string;\n}\n\nconst DEFAULT_LABELS: Pick<ChartLegendLabels, \"toggleSeries\" | \"chooseColor\"> = {\n toggleSeries: (seriesName: string) => `Show or hide ${seriesName}`,\n chooseColor: (seriesName: string) => `Choose the color of ${seriesName}`,\n};\n\nexport type ChartLegendProps = Omit<ComponentPropsWithoutRef<\"div\">, \"children\" | \"onToggle\"> & {\n items: ChartLegendItem[];\n onToggle: (seriesId: string) => void;\n // A presença é o que habilita o seletor no marcador de cor: sem ela a amostra é desenho, e não\n // controle — o gráfico que não guarda cor escolhida não pode oferecer a escolha.\n onColorChange?: (seriesId: string, colorToken: string | null) => void;\n // O token por trás da cor de cada série, por id: é o que o seletor de cor recebe.\n colorTokensBySeriesId?: Record<string, string>;\n labels?: Partial<ChartLegendLabels>;\n};\n\nconst NO_COLOR_TOKENS: Record<string, string> = {};\n\nexport function ChartLegend({\n items,\n onToggle,\n onColorChange,\n colorTokensBySeriesId = NO_COLOR_TOKENS,\n labels,\n className,\n ...props\n}: ChartLegendProps) {\n const toggleSeriesLabel = labels?.toggleSeries ?? DEFAULT_LABELS.toggleSeries;\n const chooseColorLabel = labels?.chooseColor ?? DEFAULT_LABELS.chooseColor;\n\n return (\n <div className={clsx(\"chart-legend\", className)} {...props}>\n {items.map((item: ChartLegendItem) => (\n <span key={item.id} className=\"chart-legend__item\">\n {/* Dois controles por entrada, como no Grafana: a amostra escolhe a cor e o nome mostra\n ou esconde a série. Um controle só teria que decidir qual dos dois gestos perder. */}\n {onColorChange ? (\n <ChartColorPicker\n colorToken={colorTokensBySeriesId[item.id]}\n onChange={(colorToken: string | null) => onColorChange(item.id, colorToken)}\n labels={{ ...labels, palette: chooseColorLabel(item.name) }}\n triggerLabel={chooseColorLabel(item.name)}\n triggerClassName=\"chart-legend__swatch chart-legend__swatch--interactive\"\n triggerStyle={{ backgroundColor: item.color }}\n />\n ) : (\n <span className=\"chart-legend__swatch\" style={{ backgroundColor: item.color }} />\n )}\n\n <button\n type=\"button\"\n className={clsx(\"chart-legend__name\", item.isHidden && \"chart-legend__name--hidden\")}\n aria-label={toggleSeriesLabel(item.name)}\n aria-pressed={!item.isHidden}\n onClick={() => onToggle(item.id)}\n >\n {item.name}\n </button>\n </span>\n ))}\n </div>\n );\n}\n"],"names":["DEFAULT_LABELS","seriesName","NO_COLOR_TOKENS","ChartLegend","items","onToggle","onColorChange","colorTokensBySeriesId","labels","className","props","toggleSeriesLabel","chooseColorLabel","clsx","item","jsxs","jsx","ChartColorPicker","colorToken"],"mappings":"gQAuBA,MAAMA,EAA0E,CAC9E,aAAeC,GAAuB,gBAAgBA,CAAU,GAChE,YAAcA,GAAuB,uBAAuBA,CAAU,EACxE,EAaMC,EAA0C,CAAA,EAEzC,SAASC,EAAY,CAC1B,MAAAC,EACA,SAAAC,EACA,cAAAC,EACA,sBAAAC,EAAwBL,EACxB,OAAAM,EACA,UAAAC,EACA,GAAGC,CACL,EAAqB,CACnB,MAAMC,GAAoBH,GAAA,YAAAA,EAAQ,eAAgBR,EAAe,aAC3DY,GAAmBJ,GAAA,YAAAA,EAAQ,cAAeR,EAAe,YAE/D,aACG,MAAA,CAAI,UAAWa,EAAAA,KAAK,eAAgBJ,CAAS,EAAI,GAAGC,EAClD,SAAAN,EAAM,IAAKU,GACVC,EAAAA,KAAC,OAAA,CAAmB,UAAU,qBAG3B,SAAA,CAAAT,EACCU,EAAAA,IAACC,EAAAA,iBAAA,CACC,WAAYV,EAAsBO,EAAK,EAAE,EACzC,SAAWI,GAA8BZ,EAAcQ,EAAK,GAAII,CAAU,EAC1E,OAAQ,CAAE,GAAGV,EAAQ,QAASI,EAAiBE,EAAK,IAAI,CAAA,EACxD,aAAcF,EAAiBE,EAAK,IAAI,EACxC,iBAAiB,yDACjB,aAAc,CAAE,gBAAiBA,EAAK,KAAA,CAAM,CAAA,EAG9CE,MAAC,OAAA,CAAK,UAAU,uBAAuB,MAAO,CAAE,gBAAiBF,EAAK,KAAA,EAAS,EAGjFE,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,UAAWH,EAAAA,KAAK,qBAAsBC,EAAK,UAAY,4BAA4B,EACnF,aAAYH,EAAkBG,EAAK,IAAI,EACvC,eAAc,CAACA,EAAK,SACpB,QAAS,IAAMT,EAASS,EAAK,EAAE,EAE9B,SAAAA,EAAK,IAAA,CAAA,CACR,CAAA,EAxBSA,EAAK,EAyBhB,CACD,EACH,CAEJ"}
@@ -0,0 +1,47 @@
1
+ import { jsx as c, jsxs as C } from "react/jsx-runtime";
2
+ import { clsx as t } from "../../../../vendor/clsx/dist/clsx.js";
3
+ import { ChartColorPicker as p } from "../ChartColorPicker/ChartColorPicker.js";
4
+ /* empty css */
5
+ const s = {
6
+ toggleSeries: (r) => `Show or hide ${r}`,
7
+ chooseColor: (r) => `Choose the color of ${r}`
8
+ }, m = {};
9
+ function f({
10
+ items: r,
11
+ onToggle: d,
12
+ onColorChange: n,
13
+ colorTokensBySeriesId: g = m,
14
+ labels: e,
15
+ className: h,
16
+ ...i
17
+ }) {
18
+ const l = (e == null ? void 0 : e.toggleSeries) ?? s.toggleSeries, a = (e == null ? void 0 : e.chooseColor) ?? s.chooseColor;
19
+ return /* @__PURE__ */ c("div", { className: t("chart-legend", h), ...i, children: r.map((o) => /* @__PURE__ */ C("span", { className: "chart-legend__item", children: [
20
+ n ? /* @__PURE__ */ c(
21
+ p,
22
+ {
23
+ colorToken: g[o.id],
24
+ onChange: (_) => n(o.id, _),
25
+ labels: { ...e, palette: a(o.name) },
26
+ triggerLabel: a(o.name),
27
+ triggerClassName: "chart-legend__swatch chart-legend__swatch--interactive",
28
+ triggerStyle: { backgroundColor: o.color }
29
+ }
30
+ ) : /* @__PURE__ */ c("span", { className: "chart-legend__swatch", style: { backgroundColor: o.color } }),
31
+ /* @__PURE__ */ c(
32
+ "button",
33
+ {
34
+ type: "button",
35
+ className: t("chart-legend__name", o.isHidden && "chart-legend__name--hidden"),
36
+ "aria-label": l(o.name),
37
+ "aria-pressed": !o.isHidden,
38
+ onClick: () => d(o.id),
39
+ children: o.name
40
+ }
41
+ )
42
+ ] }, o.id)) });
43
+ }
44
+ export {
45
+ f as ChartLegend
46
+ };
47
+ //# sourceMappingURL=ChartLegend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartLegend.js","sources":["../../../../../../src/ui/components/charts/ChartLegend/ChartLegend.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport {\n ChartColorPicker,\n type ChartColorPickerLabels,\n} from \"../ChartColorPicker/ChartColorPicker\";\nimport \"./chart-legend.css\";\n\nexport interface ChartLegendItem {\n id: string;\n name: string;\n // Já resolvida, e não o token: é o mesmo valor que o canvas desenha, e é o que o seletor de cor\n // consegue comparar para marcar qual das amostras está escolhida. O tema volta a ser lido quando\n // `prefers-color-scheme` muda, e a legenda se repinta junto com o gráfico.\n color: string;\n isHidden: boolean;\n}\n\nexport interface ChartLegendLabels extends ChartColorPickerLabels {\n toggleSeries: (seriesName: string) => string;\n chooseColor: (seriesName: string) => string;\n}\n\nconst DEFAULT_LABELS: Pick<ChartLegendLabels, \"toggleSeries\" | \"chooseColor\"> = {\n toggleSeries: (seriesName: string) => `Show or hide ${seriesName}`,\n chooseColor: (seriesName: string) => `Choose the color of ${seriesName}`,\n};\n\nexport type ChartLegendProps = Omit<ComponentPropsWithoutRef<\"div\">, \"children\" | \"onToggle\"> & {\n items: ChartLegendItem[];\n onToggle: (seriesId: string) => void;\n // A presença é o que habilita o seletor no marcador de cor: sem ela a amostra é desenho, e não\n // controle — o gráfico que não guarda cor escolhida não pode oferecer a escolha.\n onColorChange?: (seriesId: string, colorToken: string | null) => void;\n // O token por trás da cor de cada série, por id: é o que o seletor de cor recebe.\n colorTokensBySeriesId?: Record<string, string>;\n labels?: Partial<ChartLegendLabels>;\n};\n\nconst NO_COLOR_TOKENS: Record<string, string> = {};\n\nexport function ChartLegend({\n items,\n onToggle,\n onColorChange,\n colorTokensBySeriesId = NO_COLOR_TOKENS,\n labels,\n className,\n ...props\n}: ChartLegendProps) {\n const toggleSeriesLabel = labels?.toggleSeries ?? DEFAULT_LABELS.toggleSeries;\n const chooseColorLabel = labels?.chooseColor ?? DEFAULT_LABELS.chooseColor;\n\n return (\n <div className={clsx(\"chart-legend\", className)} {...props}>\n {items.map((item: ChartLegendItem) => (\n <span key={item.id} className=\"chart-legend__item\">\n {/* Dois controles por entrada, como no Grafana: a amostra escolhe a cor e o nome mostra\n ou esconde a série. Um controle só teria que decidir qual dos dois gestos perder. */}\n {onColorChange ? (\n <ChartColorPicker\n colorToken={colorTokensBySeriesId[item.id]}\n onChange={(colorToken: string | null) => onColorChange(item.id, colorToken)}\n labels={{ ...labels, palette: chooseColorLabel(item.name) }}\n triggerLabel={chooseColorLabel(item.name)}\n triggerClassName=\"chart-legend__swatch chart-legend__swatch--interactive\"\n triggerStyle={{ backgroundColor: item.color }}\n />\n ) : (\n <span className=\"chart-legend__swatch\" style={{ backgroundColor: item.color }} />\n )}\n\n <button\n type=\"button\"\n className={clsx(\"chart-legend__name\", item.isHidden && \"chart-legend__name--hidden\")}\n aria-label={toggleSeriesLabel(item.name)}\n aria-pressed={!item.isHidden}\n onClick={() => onToggle(item.id)}\n >\n {item.name}\n </button>\n </span>\n ))}\n </div>\n );\n}\n"],"names":["DEFAULT_LABELS","seriesName","NO_COLOR_TOKENS","ChartLegend","items","onToggle","onColorChange","colorTokensBySeriesId","labels","className","props","toggleSeriesLabel","chooseColorLabel","clsx","item","jsxs","jsx","ChartColorPicker","colorToken"],"mappings":";;;;AAuBA,MAAMA,IAA0E;AAAA,EAC9E,cAAc,CAACC,MAAuB,gBAAgBA,CAAU;AAAA,EAChE,aAAa,CAACA,MAAuB,uBAAuBA,CAAU;AACxE,GAaMC,IAA0C,CAAA;AAEzC,SAASC,EAAY;AAAA,EAC1B,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,eAAAC;AAAA,EACA,uBAAAC,IAAwBL;AAAA,EACxB,QAAAM;AAAA,EACA,WAAAC;AAAA,EACA,GAAGC;AACL,GAAqB;AACnB,QAAMC,KAAoBH,KAAA,gBAAAA,EAAQ,iBAAgBR,EAAe,cAC3DY,KAAmBJ,KAAA,gBAAAA,EAAQ,gBAAeR,EAAe;AAE/D,2BACG,OAAA,EAAI,WAAWa,EAAK,gBAAgBJ,CAAS,GAAI,GAAGC,GAClD,UAAAN,EAAM,IAAI,CAACU,MACV,gBAAAC,EAAC,QAAA,EAAmB,WAAU,sBAG3B,UAAA;AAAA,IAAAT,IACC,gBAAAU;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,YAAYV,EAAsBO,EAAK,EAAE;AAAA,QACzC,UAAU,CAACI,MAA8BZ,EAAcQ,EAAK,IAAII,CAAU;AAAA,QAC1E,QAAQ,EAAE,GAAGV,GAAQ,SAASI,EAAiBE,EAAK,IAAI,EAAA;AAAA,QACxD,cAAcF,EAAiBE,EAAK,IAAI;AAAA,QACxC,kBAAiB;AAAA,QACjB,cAAc,EAAE,iBAAiBA,EAAK,MAAA;AAAA,MAAM;AAAA,IAAA,IAG9C,gBAAAE,EAAC,QAAA,EAAK,WAAU,wBAAuB,OAAO,EAAE,iBAAiBF,EAAK,MAAA,GAAS;AAAA,IAGjF,gBAAAE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAWH,EAAK,sBAAsBC,EAAK,YAAY,4BAA4B;AAAA,QACnF,cAAYH,EAAkBG,EAAK,IAAI;AAAA,QACvC,gBAAc,CAACA,EAAK;AAAA,QACpB,SAAS,MAAMT,EAASS,EAAK,EAAE;AAAA,QAE9B,UAAAA,EAAK;AAAA,MAAA;AAAA,IAAA;AAAA,EACR,EAAA,GAxBSA,EAAK,EAyBhB,CACD,GACH;AAEJ;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react"),d=require("../chart-palette.cjs");function T(t,r,u){const[s,S]=c.useState(()=>new Set),l=c.useCallback(e=>{S(n=>{const o=new Set(n);return o.has(e)?o.delete(e):o.add(e),o})},[]),h=c.useMemo(()=>{const e={};return t.forEach((n,o)=>{e[n.id]=n.colorToken??d.CHART_SERIES_COLOR_TOKENS[o%d.CHART_SERIES_COLOR_TOKENS.length]}),e},[t]),i=c.useMemo(()=>{const e={};return t.forEach((n,o)=>{const m=n.colorToken?u(n.colorToken):void 0;e[n.id]=m??r[o%r.length]}),e},[t,r,u]);return{items:c.useMemo(()=>t.map(e=>({id:e.id,name:e.name,color:i[e.id],isHidden:s.has(e.id)})),[t,i,s]),colorsBySeriesId:i,colorTokensBySeriesId:h,hiddenSeriesIds:s,toggleSeries:l}}exports.useChartLegend=T;
2
+ //# sourceMappingURL=use-chart-legend.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-chart-legend.cjs","sources":["../../../../../../src/ui/components/charts/ChartLegend/use-chart-legend.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\nimport { CHART_SERIES_COLOR_TOKENS } from \"../chart-palette\";\nimport type { ChartLegendItem } from \"./ChartLegend\";\n\nexport interface ChartLegendSeries {\n id: string;\n name: string;\n colorToken?: string;\n}\n\nexport interface ChartLegendState {\n items: ChartLegendItem[];\n // Por id, e já resolvida: é o que o canvas recebe. Fica com todas as séries, e não só com as\n // visíveis, porque a cor de quem não escolheu token sai da posição — recalculá-la sobre a lista\n // filtrada faria esconder uma série repintar todas as que vêm depois dela.\n colorsBySeriesId: Record<string, string>;\n // O token por trás da cor: a escolhida, ou a que a paleta dá àquela posição. É o que o seletor\n // de cor recebe, porque token é o que se persiste.\n colorTokensBySeriesId: Record<string, string>;\n hiddenSeriesIds: Set<string>;\n toggleSeries: (seriesId: string) => void;\n}\n\nexport function useChartLegend(\n series: ChartLegendSeries[],\n paletteColors: string[],\n resolveSeriesColor: (token: string) => string | undefined,\n): ChartLegendState {\n const [hiddenSeriesIds, setHiddenSeriesIds] = useState<Set<string>>(() => new Set<string>());\n\n const toggleSeries = useCallback((seriesId: string): void => {\n setHiddenSeriesIds((current: Set<string>) => {\n const next: Set<string> = new Set(current);\n if (next.has(seriesId)) next.delete(seriesId);\n else next.add(seriesId);\n return next;\n });\n }, []);\n\n const colorTokensBySeriesId: Record<string, string> = useMemo(() => {\n const tokens: Record<string, string> = {};\n series.forEach((data: ChartLegendSeries, index: number) => {\n tokens[data.id] =\n data.colorToken ?? CHART_SERIES_COLOR_TOKENS[index % CHART_SERIES_COLOR_TOKENS.length];\n });\n return tokens;\n }, [series]);\n\n const colorsBySeriesId: Record<string, string> = useMemo(() => {\n const colors: Record<string, string> = {};\n series.forEach((data: ChartLegendSeries, index: number) => {\n const chosen: string | undefined = data.colorToken\n ? resolveSeriesColor(data.colorToken)\n : undefined;\n colors[data.id] = chosen ?? paletteColors[index % paletteColors.length];\n });\n return colors;\n }, [series, paletteColors, resolveSeriesColor]);\n\n // A legenda mostra a mesma cor resolvida que o canvas desenha, e não o token: é o que o seletor\n // de cor compara para marcar a amostra escolhida, e o que impede as duas metades da tela de\n // discordarem sobre a cor de uma série.\n const items: ChartLegendItem[] = useMemo(\n () =>\n series.map((data: ChartLegendSeries) => ({\n id: data.id,\n name: data.name,\n color: colorsBySeriesId[data.id],\n isHidden: hiddenSeriesIds.has(data.id),\n })),\n [series, colorsBySeriesId, hiddenSeriesIds],\n );\n\n return { items, colorsBySeriesId, colorTokensBySeriesId, hiddenSeriesIds, toggleSeries };\n}\n"],"names":["useChartLegend","series","paletteColors","resolveSeriesColor","hiddenSeriesIds","setHiddenSeriesIds","useState","toggleSeries","useCallback","seriesId","current","next","colorTokensBySeriesId","useMemo","tokens","data","index","CHART_SERIES_COLOR_TOKENS","colorsBySeriesId","colors","chosen"],"mappings":"2IAuBO,SAASA,EACdC,EACAC,EACAC,EACkB,CAClB,KAAM,CAACC,EAAiBC,CAAkB,EAAIC,EAAAA,SAAsB,IAAM,IAAI,GAAa,EAErFC,EAAeC,cAAaC,GAA2B,CAC3DJ,EAAoBK,GAAyB,CAC3C,MAAMC,EAAoB,IAAI,IAAID,CAAO,EACzC,OAAIC,EAAK,IAAIF,CAAQ,EAAGE,EAAK,OAAOF,CAAQ,EACvCE,EAAK,IAAIF,CAAQ,EACfE,CACT,CAAC,CACH,EAAG,CAAA,CAAE,EAECC,EAAgDC,EAAAA,QAAQ,IAAM,CAClE,MAAMC,EAAiC,CAAA,EACvC,OAAAb,EAAO,QAAQ,CAACc,EAAyBC,IAAkB,CACzDF,EAAOC,EAAK,EAAE,EACZA,EAAK,YAAcE,4BAA0BD,EAAQC,EAAAA,0BAA0B,MAAM,CACzF,CAAC,EACMH,CACT,EAAG,CAACb,CAAM,CAAC,EAELiB,EAA2CL,EAAAA,QAAQ,IAAM,CAC7D,MAAMM,EAAiC,CAAA,EACvC,OAAAlB,EAAO,QAAQ,CAACc,EAAyBC,IAAkB,CACzD,MAAMI,EAA6BL,EAAK,WACpCZ,EAAmBY,EAAK,UAAU,EAClC,OACJI,EAAOJ,EAAK,EAAE,EAAIK,GAAUlB,EAAcc,EAAQd,EAAc,MAAM,CACxE,CAAC,EACMiB,CACT,EAAG,CAAClB,EAAQC,EAAeC,CAAkB,CAAC,EAgB9C,MAAO,CAAE,MAXwBU,EAAAA,QAC/B,IACEZ,EAAO,IAAKc,IAA6B,CACvC,GAAIA,EAAK,GACT,KAAMA,EAAK,KACX,MAAOG,EAAiBH,EAAK,EAAE,EAC/B,SAAUX,EAAgB,IAAIW,EAAK,EAAE,CAAA,EACrC,EACJ,CAACd,EAAQiB,EAAkBd,CAAe,CAAA,EAG5B,iBAAAc,EAAkB,sBAAAN,EAAuB,gBAAAR,EAAiB,aAAAG,CAAA,CAC5E"}
@@ -0,0 +1,34 @@
1
+ import { useState as f, useCallback as k, useMemo as s } from "react";
2
+ import { CHART_SERIES_COLOR_TOKENS as m } from "../chart-palette.js";
3
+ function H(c, t, d) {
4
+ const [r, S] = f(() => /* @__PURE__ */ new Set()), h = k((o) => {
5
+ S((n) => {
6
+ const e = new Set(n);
7
+ return e.has(o) ? e.delete(o) : e.add(o), e;
8
+ });
9
+ }, []), u = s(() => {
10
+ const o = {};
11
+ return c.forEach((n, e) => {
12
+ o[n.id] = n.colorToken ?? m[e % m.length];
13
+ }), o;
14
+ }, [c]), i = s(() => {
15
+ const o = {};
16
+ return c.forEach((n, e) => {
17
+ const l = n.colorToken ? d(n.colorToken) : void 0;
18
+ o[n.id] = l ?? t[e % t.length];
19
+ }), o;
20
+ }, [c, t, d]);
21
+ return { items: s(
22
+ () => c.map((o) => ({
23
+ id: o.id,
24
+ name: o.name,
25
+ color: i[o.id],
26
+ isHidden: r.has(o.id)
27
+ })),
28
+ [c, i, r]
29
+ ), colorsBySeriesId: i, colorTokensBySeriesId: u, hiddenSeriesIds: r, toggleSeries: h };
30
+ }
31
+ export {
32
+ H as useChartLegend
33
+ };
34
+ //# sourceMappingURL=use-chart-legend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-chart-legend.js","sources":["../../../../../../src/ui/components/charts/ChartLegend/use-chart-legend.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\nimport { CHART_SERIES_COLOR_TOKENS } from \"../chart-palette\";\nimport type { ChartLegendItem } from \"./ChartLegend\";\n\nexport interface ChartLegendSeries {\n id: string;\n name: string;\n colorToken?: string;\n}\n\nexport interface ChartLegendState {\n items: ChartLegendItem[];\n // Por id, e já resolvida: é o que o canvas recebe. Fica com todas as séries, e não só com as\n // visíveis, porque a cor de quem não escolheu token sai da posição — recalculá-la sobre a lista\n // filtrada faria esconder uma série repintar todas as que vêm depois dela.\n colorsBySeriesId: Record<string, string>;\n // O token por trás da cor: a escolhida, ou a que a paleta dá àquela posição. É o que o seletor\n // de cor recebe, porque token é o que se persiste.\n colorTokensBySeriesId: Record<string, string>;\n hiddenSeriesIds: Set<string>;\n toggleSeries: (seriesId: string) => void;\n}\n\nexport function useChartLegend(\n series: ChartLegendSeries[],\n paletteColors: string[],\n resolveSeriesColor: (token: string) => string | undefined,\n): ChartLegendState {\n const [hiddenSeriesIds, setHiddenSeriesIds] = useState<Set<string>>(() => new Set<string>());\n\n const toggleSeries = useCallback((seriesId: string): void => {\n setHiddenSeriesIds((current: Set<string>) => {\n const next: Set<string> = new Set(current);\n if (next.has(seriesId)) next.delete(seriesId);\n else next.add(seriesId);\n return next;\n });\n }, []);\n\n const colorTokensBySeriesId: Record<string, string> = useMemo(() => {\n const tokens: Record<string, string> = {};\n series.forEach((data: ChartLegendSeries, index: number) => {\n tokens[data.id] =\n data.colorToken ?? CHART_SERIES_COLOR_TOKENS[index % CHART_SERIES_COLOR_TOKENS.length];\n });\n return tokens;\n }, [series]);\n\n const colorsBySeriesId: Record<string, string> = useMemo(() => {\n const colors: Record<string, string> = {};\n series.forEach((data: ChartLegendSeries, index: number) => {\n const chosen: string | undefined = data.colorToken\n ? resolveSeriesColor(data.colorToken)\n : undefined;\n colors[data.id] = chosen ?? paletteColors[index % paletteColors.length];\n });\n return colors;\n }, [series, paletteColors, resolveSeriesColor]);\n\n // A legenda mostra a mesma cor resolvida que o canvas desenha, e não o token: é o que o seletor\n // de cor compara para marcar a amostra escolhida, e o que impede as duas metades da tela de\n // discordarem sobre a cor de uma série.\n const items: ChartLegendItem[] = useMemo(\n () =>\n series.map((data: ChartLegendSeries) => ({\n id: data.id,\n name: data.name,\n color: colorsBySeriesId[data.id],\n isHidden: hiddenSeriesIds.has(data.id),\n })),\n [series, colorsBySeriesId, hiddenSeriesIds],\n );\n\n return { items, colorsBySeriesId, colorTokensBySeriesId, hiddenSeriesIds, toggleSeries };\n}\n"],"names":["useChartLegend","series","paletteColors","resolveSeriesColor","hiddenSeriesIds","setHiddenSeriesIds","useState","toggleSeries","useCallback","seriesId","current","next","colorTokensBySeriesId","useMemo","tokens","data","index","CHART_SERIES_COLOR_TOKENS","colorsBySeriesId","colors","chosen"],"mappings":";;AAuBO,SAASA,EACdC,GACAC,GACAC,GACkB;AAClB,QAAM,CAACC,GAAiBC,CAAkB,IAAIC,EAAsB,MAAM,oBAAI,KAAa,GAErFC,IAAeC,EAAY,CAACC,MAA2B;AAC3D,IAAAJ,EAAmB,CAACK,MAAyB;AAC3C,YAAMC,IAAoB,IAAI,IAAID,CAAO;AACzC,aAAIC,EAAK,IAAIF,CAAQ,IAAGE,EAAK,OAAOF,CAAQ,IACvCE,EAAK,IAAIF,CAAQ,GACfE;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAA,CAAE,GAECC,IAAgDC,EAAQ,MAAM;AAClE,UAAMC,IAAiC,CAAA;AACvC,WAAAb,EAAO,QAAQ,CAACc,GAAyBC,MAAkB;AACzD,MAAAF,EAAOC,EAAK,EAAE,IACZA,EAAK,cAAcE,EAA0BD,IAAQC,EAA0B,MAAM;AAAA,IACzF,CAAC,GACMH;AAAA,EACT,GAAG,CAACb,CAAM,CAAC,GAELiB,IAA2CL,EAAQ,MAAM;AAC7D,UAAMM,IAAiC,CAAA;AACvC,WAAAlB,EAAO,QAAQ,CAACc,GAAyBC,MAAkB;AACzD,YAAMI,IAA6BL,EAAK,aACpCZ,EAAmBY,EAAK,UAAU,IAClC;AACJ,MAAAI,EAAOJ,EAAK,EAAE,IAAIK,KAAUlB,EAAcc,IAAQd,EAAc,MAAM;AAAA,IACxE,CAAC,GACMiB;AAAA,EACT,GAAG,CAAClB,GAAQC,GAAeC,CAAkB,CAAC;AAgB9C,SAAO,EAAE,OAXwBU;AAAA,IAC/B,MACEZ,EAAO,IAAI,CAACc,OAA6B;AAAA,MACvC,IAAIA,EAAK;AAAA,MACT,MAAMA,EAAK;AAAA,MACX,OAAOG,EAAiBH,EAAK,EAAE;AAAA,MAC/B,UAAUX,EAAgB,IAAIW,EAAK,EAAE;AAAA,IAAA,EACrC;AAAA,IACJ,CAACd,GAAQiB,GAAkBd,CAAe;AAAA,EAAA,GAG5B,kBAAAc,GAAkB,uBAAAN,GAAuB,iBAAAR,GAAiB,cAAAG,EAAA;AAC5E;"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const C=require("react/jsx-runtime"),I=require("../../../../vendor/clsx/dist/clsx.cjs"),d=require("react"),h=require("../useChartInstance.cjs"),P=require("./time-series-option.cjs");;/* empty css */const _={},E={};function M({series:e,displayType:n="line",legend:o="inline",line:c=E,yAxis:s=_,showSymbols:u=!1,showValueLabels:a=!1,valueFormatter:f,className:T,...m}){const{containerRef:q,chart:r,theme:t,resolveSeriesColor:l}=h.useChartInstance();return d.useEffect(()=>{if(!r||!t)return;const O={};for(const i of e){if(!i.colorToken)continue;const S=l(i.colorToken);S&&(O[i.id]=S)}r.setOption(P.buildTimeSeriesOption({series:e,displayType:n,legend:o,line:c,yAxis:s,theme:t,showSymbols:u,showValueLabels:a,seriesColorOverrides:O,valueFormatter:f}),{notMerge:!0})},[r,t,l,e,n,o,c,s,u,a,f]),C.jsx("div",{ref:q,className:I.clsx("time-series-chart",T),...m})}exports.TimeSeriesChart=M;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("react/jsx-runtime"),L=require("../../../../vendor/clsx/dist/clsx.cjs"),S=require("react"),M=require("../useChartInstance.cjs"),N=require("../ChartLegend/ChartLegend.cjs"),P=require("../ChartLegend/use-chart-legend.cjs"),b=require("./time-series-option.cjs");;/* empty css */const E={},R={};function Y({series:r,displayType:t="line",legend:h="inline",line:n=R,yAxis:o=E,showSymbols:c=!1,showValueLabels:a=!1,valueFormatter:l,onSeriesColorChange:C,legendLabels:f,className:m,...I}){const{containerRef:O,chart:s,theme:e,resolveSeriesColor:T}=M.useChartInstance(),{items:q,colorsBySeriesId:u,colorTokensBySeriesId:_,hiddenSeriesIds:d,toggleSeries:v}=P.useChartLegend(r,(e==null?void 0:e.seriesColors)??[],T),g=S.useMemo(()=>r.filter(x=>!d.has(x.id)),[r,d]);S.useEffect(()=>{!s||!e||s.setOption(b.buildTimeSeriesOption({series:g,displayType:t,line:n,yAxis:o,theme:e,showSymbols:c,showValueLabels:a,seriesColorOverrides:u,valueFormatter:l}),{notMerge:!0})},[s,e,g,t,n,o,c,a,u,l]);const j=h!=="none"&&r.length>0;return i.jsxs("div",{className:L.clsx("time-series-chart",m),...I,children:[j&&i.jsx(N.ChartLegend,{items:q,onToggle:v,onColorChange:C,colorTokensBySeriesId:_,labels:f}),i.jsx("div",{ref:O,className:"time-series-chart__canvas"})]})}exports.TimeSeriesChart=Y;
2
2
  //# sourceMappingURL=TimeSeriesChart.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"TimeSeriesChart.cjs","sources":["../../../../../../src/ui/components/charts/TimeSeriesChart/TimeSeriesChart.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport { type ComponentPropsWithoutRef, useEffect } from \"react\";\nimport { useChartInstance, type ChartInstance } from \"../useChartInstance\";\nimport {\n buildTimeSeriesOption,\n type TimeSeriesData,\n type TimeSeriesDisplayType,\n type TimeSeriesLegendMode,\n type TimeSeriesLineOptions,\n type TimeSeriesYAxisOptions,\n} from \"./time-series-option\";\nimport \"./time-series-chart.css\";\n\nexport type {\n TimeSeriesData,\n TimeSeriesDisplayType,\n TimeSeriesLegendMode,\n TimeSeriesLineOptions,\n TimeSeriesLineStyle,\n TimeSeriesLineWidth,\n TimeSeriesPoint,\n TimeSeriesYAxisOptions,\n} from \"./time-series-option\";\n\nexport type TimeSeriesChartProps = Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> & {\n series: TimeSeriesData[];\n displayType?: TimeSeriesDisplayType;\n legend?: TimeSeriesLegendMode;\n line?: TimeSeriesLineOptions;\n yAxis?: TimeSeriesYAxisOptions;\n showSymbols?: boolean;\n showValueLabels?: boolean;\n valueFormatter?: (value: number) => string;\n};\n\nconst EMPTY_Y_AXIS_OPTIONS: TimeSeriesYAxisOptions = {};\n\nconst EMPTY_LINE_OPTIONS: TimeSeriesLineOptions = {};\n\nexport function TimeSeriesChart({\n series,\n displayType = \"line\",\n legend = \"inline\",\n line = EMPTY_LINE_OPTIONS,\n yAxis = EMPTY_Y_AXIS_OPTIONS,\n showSymbols = false,\n showValueLabels = false,\n valueFormatter,\n className,\n ...props\n}: TimeSeriesChartProps) {\n const { containerRef, chart, theme, resolveSeriesColor }: ChartInstance = useChartInstance();\n\n useEffect(() => {\n if (!chart || !theme) return;\n\n const seriesColorOverrides: Record<string, string> = {};\n for (const data of series) {\n if (!data.colorToken) continue;\n const color: string | undefined = resolveSeriesColor(data.colorToken);\n if (color) seriesColorOverrides[data.id] = color;\n }\n\n // `notMerge` evita que uma série removida da configuração continue desenhada: o ECharts\n // casa séries por id e mantém as que não aparecem na opção nova.\n chart.setOption(\n buildTimeSeriesOption({\n series,\n displayType,\n legend,\n line,\n yAxis,\n theme,\n showSymbols,\n showValueLabels,\n seriesColorOverrides,\n valueFormatter,\n }),\n { notMerge: true },\n );\n }, [\n chart,\n theme,\n resolveSeriesColor,\n series,\n displayType,\n legend,\n line,\n yAxis,\n showSymbols,\n showValueLabels,\n valueFormatter,\n ]);\n\n return <div ref={containerRef} className={clsx(\"time-series-chart\", className)} {...props} />;\n}\n"],"names":["EMPTY_Y_AXIS_OPTIONS","EMPTY_LINE_OPTIONS","TimeSeriesChart","series","displayType","legend","line","yAxis","showSymbols","showValueLabels","valueFormatter","className","props","containerRef","chart","theme","resolveSeriesColor","useChartInstance","useEffect","seriesColorOverrides","data","color","buildTimeSeriesOption","jsx","clsx"],"mappings":"6SAmCA,MAAMA,EAA+C,CAAA,EAE/CC,EAA4C,CAAA,EAE3C,SAASC,EAAgB,CAC9B,OAAAC,EACA,YAAAC,EAAc,OACd,OAAAC,EAAS,SACT,KAAAC,EAAOL,EACP,MAAAM,EAAQP,EACR,YAAAQ,EAAc,GACd,gBAAAC,EAAkB,GAClB,eAAAC,EACA,UAAAC,EACA,GAAGC,CACL,EAAyB,CACvB,KAAM,CAAE,aAAAC,EAAc,MAAAC,EAAO,MAAAC,EAAO,mBAAAC,CAAA,EAAsCC,EAAAA,iBAAA,EAE1EC,OAAAA,EAAAA,UAAU,IAAM,CACd,GAAI,CAACJ,GAAS,CAACC,EAAO,OAEtB,MAAMI,EAA+C,CAAA,EACrD,UAAWC,KAAQjB,EAAQ,CACzB,GAAI,CAACiB,EAAK,WAAY,SACtB,MAAMC,EAA4BL,EAAmBI,EAAK,UAAU,EAChEC,IAAOF,EAAqBC,EAAK,EAAE,EAAIC,EAC7C,CAIAP,EAAM,UACJQ,wBAAsB,CACpB,OAAAnB,EACA,YAAAC,EACA,OAAAC,EACA,KAAAC,EACA,MAAAC,EACA,MAAAQ,EACA,YAAAP,EACA,gBAAAC,EACA,qBAAAU,EACA,eAAAT,CAAA,CACD,EACD,CAAE,SAAU,EAAA,CAAK,CAErB,EAAG,CACDI,EACAC,EACAC,EACAb,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,CAAA,CACD,EAEMa,MAAC,MAAA,CAAI,IAAKV,EAAc,UAAWW,EAAAA,KAAK,oBAAqBb,CAAS,EAAI,GAAGC,CAAA,CAAO,CAC7F"}
1
+ {"version":3,"file":"TimeSeriesChart.cjs","sources":["../../../../../../src/ui/components/charts/TimeSeriesChart/TimeSeriesChart.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport { type ComponentPropsWithoutRef, useEffect, useMemo } from \"react\";\nimport { useChartInstance, type ChartInstance } from \"../useChartInstance\";\nimport { ChartLegend, type ChartLegendLabels } from \"../ChartLegend/ChartLegend\";\nimport { useChartLegend, type ChartLegendState } from \"../ChartLegend/use-chart-legend\";\nimport {\n buildTimeSeriesOption,\n type TimeSeriesData,\n type TimeSeriesDisplayType,\n type TimeSeriesLegendMode,\n type TimeSeriesLineOptions,\n type TimeSeriesYAxisOptions,\n} from \"./time-series-option\";\nimport \"./time-series-chart.css\";\n\nexport type {\n TimeSeriesData,\n TimeSeriesDisplayType,\n TimeSeriesLegendMode,\n TimeSeriesLineOptions,\n TimeSeriesLineStyle,\n TimeSeriesLineWidth,\n TimeSeriesPoint,\n TimeSeriesYAxisOptions,\n} from \"./time-series-option\";\n\nexport type TimeSeriesChartProps = Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> & {\n series: TimeSeriesData[];\n displayType?: TimeSeriesDisplayType;\n legend?: TimeSeriesLegendMode;\n line?: TimeSeriesLineOptions;\n yAxis?: TimeSeriesYAxisOptions;\n showSymbols?: boolean;\n showValueLabels?: boolean;\n valueFormatter?: (value: number) => string;\n // Habilita o seletor de cor no marcador da legenda. Sem ele o marcador é só desenho — o gráfico\n // que não tem onde guardar a escolha não pode oferecê-la.\n onSeriesColorChange?: (seriesId: string, colorToken: string | null) => void;\n legendLabels?: Partial<ChartLegendLabels>;\n};\n\nconst EMPTY_Y_AXIS_OPTIONS: TimeSeriesYAxisOptions = {};\n\nconst EMPTY_LINE_OPTIONS: TimeSeriesLineOptions = {};\n\nexport function TimeSeriesChart({\n series,\n displayType = \"line\",\n legend = \"inline\",\n line = EMPTY_LINE_OPTIONS,\n yAxis = EMPTY_Y_AXIS_OPTIONS,\n showSymbols = false,\n showValueLabels = false,\n valueFormatter,\n onSeriesColorChange,\n legendLabels,\n className,\n ...props\n}: TimeSeriesChartProps) {\n const { containerRef, chart, theme, resolveSeriesColor }: ChartInstance = useChartInstance();\n\n const {\n items,\n colorsBySeriesId,\n colorTokensBySeriesId,\n hiddenSeriesIds,\n toggleSeries,\n }: ChartLegendState =\n useChartLegend(series, theme?.seriesColors ?? [], resolveSeriesColor);\n\n // A série escondida sai da opção inteira, em vez de ficar com a seleção desligada do ECharts: é\n // o que faz o eixo reescalar sobre o que restou.\n const visibleSeries: TimeSeriesData[] = useMemo(\n () => series.filter((data: TimeSeriesData) => !hiddenSeriesIds.has(data.id)),\n [series, hiddenSeriesIds],\n );\n\n useEffect(() => {\n if (!chart || !theme) return;\n\n // `notMerge` evita que uma série removida da configuração continue desenhada: o ECharts\n // casa séries por id e mantém as que não aparecem na opção nova.\n chart.setOption(\n buildTimeSeriesOption({\n series: visibleSeries,\n displayType,\n line,\n yAxis,\n theme,\n showSymbols,\n showValueLabels,\n seriesColorOverrides: colorsBySeriesId,\n valueFormatter,\n }),\n { notMerge: true },\n );\n }, [\n chart,\n theme,\n visibleSeries,\n displayType,\n line,\n yAxis,\n showSymbols,\n showValueLabels,\n colorsBySeriesId,\n valueFormatter,\n ]);\n\n const isLegendVisible: boolean = legend !== \"none\" && series.length > 0;\n\n return (\n <div className={clsx(\"time-series-chart\", className)} {...props}>\n {isLegendVisible && (\n <ChartLegend\n items={items}\n onToggle={toggleSeries}\n onColorChange={onSeriesColorChange}\n colorTokensBySeriesId={colorTokensBySeriesId}\n labels={legendLabels}\n />\n )}\n <div ref={containerRef} className=\"time-series-chart__canvas\" />\n </div>\n );\n}\n"],"names":["EMPTY_Y_AXIS_OPTIONS","EMPTY_LINE_OPTIONS","TimeSeriesChart","series","displayType","legend","line","yAxis","showSymbols","showValueLabels","valueFormatter","onSeriesColorChange","legendLabels","className","props","containerRef","chart","theme","resolveSeriesColor","useChartInstance","items","colorsBySeriesId","colorTokensBySeriesId","hiddenSeriesIds","toggleSeries","useChartLegend","visibleSeries","useMemo","data","useEffect","buildTimeSeriesOption","isLegendVisible","jsxs","clsx","jsx","ChartLegend"],"mappings":"0YAyCA,MAAMA,EAA+C,CAAA,EAE/CC,EAA4C,CAAA,EAE3C,SAASC,EAAgB,CAC9B,OAAAC,EACA,YAAAC,EAAc,OACd,OAAAC,EAAS,SACT,KAAAC,EAAOL,EACP,MAAAM,EAAQP,EACR,YAAAQ,EAAc,GACd,gBAAAC,EAAkB,GAClB,eAAAC,EACA,oBAAAC,EACA,aAAAC,EACA,UAAAC,EACA,GAAGC,CACL,EAAyB,CACvB,KAAM,CAAE,aAAAC,EAAc,MAAAC,EAAO,MAAAC,EAAO,mBAAAC,CAAA,EAAsCC,EAAAA,iBAAA,EAEpE,CACJ,MAAAC,EACA,iBAAAC,EACA,sBAAAC,EACA,gBAAAC,EACA,aAAAC,CAAA,EAEAC,EAAAA,eAAetB,GAAQc,GAAA,YAAAA,EAAO,eAAgB,CAAA,EAAIC,CAAkB,EAIhEQ,EAAkCC,EAAAA,QACtC,IAAMxB,EAAO,OAAQyB,GAAyB,CAACL,EAAgB,IAAIK,EAAK,EAAE,CAAC,EAC3E,CAACzB,EAAQoB,CAAe,CAAA,EAG1BM,EAAAA,UAAU,IAAM,CACV,CAACb,GAAS,CAACC,GAIfD,EAAM,UACJc,wBAAsB,CACpB,OAAQJ,EACR,YAAAtB,EACA,KAAAE,EACA,MAAAC,EACA,MAAAU,EACA,YAAAT,EACA,gBAAAC,EACA,qBAAsBY,EACtB,eAAAX,CAAA,CACD,EACD,CAAE,SAAU,EAAA,CAAK,CAErB,EAAG,CACDM,EACAC,EACAS,EACAtB,EACAE,EACAC,EACAC,EACAC,EACAY,EACAX,CAAA,CACD,EAED,MAAMqB,EAA2B1B,IAAW,QAAUF,EAAO,OAAS,EAEtE,OACE6B,EAAAA,KAAC,OAAI,UAAWC,EAAAA,KAAK,oBAAqBpB,CAAS,EAAI,GAAGC,EACvD,SAAA,CAAAiB,GACCG,EAAAA,IAACC,EAAAA,YAAA,CACC,MAAAf,EACA,SAAUI,EACV,cAAeb,EACf,sBAAAW,EACA,OAAQV,CAAA,CAAA,EAGZsB,EAAAA,IAAC,MAAA,CAAI,IAAKnB,EAAc,UAAU,2BAAA,CAA4B,CAAA,EAChE,CAEJ"}
@@ -1,61 +1,79 @@
1
- import { jsx as S } from "react/jsx-runtime";
2
- import { clsx as _ } from "../../../../vendor/clsx/dist/clsx.js";
3
- import { useEffect as C } from "react";
4
- import { useChartInstance as E } from "../useChartInstance.js";
5
- import { buildTimeSeriesOption as N } from "./time-series-option.js";
1
+ import { jsxs as E, jsx as d } from "react/jsx-runtime";
2
+ import { clsx as M } from "../../../../vendor/clsx/dist/clsx.js";
3
+ import { useMemo as P, useEffect as x } from "react";
4
+ import { useChartInstance as L } from "../useChartInstance.js";
5
+ import { ChartLegend as Y } from "../ChartLegend/ChartLegend.js";
6
+ import { useChartLegend as b } from "../ChartLegend/use-chart-legend.js";
7
+ import { buildTimeSeriesOption as j } from "./time-series-option.js";
6
8
  /* empty css */
7
- const P = {}, d = {};
8
- function j({
9
- series: o,
9
+ const B = {}, k = {};
10
+ function J({
11
+ series: r,
10
12
  displayType: i = "line",
11
- legend: n = "inline",
12
- line: c = d,
13
- yAxis: f = P,
14
- showSymbols: s = !1,
15
- showValueLabels: m = !1,
16
- valueFormatter: a,
17
- className: l,
18
- ...u
13
+ legend: g = "inline",
14
+ line: s = k,
15
+ yAxis: t = B,
16
+ showSymbols: n = !1,
17
+ showValueLabels: c = !1,
18
+ valueFormatter: m,
19
+ onSeriesColorChange: S,
20
+ legendLabels: h,
21
+ className: p,
22
+ ...C
19
23
  }) {
20
- const { containerRef: I, chart: r, theme: t, resolveSeriesColor: p } = E();
21
- return C(() => {
22
- if (!r || !t) return;
23
- const O = {};
24
- for (const e of o) {
25
- if (!e.colorToken) continue;
26
- const T = p(e.colorToken);
27
- T && (O[e.id] = T);
28
- }
29
- r.setOption(
30
- N({
31
- series: o,
24
+ const { containerRef: I, chart: o, theme: e, resolveSeriesColor: u } = L(), {
25
+ items: O,
26
+ colorsBySeriesId: l,
27
+ colorTokensBySeriesId: T,
28
+ hiddenSeriesIds: f,
29
+ toggleSeries: _
30
+ } = b(r, (e == null ? void 0 : e.seriesColors) ?? [], u), a = P(
31
+ () => r.filter((N) => !f.has(N.id)),
32
+ [r, f]
33
+ );
34
+ x(() => {
35
+ !o || !e || o.setOption(
36
+ j({
37
+ series: a,
32
38
  displayType: i,
33
- legend: n,
34
- line: c,
35
- yAxis: f,
36
- theme: t,
37
- showSymbols: s,
38
- showValueLabels: m,
39
- seriesColorOverrides: O,
40
- valueFormatter: a
39
+ line: s,
40
+ yAxis: t,
41
+ theme: e,
42
+ showSymbols: n,
43
+ showValueLabels: c,
44
+ seriesColorOverrides: l,
45
+ valueFormatter: m
41
46
  }),
42
47
  { notMerge: !0 }
43
48
  );
44
49
  }, [
45
- r,
46
- t,
47
- p,
48
50
  o,
51
+ e,
52
+ a,
49
53
  i,
54
+ s,
55
+ t,
50
56
  n,
51
57
  c,
52
- f,
53
- s,
54
- m,
55
- a
56
- ]), /* @__PURE__ */ S("div", { ref: I, className: _("time-series-chart", l), ...u });
58
+ l,
59
+ m
60
+ ]);
61
+ const v = g !== "none" && r.length > 0;
62
+ return /* @__PURE__ */ E("div", { className: M("time-series-chart", p), ...C, children: [
63
+ v && /* @__PURE__ */ d(
64
+ Y,
65
+ {
66
+ items: O,
67
+ onToggle: _,
68
+ onColorChange: S,
69
+ colorTokensBySeriesId: T,
70
+ labels: h
71
+ }
72
+ ),
73
+ /* @__PURE__ */ d("div", { ref: I, className: "time-series-chart__canvas" })
74
+ ] });
57
75
  }
58
76
  export {
59
- j as TimeSeriesChart
77
+ J as TimeSeriesChart
60
78
  };
61
79
  //# sourceMappingURL=TimeSeriesChart.js.map