@rowsncolumns/charts 28.1.13 → 28.1.15

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 (99) hide show
  1. package/dist/cjs/basic-chart/basic-chart.d.ts.map +1 -1
  2. package/dist/cjs/basic-chart/basic-chart.js +308 -270
  3. package/dist/cjs/components/editors/chart-editor-capabilities.d.ts +48 -0
  4. package/dist/cjs/components/editors/chart-editor-capabilities.d.ts.map +1 -0
  5. package/dist/cjs/components/editors/chart-editor-capabilities.js +62 -0
  6. package/dist/cjs/components/editors/chart-editor.d.ts.map +1 -1
  7. package/dist/cjs/components/editors/chart-editor.js +200 -534
  8. package/dist/cjs/components/editors/fields/axis-options-fields.d.ts +16 -0
  9. package/dist/cjs/components/editors/fields/axis-options-fields.d.ts.map +1 -0
  10. package/dist/cjs/components/editors/fields/axis-options-fields.js +31 -0
  11. package/dist/cjs/components/editors/fields/chart-type-options.d.ts +25 -0
  12. package/dist/cjs/components/editors/fields/chart-type-options.d.ts.map +1 -0
  13. package/dist/cjs/components/editors/fields/chart-type-options.js +170 -0
  14. package/dist/cjs/components/editors/fields/data-labels-fields.d.ts +15 -0
  15. package/dist/cjs/components/editors/fields/data-labels-fields.d.ts.map +1 -0
  16. package/dist/cjs/components/editors/fields/data-labels-fields.js +57 -0
  17. package/dist/cjs/components/editors/fields/primitives.d.ts +54 -0
  18. package/dist/cjs/components/editors/fields/primitives.d.ts.map +1 -0
  19. package/dist/cjs/components/editors/fields/primitives.js +52 -0
  20. package/dist/cjs/components/editors/fields/series-format-fields.d.ts +17 -0
  21. package/dist/cjs/components/editors/fields/series-format-fields.d.ts.map +1 -0
  22. package/dist/cjs/components/editors/fields/series-format-fields.js +165 -0
  23. package/dist/cjs/components/editors/fields/series-name-field.d.ts +16 -0
  24. package/dist/cjs/components/editors/fields/series-name-field.d.ts.map +1 -0
  25. package/dist/cjs/components/editors/fields/series-name-field.js +36 -0
  26. package/dist/cjs/components/editors/fields/text-format-fields.d.ts +20 -0
  27. package/dist/cjs/components/editors/fields/text-format-fields.d.ts.map +1 -0
  28. package/dist/cjs/components/editors/fields/text-format-fields.js +46 -0
  29. package/dist/cjs/config.d.ts.map +1 -1
  30. package/dist/cjs/config.js +3 -0
  31. package/dist/cjs/interface/create-chart.d.ts +3 -2
  32. package/dist/cjs/interface/create-chart.d.ts.map +1 -1
  33. package/dist/cjs/interface/create-chart.js +7 -0
  34. package/dist/cjs/plotly/basic-chart/basic-chart.d.ts.map +1 -1
  35. package/dist/cjs/plotly/basic-chart/basic-chart.js +255 -218
  36. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  37. package/dist/cjs/utils/chart-orientation.d.ts.map +1 -1
  38. package/dist/cjs/utils/chart-orientation.js +24 -12
  39. package/dist/cjs/utils/chart-spec-utils.d.ts.map +1 -1
  40. package/dist/cjs/utils/chart-spec-utils.js +120 -21
  41. package/dist/cjs/utils/echarts-overlays.d.ts +2 -0
  42. package/dist/cjs/utils/echarts-overlays.d.ts.map +1 -1
  43. package/dist/cjs/utils/echarts-overlays.js +25 -12
  44. package/dist/cjs/utils/series-name.d.ts +12 -0
  45. package/dist/cjs/utils/series-name.d.ts.map +1 -0
  46. package/dist/cjs/utils/series-name.js +26 -0
  47. package/dist/cjs/utils/trendline.d.ts +9 -0
  48. package/dist/cjs/utils/trendline.d.ts.map +1 -1
  49. package/dist/cjs/utils/trendline.js +16 -1
  50. package/dist/esm/basic-chart/basic-chart.d.ts.map +1 -1
  51. package/dist/esm/basic-chart/basic-chart.js +73 -37
  52. package/dist/esm/components/editors/chart-editor-capabilities.d.ts +48 -0
  53. package/dist/esm/components/editors/chart-editor-capabilities.d.ts.map +1 -0
  54. package/dist/esm/components/editors/chart-editor-capabilities.js +58 -0
  55. package/dist/esm/components/editors/chart-editor.d.ts.map +1 -1
  56. package/dist/esm/components/editors/chart-editor.js +166 -448
  57. package/dist/esm/components/editors/fields/axis-options-fields.d.ts +16 -0
  58. package/dist/esm/components/editors/fields/axis-options-fields.d.ts.map +1 -0
  59. package/dist/esm/components/editors/fields/axis-options-fields.js +22 -0
  60. package/dist/esm/components/editors/fields/chart-type-options.d.ts +25 -0
  61. package/dist/esm/components/editors/fields/chart-type-options.d.ts.map +1 -0
  62. package/dist/esm/components/editors/fields/chart-type-options.js +151 -0
  63. package/dist/esm/components/editors/fields/data-labels-fields.d.ts +15 -0
  64. package/dist/esm/components/editors/fields/data-labels-fields.d.ts.map +1 -0
  65. package/dist/esm/components/editors/fields/data-labels-fields.js +47 -0
  66. package/dist/esm/components/editors/fields/primitives.d.ts +54 -0
  67. package/dist/esm/components/editors/fields/primitives.d.ts.map +1 -0
  68. package/dist/esm/components/editors/fields/primitives.js +26 -0
  69. package/dist/esm/components/editors/fields/series-format-fields.d.ts +17 -0
  70. package/dist/esm/components/editors/fields/series-format-fields.d.ts.map +1 -0
  71. package/dist/esm/components/editors/fields/series-format-fields.js +143 -0
  72. package/dist/esm/components/editors/fields/series-name-field.d.ts +16 -0
  73. package/dist/esm/components/editors/fields/series-name-field.d.ts.map +1 -0
  74. package/dist/esm/components/editors/fields/series-name-field.js +31 -0
  75. package/dist/esm/components/editors/fields/text-format-fields.d.ts +20 -0
  76. package/dist/esm/components/editors/fields/text-format-fields.d.ts.map +1 -0
  77. package/dist/esm/components/editors/fields/text-format-fields.js +34 -0
  78. package/dist/esm/config.d.ts.map +1 -1
  79. package/dist/esm/config.js +3 -0
  80. package/dist/esm/interface/create-chart.d.ts +3 -2
  81. package/dist/esm/interface/create-chart.d.ts.map +1 -1
  82. package/dist/esm/interface/create-chart.js +8 -1
  83. package/dist/esm/plotly/basic-chart/basic-chart.d.ts.map +1 -1
  84. package/dist/esm/plotly/basic-chart/basic-chart.js +52 -30
  85. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  86. package/dist/esm/utils/chart-orientation.d.ts.map +1 -1
  87. package/dist/esm/utils/chart-orientation.js +20 -0
  88. package/dist/esm/utils/chart-spec-utils.d.ts.map +1 -1
  89. package/dist/esm/utils/chart-spec-utils.js +95 -8
  90. package/dist/esm/utils/echarts-overlays.d.ts +2 -0
  91. package/dist/esm/utils/echarts-overlays.d.ts.map +1 -1
  92. package/dist/esm/utils/echarts-overlays.js +15 -1
  93. package/dist/esm/utils/series-name.d.ts +12 -0
  94. package/dist/esm/utils/series-name.d.ts.map +1 -0
  95. package/dist/esm/utils/series-name.js +24 -0
  96. package/dist/esm/utils/trendline.d.ts +9 -0
  97. package/dist/esm/utils/trendline.d.ts.map +1 -1
  98. package/dist/esm/utils/trendline.js +14 -0
  99. package/package.json +3 -3
@@ -0,0 +1,31 @@
1
+ import { Input, Stack } from "@rowsncolumns/ui";
2
+ import React from "react";
3
+ import { ChartRangeInput } from "../chart-range-input";
4
+ /**
5
+ * Excel's "Series name": either text, or a link to a header cell
6
+ * (`dataLabelSource`, #1100). A linked name shows the cell's current text
7
+ * and the cell it comes from; typing a name replaces the link with the
8
+ * literal, picking a cell links it.
9
+ */
10
+ export const SeriesNameField = ({ sheetId, series, getFormattedValue, onChange, }) => {
11
+ const source = series.dataLabelSource ?? undefined;
12
+ const linkedText = source
13
+ ? getFormattedValue?.(source.sheetId, source.startRowIndex, source.startColumnIndex)
14
+ : undefined;
15
+ return (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
16
+ React.createElement("label", { className: "font-system text-sm" }, "Name"),
17
+ React.createElement(Input, { value: (source ? linkedText ?? series.dataLabel : series.dataLabel) ?? "", type: "text", onChange: (e) => onChange({ dataLabel: e.target.value, dataLabelSource: undefined }), className: "text-xs", placeholder: "Series name", "aria-label": "Series name" }),
18
+ React.createElement("label", { className: "font-system text-xs text-rnc-muted-foreground" }, source ? "Linked to cell" : "Or link to a cell"),
19
+ React.createElement(ChartRangeInput, { sheetId: sheetId, range: source, onChangeRange: (range) => {
20
+ const cell = {
21
+ ...range,
22
+ endRowIndex: range.startRowIndex,
23
+ endColumnIndex: range.startColumnIndex,
24
+ };
25
+ onChange({
26
+ dataLabel: getFormattedValue?.(cell.sheetId, cell.startRowIndex, cell.startColumnIndex) ??
27
+ series.dataLabel,
28
+ dataLabelSource: cell,
29
+ });
30
+ }, placeholder: "Header cell", className: "mb-0" })));
31
+ };
@@ -0,0 +1,20 @@
1
+ import type { ChartTextFormat } from "@rowsncolumns/spreadsheet";
2
+ import React from "react";
3
+ /**
4
+ * Font family / size / colour / bold / italic / underline / strikethrough
5
+ * of one text element — the chart title, the legend, an axis or the data
6
+ * labels (`ChartTextFormat`, OOXML `<c:txPr>`).
7
+ */
8
+ export declare const TextFormatFields: ({ label, value, onChange, collapsible, ariaLabels, }: {
9
+ label: string;
10
+ value: ChartTextFormat | null | undefined;
11
+ onChange(next: ChartTextFormat | undefined): void;
12
+ /** Mount the fields behind a "Font…" toggle (secondary text elements). */
13
+ collapsible?: boolean;
14
+ ariaLabels?: {
15
+ family?: string;
16
+ size?: string;
17
+ color?: string;
18
+ };
19
+ }) => React.JSX.Element;
20
+ //# sourceMappingURL=text-format-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-format-fields.d.ts","sourceRoot":"","sources":["../../../../../components/editors/fields/text-format-fields.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,sDAM9B;IACD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,SAAS,GAAG,IAAI,CAAC;IAClD,0EAA0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjE,sBA6EA,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { Input } from "@rowsncolumns/ui";
2
+ import React, { useState } from "react";
3
+ import { CheckboxField, COLOR_CLASS } from "./primitives";
4
+ /**
5
+ * Font family / size / colour / bold / italic / underline / strikethrough
6
+ * of one text element — the chart title, the legend, an axis or the data
7
+ * labels (`ChartTextFormat`, OOXML `<c:txPr>`).
8
+ */
9
+ export const TextFormatFields = ({ label, value, onChange, collapsible = false, ariaLabels, }) => {
10
+ const [open, setOpen] = useState(!collapsible);
11
+ if (collapsible && !open) {
12
+ return (React.createElement("div", { className: "pb-2" },
13
+ React.createElement("button", { type: "button", className: "font-system text-xs text-rnc-muted-foreground underline", onClick: () => setOpen(true) },
14
+ label,
15
+ "\u2026")));
16
+ }
17
+ const set = (patch) => {
18
+ const next = { ...(value ?? {}), ...patch };
19
+ const entries = Object.entries(next).filter(([, v]) => v !== undefined && v !== null && v !== false && v !== "");
20
+ onChange(entries.length ? Object.fromEntries(entries) : undefined);
21
+ };
22
+ return (React.createElement("div", { className: "flex flex-col gap-1 pb-2" },
23
+ React.createElement("label", { className: "font-system text-sm" }, label),
24
+ React.createElement("div", { className: "flex items-center gap-1 flex-wrap" },
25
+ React.createElement(Input, { value: value?.fontFamily ?? "", type: "text", onChange: (e) => set({ fontFamily: e.target.value || undefined }), className: "text-xs w-32", placeholder: "Font family", "aria-label": ariaLabels?.family ?? `${label} family` }),
26
+ React.createElement(Input, { value: value?.fontSize ?? "", type: "number", min: 1, onChange: (e) => set({
27
+ fontSize: e.target.value === "" ? undefined : Number(e.target.value),
28
+ }), className: "text-xs w-16", placeholder: "Size", "aria-label": ariaLabels?.size ?? `${label} size` }),
29
+ React.createElement("input", { type: "color", value: value?.color ?? "#000000", onChange: (e) => set({ color: e.target.value }), className: COLOR_CLASS, "aria-label": ariaLabels?.color ?? `${label} color` }),
30
+ React.createElement(CheckboxField, { label: "Bold", checked: Boolean(value?.bold), onChange: (bold) => set({ bold }) }),
31
+ React.createElement(CheckboxField, { label: "Italic", checked: Boolean(value?.italic), onChange: (italic) => set({ italic }) }),
32
+ React.createElement(CheckboxField, { label: "Underline", checked: Boolean(value?.underline), onChange: (underline) => set({ underline }) }),
33
+ React.createElement(CheckboxField, { label: "Strikethrough", checked: Boolean(value?.strikethrough), onChange: (strikethrough) => set({ strikethrough }) }))));
34
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAqR3D,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAgB1E,CAAC;AAYJ;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,OAAO,CAAC,SAAS,CAAC,KAAG,OAQzD,CAAC;AAuBF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,OAAO,CAAC,SAAS,CAAC,KAAG,MA4B9D,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAwR3D,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAgB1E,CAAC;AAYJ;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,OAAO,CAAC,SAAS,CAAC,KAAG,OAQzD,CAAC;AAuBF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,OAAO,CAAC,SAAS,CAAC,KAAG,MA4B9D,CAAC"}
@@ -232,6 +232,9 @@ const HIERARCHY_CHART_TYPES = [
232
232
  ];
233
233
  const STATISTICAL_CHART_TYPES = [
234
234
  ["Histogram", { chartType: "histogram" }],
235
+ // Excel's Pareto: a histogram with its bins sorted descending plus a
236
+ // cumulative-% line (sourceChartType PARETO, the import token).
237
+ ["Pareto", { chartType: "histogram", sourceChartType: "PARETO" }],
235
238
  ["Box & Whisker", { chartType: "boxplot" }],
236
239
  ];
237
240
  const FLOW_CHART_TYPES = [
@@ -1,5 +1,6 @@
1
- import { CellInterface, SelectionArea } from "@rowsncolumns/grid";
2
- import { type CellData, SelectionAttributes, EmbeddedChart } from "@rowsncolumns/spreadsheet";
1
+ import type { CellInterface, SelectionArea } from "@rowsncolumns/grid";
2
+ import type { EmbeddedChart, SelectionAttributes } from "@rowsncolumns/spreadsheet";
3
+ import { type CellData } from "@rowsncolumns/spreadsheet";
3
4
  import type { UseOnCreateChartProps } from "../hooks/use-on-create-chart";
4
5
  /**
5
6
  * Ensures endIndex is at least minValue.
@@ -1 +1 @@
1
- {"version":3,"file":"create-chart.d.ts","sourceRoot":"","sources":["../../../interface/create-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EACL,KAAK,QAAQ,EACb,mBAAmB,EACnB,aAAa,EAKd,MAAM,2BAA2B,CAAC;AAInC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAiB1E;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,GAAG,SAAS,EAC5B,UAAU,MAAM,KACf,MAAkF,CAAC;AAEtF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,QAAQ,EAAE,8FAM7C,qBAAqB,CAAC,CAAC,CAAC,MAEvB,SAAS,MAAM,EACf,YAAY,aAAa,EACzB,YAAY,aAAa,CAAC,mBAAmB,CAAC,EAAE,EAChD,YAAY,aAAa,kBAuH5B,CAAC"}
1
+ {"version":3,"file":"create-chart.d.ts","sourceRoot":"","sources":["../../../interface/create-chart.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,KAAK,EAIV,aAAa,EACb,mBAAmB,EACR,MAAM,2BAA2B,CAAC;AAC/C,OAAO,EACL,KAAK,QAAQ,EACd,MAAM,2BAA2B,CAAC;AAInC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAiB1E;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,GAAG,SAAS,EAC5B,UAAU,MAAM,KACf,MAAkF,CAAC;AAEtF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,QAAQ,EAAE,8FAM7C,qBAAqB,CAAC,CAAC,CAAC,MAEvB,SAAS,MAAM,EACf,YAAY,aAAa,EACzB,YAAY,aAAa,CAAC,mBAAmB,CAAC,EAAE,EAChD,YAAY,aAAa,kBA8H5B,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { isNumber, selectionBoundsFromCells, uuid } from "@rowsncolumns/utils";
2
2
  import { enablePatches, produceWithPatches } from "immer";
3
3
  import { deriveChartSeriesFromRange, pickSeriesOrientationForRange, } from "../utils/chart-orientation";
4
- import { isBasicChartSpec, getDefaultChartTypeSpec, } from "../utils/chart-spec-utils";
4
+ import { getDefaultChartTypeSpec, isBasicChartSpec, } from "../utils/chart-spec-utils";
5
5
  // For external interface
6
6
  enablePatches();
7
7
  /**
@@ -30,6 +30,13 @@ export const createChart = ({ onChangeCharts, getFormattedValue, getEffectiveVal
30
30
  ? [
31
31
  {
32
32
  dataLabel: getFormattedValue(sheetId, lastSelection.range.startRowIndex, lastSelection.range.startColumnIndex) ?? "",
33
+ dataLabelSource: {
34
+ sheetId,
35
+ startRowIndex: lastSelection.range.startRowIndex,
36
+ endRowIndex: lastSelection.range.startRowIndex,
37
+ startColumnIndex: lastSelection.range.startColumnIndex,
38
+ endColumnIndex: lastSelection.range.startColumnIndex,
39
+ },
33
40
  sources: categoryAxis,
34
41
  aggregateType: "COUNT",
35
42
  },
@@ -1 +1 @@
1
- {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA8ZxD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAmGnD,eAAO,MAAM,UAAU,GAAI,gPAkBxB,eAAe,sBAkqFjB,CAAC"}
1
+ {"version":3,"file":"basic-chart.d.ts","sourceRoot":"","sources":["../../../../plotly/basic-chart/basic-chart.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA+ZxD,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAmGnD,eAAO,MAAM,UAAU,GAAI,gPAkBxB,eAAe,sBA2rFjB,CAAC"}
@@ -7,29 +7,30 @@ import React, { useCallback, useMemo, useRef, useState } from "react";
7
7
  import { aggregateSeriesByDomain, getDomainValuesForAxis, sanitizeDomainValues, shouldAggregateSeries, } from "../../utils/aggregation";
8
8
  import { formatAxisValue, numberFormatToPlotlyTicks, plotlySeparators, resolveSeriesNumberFormats, resolveValueAxisNumberFormat, valueAxisNameGap, } from "../../utils/axis-number-format";
9
9
  import { createBubbleSizeScale, prepareBubbleSeriesData, toLabelString, } from "../../utils/bubble";
10
- import { canSwitchRowColumn, cellLabelGetterFromRangeReader, switchRowColumn, } from "../../utils/chart-orientation";
10
+ import { plotlyMulticategoryX, resolveCategoryLevels, } from "../../utils/category-levels";
11
11
  import { dataUrlToBlob } from "../../utils/chart-image";
12
- import { getChartPalette } from "../../utils/chart-styles";
12
+ import { canSwitchRowColumn, cellLabelGetterFromRangeReader, switchRowColumn, } from "../../utils/chart-orientation";
13
13
  import { coerceCalculatedLabel } from "../../utils/chart-spec-utils";
14
+ import { getChartPalette } from "../../utils/chart-styles";
15
+ import { clampDoughnutHole, doughnutRings } from "../../utils/doughnut";
14
16
  import { applyEmptyCellsPolicy, connectsAcrossEmptyCells, isLineLikeChartType, isolatedPointIndexes, } from "../../utils/empty-cells";
15
17
  import { computeErrorBars, resolveCustomErrorBarValues, } from "../../utils/error-bars";
16
- import { plotlyMulticategoryX, resolveCategoryLevels, } from "../../utils/category-levels";
17
18
  import { gradientToPlotly } from "../../utils/gradient";
19
+ import { extractHierarchyRows, getHierarchyHeaderTitle, hierarchyNodeColors, toPlotlyHierarchy, } from "../../utils/hierarchy";
20
+ import { aggregateByCategory, binHistogram, computePareto, hasExcelBinning, isParetoSpec, } from "../../utils/histogram";
18
21
  import { BAND_GAP, legendLabelsFrom, measureTextWidth, reservePlotlyLegendBand, } from "../../utils/legend-layout";
19
- import { clampDoughnutHole, doughnutRings } from "../../utils/doughnut";
22
+ import { clampSecondPieSize, isOfPieChartSpec, otherSliceHalfAngle, resolveOfPieType, splitOfPie, } from "../../utils/of-pie";
20
23
  import { dataLabelFormatter, resolveSeriesDataLabels, } from "../../utils/overrides";
21
- import { plotlyTitleText } from "../../utils/plotly-title";
22
24
  import { explosionToPlotlyPull, resolveExplosion, } from "../../utils/pie-explosion";
23
25
  import { resolvePlotlyClickSelection, wasDragged, } from "../../utils/plotly-click";
24
26
  import { buildPlotlySurfaceTrace } from "../../utils/plotly-surface";
25
- import { normalize3DSourceType, } from "../../utils/three-d";
26
- import { extractHierarchyRows, getHierarchyHeaderTitle, hierarchyNodeColors, toPlotlyHierarchy, } from "../../utils/hierarchy";
27
- import { aggregateByCategory, binHistogram, computePareto, hasExcelBinning, isParetoSpec, } from "../../utils/histogram";
28
- import { clampSecondPieSize, isOfPieChartSpec, otherSliceHalfAngle, resolveOfPieType, splitOfPie, } from "../../utils/of-pie";
27
+ import { plotlyTitleText } from "../../utils/plotly-title";
29
28
  import { buildRadarIndicators } from "../../utils/radar";
30
29
  import { buildSequentialColorRamp, isRegionMapSpec, resolveGeoScope, WORLD_GEO_SCOPE, } from "../../utils/region-map";
30
+ import { linkedSeriesName } from "../../utils/series-name";
31
31
  import { assignStockRoles, toLineSeries, toVolumeSeries, } from "../../utils/stock";
32
- import { computeTrendline } from "../../utils/trendline";
32
+ import { normalize3DSourceType, } from "../../utils/three-d";
33
+ import { computeTrendline, trendlineLabel } from "../../utils/trendline";
33
34
  import { Plot, Plotly } from "../plot";
34
35
  import { chartTypeToPlotlyType, getPlotlyTraceStyle, mapMarkerSymbolToPlotly, showXAxis, } from "./helpers";
35
36
  const BASIC_CHART_TYPES = new Set([
@@ -503,8 +504,9 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
503
504
  const seriesInputs = [];
504
505
  for (let i = 0; i < spec.series.length; i++) {
505
506
  const seriesEntry = spec.series[i];
506
- let resolvedLabel = seriesEntry.dataLabel ?? "";
507
- if (resolvedLabel && isAFormula(resolvedLabel)) {
507
+ const linkedLabel = linkedSeriesName(seriesEntry, getDomainValuesFromRange);
508
+ let resolvedLabel = linkedLabel ?? seriesEntry.dataLabel ?? "";
509
+ if (linkedLabel === undefined && resolvedLabel && isAFormula(resolvedLabel)) {
508
510
  resolvedLabel = coerceCalculatedLabel(await onRequestCalculate(resolvedLabel, chart.position.sheetId ?? sheetId, chart.position.overlayPosition.anchorCell.rowIndex, chart.position.overlayPosition.anchorCell.columnIndex));
509
511
  }
510
512
  // Per-series X, with fallback to the first domain so single-X
@@ -693,9 +695,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
693
695
  continue;
694
696
  const tlName = tl.name ??
695
697
  `${entry.name ? entry.name + " " : ""}${tl.type ?? "linear"} trend`;
698
+ const label = trendlineLabel(tl, result);
696
699
  traces.push({
697
700
  type: "scatter",
698
- mode: "lines",
701
+ mode: label ? "lines+text" : "lines",
699
702
  name: tlName,
700
703
  x: result.points.map((p) => hasStringX
701
704
  ? categories[Math.round(p.x)] ?? p.x
@@ -703,6 +706,14 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
703
706
  y: result.points.map((p) => p.y),
704
707
  line: { color: tl.color ?? seriesColor, dash: "dash", width: 2 },
705
708
  hoverinfo: "skip",
709
+ ...(label
710
+ ? {
711
+ // Excel prints the equation / R² at the line's end.
712
+ text: result.points.map((_, i) => i === result.points.length - 1 ? label.replace("\n", "<br>") : ""),
713
+ textposition: "top left",
714
+ textfont: { color: tl.color ?? seriesColor, size: 11 },
715
+ }
716
+ : {}),
706
717
  ...onSecondary,
707
718
  });
708
719
  }
@@ -1006,9 +1017,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1006
1017
  const categories = flattenChartDataValues(spec.domains, getDomainValuesFromRange, spec.hiddenDimensionStrategy, false).map((v) => String(v ?? ""));
1007
1018
  const surfaceSeriesInputs = [];
1008
1019
  for (const seriesEntry of spec.series ?? []) {
1009
- const dataLabel = !isNil(seriesEntry.dataLabel) && isAFormula(seriesEntry.dataLabel)
1010
- ? coerceCalculatedLabel(await onRequestCalculate(seriesEntry.dataLabel, position.sheetId ?? sheetId, position.overlayPosition.anchorCell.rowIndex, position.overlayPosition.anchorCell.columnIndex))
1011
- : seriesEntry.dataLabel ?? "";
1020
+ const dataLabel = linkedSeriesName(seriesEntry, getDomainValuesFromRange) ??
1021
+ (!isNil(seriesEntry.dataLabel) && isAFormula(seriesEntry.dataLabel)
1022
+ ? coerceCalculatedLabel(await onRequestCalculate(seriesEntry.dataLabel, position.sheetId ?? sheetId, position.overlayPosition.anchorCell.rowIndex, position.overlayPosition.anchorCell.columnIndex))
1023
+ : seriesEntry.dataLabel ?? "");
1012
1024
  const values = flattenChartDataValues([seriesEntry], getSeriesValuesFromRange, spec.hiddenDimensionStrategy).map((v) => (typeof v === "number" ? v : Number(v)));
1013
1025
  surfaceSeriesInputs.push({ name: dataLabel, values });
1014
1026
  }
@@ -1068,9 +1080,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1068
1080
  const radarTraces = [];
1069
1081
  const radarInputs = [];
1070
1082
  for (const seriesEntry of spec.series ?? []) {
1071
- const label = seriesEntry.dataLabel && !isAFormula(seriesEntry.dataLabel)
1072
- ? seriesEntry.dataLabel
1073
- : "";
1083
+ const label = linkedSeriesName(seriesEntry, getDomainValuesFromRange) ??
1084
+ (seriesEntry.dataLabel && !isAFormula(seriesEntry.dataLabel)
1085
+ ? seriesEntry.dataLabel
1086
+ : "");
1074
1087
  const values = flattenChartDataValues([seriesEntry], getSeriesValuesFromRange, spec.hiddenDimensionStrategy).map((v) => (typeof v === "number" ? v : Number(v)));
1075
1088
  radarInputs.push({ name: label, values });
1076
1089
  }
@@ -1579,9 +1592,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1579
1592
  const categories = categoriesFor(series);
1580
1593
  const xs = result.points.map((p) => p.x >= 0 && p.x < categories.length ? categories[p.x] : p.x);
1581
1594
  const ys = result.points.map((p) => p.y);
1595
+ const label = trendlineLabel(tl, result);
1582
1596
  const overlay = {
1583
1597
  type: "scatter",
1584
- mode: "lines",
1598
+ mode: label ? "lines+text" : "lines",
1585
1599
  name: tlName,
1586
1600
  line: {
1587
1601
  color: tl.color ?? seriesColor,
@@ -1589,6 +1603,14 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1589
1603
  width: 2,
1590
1604
  },
1591
1605
  hoverinfo: "skip",
1606
+ ...(label
1607
+ ? {
1608
+ // Excel prints the equation / R² at the line's end.
1609
+ text: result.points.map((_, i) => i === result.points.length - 1 ? label.replace("\n", "<br>") : ""),
1610
+ textposition: "top left",
1611
+ textfont: { color: tl.color ?? seriesColor, size: 11 },
1612
+ }
1613
+ : {}),
1592
1614
  ...(series.useSecondaryAxis
1593
1615
  ? { [valueAxisKey]: secondaryValueAxisRef }
1594
1616
  : {}),
@@ -1613,9 +1635,10 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1613
1635
  let seriesIndex = 0;
1614
1636
  for (const series of spec.series ?? []) {
1615
1637
  const currentSeriesIndex = seriesIndex++;
1616
- const dataLabel = !isNil(series.dataLabel) && isAFormula(series.dataLabel)
1617
- ? coerceCalculatedLabel(await onRequestCalculate(series.dataLabel, position.sheetId ?? sheetId, position.overlayPosition.anchorCell.rowIndex, position.overlayPosition.anchorCell.columnIndex))
1618
- : series.dataLabel ?? "";
1638
+ const dataLabel = linkedSeriesName(series, getDomainValuesFromRange) ??
1639
+ (!isNil(series.dataLabel) && isAFormula(series.dataLabel)
1640
+ ? coerceCalculatedLabel(await onRequestCalculate(series.dataLabel, position.sheetId ?? sheetId, position.overlayPosition.anchorCell.rowIndex, position.overlayPosition.anchorCell.columnIndex))
1641
+ : series.dataLabel ?? "");
1619
1642
  // A series with no ranges draws nothing.
1620
1643
  if (series.sources.length === 0)
1621
1644
  continue;
@@ -1754,10 +1777,11 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1754
1777
  const showMeanLine = spec.showMeanLine === true;
1755
1778
  // A category domain groups the series by its values (one box per
1756
1779
  // category per series, `boxmode: "group"` in the layout); without
1757
- // one each series is a box on its own slot (#1092). Plotly's box
1758
- // trace computes the quartiles (Excel's inclusive / exclusive
1759
- // methods are native), keeps the whiskers at the 1.5×IQR fences
1760
- // and only hides the points when outliers are off.
1780
+ // one every series is a box in a single group labelled "1", side by
1781
+ // side as Excel draws it (#1092, #1099). Plotly's box trace computes
1782
+ // the quartiles (Excel's inclusive / exclusive methods are native),
1783
+ // keeps the whiskers at the 1.5×IQR fences and only hides the
1784
+ // points when outliers are off.
1761
1785
  const boxDomainSource = spec.domains?.[0]?.sources?.[0];
1762
1786
  const boxCategories = boxDomainSource
1763
1787
  ? (getDomainValuesFromRange(boxDomainSource, spec.hiddenDimensionStrategy) ?? []).map((v) => (v === null || v === undefined ? "" : `${v}`.trim()))
@@ -1768,9 +1792,7 @@ export const BasicChart = ({ width, height, chart, theme, isDarkMode, sheetId, r
1768
1792
  type: "box",
1769
1793
  name: dataLabel,
1770
1794
  y: values,
1771
- ...(grouped
1772
- ? { x: values.map((_, i) => boxCategories[i] ?? "") }
1773
- : {}),
1795
+ x: values.map((_, i) => (grouped ? boxCategories[i] ?? "" : "1")),
1774
1796
  ...(quartileMethod ? { quartilemethod: quartileMethod } : {}),
1775
1797
  boxpoints: showInnerPoints ? "all" : showOutliers ? "outliers" : false,
1776
1798
  ...(showInnerPoints ? { jitter: 0, pointpos: 0 } : {}),
@@ -1 +1 @@
1
- {"root":["../../config.ts","../../echarts-gl.d.ts","../../geo-modules.d.ts","../../index.ts","../../plotly-dist.d.ts","../../types.ts","../../vitest.config.ts","../../atoms/editing-chart.atom.ts","../../atoms/pivot-chart.atom.ts","../../basic-chart/basic-chart.tsx","../../basic-chart/helpers.ts","../../basic-chart/index.tsx","../../components/dialogs/chart-editor-dialog.tsx","../../components/dialogs/pivot-chart-dialog.tsx","../../components/editors/chart-editor.tsx","../../components/editors/chart-range-input.tsx","../../hooks/use-chart-editor.ts","../../hooks/use-charts.ts","../../hooks/use-on-create-chart.ts","../../hooks/use-on-delete-chart.ts","../../hooks/use-on-move-chart-to-sheet.ts","../../hooks/use-on-move-chart.ts","../../hooks/use-on-resize-chart.ts","../../hooks/use-on-update-chart.ts","../../interface/create-chart.ts","../../interface/delete-chart.ts","../../interface/move-chart-to-sheet.ts","../../interface/move-chart.ts","../../interface/resize-chart.ts","../../interface/shift-chart-ranges.ts","../../interface/update-chart.ts","../../plotly/plot.ts","../../plotly/basic-chart/basic-chart.tsx","../../plotly/basic-chart/helpers.ts","../../plotly/basic-chart/index.tsx","../../utils/aggregation.ts","../../utils/axis-number-format.ts","../../utils/bar-layout.ts","../../utils/boxplot.ts","../../utils/bubble.ts","../../utils/category-levels.ts","../../utils/chart-image.ts","../../utils/chart-orientation.ts","../../utils/chart-spec-utils.ts","../../utils/chart-styles.ts","../../utils/doughnut.ts","../../utils/echarts-gl-loader.ts","../../utils/echarts-overlays.ts","../../utils/empty-cells.ts","../../utils/error-bars.ts","../../utils/gradient.ts","../../utils/hierarchy.ts","../../utils/histogram.ts","../../utils/legend-layout.ts","../../utils/of-pie.ts","../../utils/overrides.ts","../../utils/pie-explosion.ts","../../utils/plotly-click.ts","../../utils/plotly-surface.ts","../../utils/plotly-title.ts","../../utils/radar.ts","../../utils/region-map-loader.ts","../../utils/region-map.ts","../../utils/series-click.ts","../../utils/stock.ts","../../utils/three-d.ts","../../utils/trendline.ts","../../utils/waterfall.ts","../../utils/webgl.ts"],"version":"5.8.3"}
1
+ {"root":["../../config.ts","../../echarts-gl.d.ts","../../geo-modules.d.ts","../../index.ts","../../plotly-dist.d.ts","../../types.ts","../../vitest.config.ts","../../atoms/editing-chart.atom.ts","../../atoms/pivot-chart.atom.ts","../../basic-chart/basic-chart.tsx","../../basic-chart/helpers.ts","../../basic-chart/index.tsx","../../components/dialogs/chart-editor-dialog.tsx","../../components/dialogs/pivot-chart-dialog.tsx","../../components/editors/chart-editor-capabilities.ts","../../components/editors/chart-editor.tsx","../../components/editors/chart-range-input.tsx","../../components/editors/fields/axis-options-fields.tsx","../../components/editors/fields/chart-type-options.tsx","../../components/editors/fields/data-labels-fields.tsx","../../components/editors/fields/primitives.tsx","../../components/editors/fields/series-format-fields.tsx","../../components/editors/fields/series-name-field.tsx","../../components/editors/fields/text-format-fields.tsx","../../hooks/use-chart-editor.ts","../../hooks/use-charts.ts","../../hooks/use-on-create-chart.ts","../../hooks/use-on-delete-chart.ts","../../hooks/use-on-move-chart-to-sheet.ts","../../hooks/use-on-move-chart.ts","../../hooks/use-on-resize-chart.ts","../../hooks/use-on-update-chart.ts","../../interface/create-chart.ts","../../interface/delete-chart.ts","../../interface/move-chart-to-sheet.ts","../../interface/move-chart.ts","../../interface/resize-chart.ts","../../interface/shift-chart-ranges.ts","../../interface/update-chart.ts","../../plotly/plot.ts","../../plotly/basic-chart/basic-chart.tsx","../../plotly/basic-chart/helpers.ts","../../plotly/basic-chart/index.tsx","../../utils/aggregation.ts","../../utils/axis-number-format.ts","../../utils/bar-layout.ts","../../utils/boxplot.ts","../../utils/bubble.ts","../../utils/category-levels.ts","../../utils/chart-image.ts","../../utils/chart-orientation.ts","../../utils/chart-spec-utils.ts","../../utils/chart-styles.ts","../../utils/doughnut.ts","../../utils/echarts-gl-loader.ts","../../utils/echarts-overlays.ts","../../utils/empty-cells.ts","../../utils/error-bars.ts","../../utils/gradient.ts","../../utils/hierarchy.ts","../../utils/histogram.ts","../../utils/legend-layout.ts","../../utils/of-pie.ts","../../utils/overrides.ts","../../utils/pie-explosion.ts","../../utils/plotly-click.ts","../../utils/plotly-surface.ts","../../utils/plotly-title.ts","../../utils/radar.ts","../../utils/region-map-loader.ts","../../utils/region-map.ts","../../utils/series-click.ts","../../utils/series-name.ts","../../utils/stock.ts","../../utils/three-d.ts","../../utils/trendline.ts","../../utils/waterfall.ts","../../utils/webgl.ts"],"version":"5.8.3"}
@@ -1 +1 @@
1
- {"version":3,"file":"chart-orientation.d.ts","sourceRoot":"","sources":["../../../utils/chart-orientation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EACb,yBAAyB,EACzB,UAAU,EACX,MAAM,2BAA2B,CAAC;AAInC,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAEvC,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAE5E,4EAA4E;AAC5E,MAAM,MAAM,oBAAoB,GAAG,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,KAChB,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAE/B;;;GAGG;AACH,eAAO,MAAM,8BAA8B,GAEvC,WAAW,CACT,KAAK,EAAE,UAAU,EACjB,cAAc,CAAC,EAAE,yBAAyB,GAAG,IAAI,KAC9C,SAAS,OAAO,EAAE,KACtB,oBAaF,CAAC;AAOJ;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,MAAM,SAAS,KAAG,iBAQxD,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,aAAa,iBAAiB,KAC7B,iBAAkE,CAAC;AAEtE;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GACxC,OAAO,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,KACjC,iBAIY,CAAC;AAEhB;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GAAI,4CAIxC;IACD,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;CAC1C,KAAG;IAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAAC,MAAM,EAAE,SAAS,EAAE,CAAA;CA4D9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAClC,MAAM,SAAS,EACf,aAAa,iBAAiB,KAC7B,UAAU,GAAG,SAsCf,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,kBAAkB,GAAI,MAAM,SAAS,KAAG,OAIrC,CAAC;AAEjB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAC1B,MAAM,SAAS,EACf,wBAAuB;IAAE,iBAAiB,CAAC,EAAE,oBAAoB,CAAA;CAAO,KACvE,SAAS,GAAG,SA8Ed,CAAC"}
1
+ {"version":3,"file":"chart-orientation.d.ts","sourceRoot":"","sources":["../../../utils/chart-orientation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EACb,yBAAyB,EACzB,UAAU,EACX,MAAM,2BAA2B,CAAC;AAInC,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAevC,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAE5E,4EAA4E;AAC5E,MAAM,MAAM,oBAAoB,GAAG,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,KAChB,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAE/B;;;GAGG;AACH,eAAO,MAAM,8BAA8B,GAEvC,WAAW,CACT,KAAK,EAAE,UAAU,EACjB,cAAc,CAAC,EAAE,yBAAyB,GAAG,IAAI,KAC9C,SAAS,OAAO,EAAE,KACtB,oBAaF,CAAC;AAOJ;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,MAAM,SAAS,KAAG,iBAQxD,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,aAAa,iBAAiB,KAC7B,iBAAkE,CAAC;AAEtE;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GACxC,OAAO,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,KACjC,iBAIY,CAAC;AAEhB;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GAAI,4CAIxC;IACD,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;CAC1C,KAAG;IAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAAC,MAAM,EAAE,SAAS,EAAE,CAAA;CA8D9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAClC,MAAM,SAAS,EACf,aAAa,iBAAiB,KAC7B,UAAU,GAAG,SAsCf,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,kBAAkB,GAAI,MAAM,SAAS,KAAG,OAIrC,CAAC;AAEjB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAC1B,MAAM,SAAS,EACf,wBAAuB;IAAE,iBAAiB,CAAC,EAAE,oBAAoB,CAAA;CAAO,KACvE,SAAS,GAAG,SAgGd,CAAC"}
@@ -1,4 +1,12 @@
1
1
  import { isBasicChartSpec } from "./chart-spec-utils";
2
+ /** The single-cell range a series name is linked to (its header cell). */
3
+ const cellRange = (sheetId, rowIndex, columnIndex) => ({
4
+ sheetId,
5
+ startRowIndex: rowIndex,
6
+ endRowIndex: rowIndex,
7
+ startColumnIndex: columnIndex,
8
+ endColumnIndex: columnIndex,
9
+ });
2
10
  /**
3
11
  * Adapt a range reader (the renderers' `getDomainValuesFromRange`) into
4
12
  * the single-cell label getter the orientation helpers take.
@@ -68,6 +76,7 @@ export const deriveChartSeriesFromRange = ({ range, orientation, getFormattedVal
68
76
  for (let rowIndex = startRowIndex + 1; rowIndex <= endRowIndex; rowIndex++) {
69
77
  series.push({
70
78
  dataLabel: label(rowIndex, startColumnIndex),
79
+ dataLabelSource: cellRange(sheetId, rowIndex, startColumnIndex),
71
80
  sources: [
72
81
  {
73
82
  sheetId,
@@ -92,6 +101,7 @@ export const deriveChartSeriesFromRange = ({ range, orientation, getFormattedVal
92
101
  for (let columnIndex = startColumnIndex + 1; columnIndex <= endColumnIndex; columnIndex++) {
93
102
  series.push({
94
103
  dataLabel: label(startRowIndex, columnIndex),
104
+ dataLabelSource: cellRange(sheetId, startRowIndex, columnIndex),
95
105
  sources: [
96
106
  {
97
107
  sheetId,
@@ -193,6 +203,11 @@ export const switchRowColumn = (spec, { getFormattedValue } = {}) => {
193
203
  dataLabel: categorySource && getFormattedValue
194
204
  ? getFormattedValue(categorySource.sheetId, categorySource.startRowIndex + offset, categorySource.startColumnIndex) ?? undefined
195
205
  : undefined,
206
+ ...(categorySource
207
+ ? {
208
+ dataLabelSource: cellRange(categorySource.sheetId, categorySource.startRowIndex + offset, categorySource.startColumnIndex),
209
+ }
210
+ : {}),
196
211
  sources: [
197
212
  {
198
213
  sheetId: block.sheetId,
@@ -212,6 +227,11 @@ export const switchRowColumn = (spec, { getFormattedValue } = {}) => {
212
227
  dataLabel: categorySource && getFormattedValue
213
228
  ? getFormattedValue(categorySource.sheetId, categorySource.startRowIndex, categorySource.startColumnIndex + offset) ?? undefined
214
229
  : undefined,
230
+ ...(categorySource
231
+ ? {
232
+ dataLabelSource: cellRange(categorySource.sheetId, categorySource.startRowIndex, categorySource.startColumnIndex + offset),
233
+ }
234
+ : {}),
215
235
  sources: [
216
236
  {
217
237
  sheetId: block.sheetId,
@@ -1 +1 @@
1
- {"version":3,"file":"chart-spec-utils.d.ts","sourceRoot":"","sources":["../../../utils/chart-spec-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,aAAa,EACb,UAAU,EACV,YAAY,EACb,MAAM,2BAA2B,CAAC;AAEnC,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC;AACpD,KAAK,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AACtD,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAEvC,eAAO,MAAM,iBAAiB,6MAe5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,6MAA4C,CAAC;AAE5E,eAAO,MAAM,qBAAqB,6MAGhC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,SAAS,KAAG,aAKvD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,cAAuD,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC;IAC1B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,yEAAyE;IACzE,YAAY,CAAC,EACT,MAAM,GACN,QAAQ,GACR,YAAY,GACZ,cAAc,GACd,QAAQ,GACR,MAAM,GACN,IAAI,CAAC;CACV,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,qBACiB,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,kBACoB,CAAC;AAwC5C;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,WAAW,SAAS,KACnB,OAAO,CAAC,SAAS,CAEnB,CAAC;AAiFF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAChC,UAAU,SAAS,EACnB,QAAQ,SAAS,KAChB,MAAM,EAoBR,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,SAAS,EAAE,KAAG,OAO3D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,SAAS,EAAE,EACrB,WAAW,SAAS,EAAE,KACrB,SAAS,EAKX,CAAC;AA+BF;;;;GAIG;AACH,eAAO,MAAM,cAAc,GACzB,cAAc,SAAS,EACvB,cAAc,OAAO,CAAC,SAAS,CAAC,KAC/B,SA0EF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,SAAS,KAAG,UAAU,EAsB9D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,QAAQ,OAAO,KAAG,MAQvD,CAAC"}
1
+ {"version":3,"file":"chart-spec-utils.d.ts","sourceRoot":"","sources":["../../../utils/chart-spec-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,aAAa,EACb,UAAU,EACV,YAAY,EACb,MAAM,2BAA2B,CAAC;AAEnC,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC;AACpD,KAAK,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AACtD,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAEvC,eAAO,MAAM,iBAAiB,6MAe5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,6MAA4C,CAAC;AAE5E,eAAO,MAAM,qBAAqB,6MAGhC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,SAAS,KAAG,aAKvD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,cAAuD,CAAC;AAE/E,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC;IAC1B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,yEAAyE;IACzE,YAAY,CAAC,EACT,MAAM,GACN,QAAQ,GACR,YAAY,GACZ,cAAc,GACd,QAAQ,GACR,MAAM,GACN,IAAI,CAAC;CACV,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,qBACiB,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,MAAM,SAAS,KACd,IAAI,IAAI,SAAS,GAAG,kBACoB,CAAC;AAwC5C;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,WAAW,SAAS,KACnB,OAAO,CAAC,SAAS,CAEnB,CAAC;AA2HF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAChC,UAAU,SAAS,EACnB,QAAQ,SAAS,KAChB,MAAM,EAoBR,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,SAAS,EAAE,KAAG,OAO3D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,SAAS,EAAE,EACrB,WAAW,SAAS,EAAE,KACrB,SAAS,EAKX,CAAC;AA+BF;;;;GAIG;AACH,eAAO,MAAM,cAAc,GACzB,cAAc,SAAS,EACvB,cAAc,OAAO,CAAC,SAAS,CAAC,KAC/B,SA0FF,CAAC;AAyCF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,SAAS,KAAG,UAAU,EAsB9D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,QAAQ,OAAO,KAAG,MAQvD,CAAC"}
@@ -101,7 +101,25 @@ const BASIC_CHART_TYPE_PROPERTIES = {
101
101
  ],
102
102
  doughnut: ["doughnutHoleSize", "explosion"],
103
103
  waterfall: ["totalIndices"],
104
- boxplot: ["quartileMethod", "showOutliers", "showMeanMarker"],
104
+ boxplot: [
105
+ "quartileMethod",
106
+ "showOutliers",
107
+ "showMeanMarker",
108
+ "showInnerPoints",
109
+ "showMeanLine",
110
+ ],
111
+ histogram: [
112
+ "binCount",
113
+ "binSize",
114
+ "intervalClosed",
115
+ "overflow",
116
+ "underflow",
117
+ "paretoLineColor",
118
+ // A Pareto is a histogram variant (`sourceChartType: "PARETO"`).
119
+ "sourceChartType",
120
+ ],
121
+ radar: ["radarStyle"],
122
+ stock: ["stockVariant"],
105
123
  // Region map (filled map / choropleth) — the geo scope and the
106
124
  // authored-class marker are meaningless on any other chart type.
107
125
  regionMap: ["sourceChartType", "geoScope"],
@@ -127,6 +145,19 @@ const CATEGORY_SPECIFIC_PROPERTIES = {
127
145
  "quartileMethod",
128
146
  "showOutliers",
129
147
  "showMeanMarker",
148
+ "showInnerPoints",
149
+ "showMeanLine",
150
+ "binCount",
151
+ "binSize",
152
+ "intervalClosed",
153
+ "overflow",
154
+ "underflow",
155
+ "paretoLineColor",
156
+ "radarStyle",
157
+ "stockVariant",
158
+ "overlap",
159
+ "gapWidth",
160
+ "categoryLevels",
130
161
  "geoScope",
131
162
  ],
132
163
  bubble: [
@@ -134,14 +165,24 @@ const CATEGORY_SPECIFIC_PROPERTIES = {
134
165
  "bubbleSizes",
135
166
  "useFirstRowAsHeaders",
136
167
  "scatterStyle",
168
+ "bubbleScale",
169
+ "sizeRepresents",
170
+ ],
171
+ hierarchy: [
172
+ "labels",
173
+ "parentLabels",
174
+ "sizeData",
175
+ "useFirstRowAsHeaders",
176
+ "drillDown",
177
+ "parentLabelLayout",
137
178
  ],
138
- hierarchy: ["labels", "parentLabels", "sizeData", "useFirstRowAsHeaders"],
139
179
  };
140
180
  /**
141
- * `sourceChartType` tokens the picker's presets author (3-D classes and
142
- * the of-pie composite). Picking a chart type that carries none of them
143
- * resets the variant, so "Clustered Column" after "3-D Column" is 2-D
144
- * again — unlike `PARETO` / `REGION_MAP`, which only import sets.
181
+ * `sourceChartType` tokens the picker's presets author (3-D classes, the
182
+ * of-pie composite and the Pareto histogram). Picking a chart type that
183
+ * carries none of them resets the variant, so "Clustered Column" after
184
+ * "3-D Column" is 2-D again and "Histogram" after "Pareto" is a plain
185
+ * histogram — unlike `REGION_MAP`, which only an import sets.
145
186
  */
146
187
  const PICKER_VARIANT_TOKENS = new Set([
147
188
  "BAR_3D",
@@ -151,6 +192,7 @@ const PICKER_VARIANT_TOKENS = new Set([
151
192
  "SURFACE",
152
193
  "SURFACE_3D",
153
194
  "OF_PIE",
195
+ "PARETO",
154
196
  ]);
155
197
  /** Of-pie split fields; meaningless once the spec is no longer an of-pie. */
156
198
  const OF_PIE_FIELDS = ["ofPieType", "splitType", "splitPos", "secondPieSize"];
@@ -230,7 +272,9 @@ export const mergeChartSpec = (existingSpec, incomingSpec) => {
230
272
  delete merged[prop];
231
273
  }
232
274
  }
233
- // When switching categories, remove data fields from old category
275
+ // When switching categories, remove data fields from old category. The
276
+ // data itself is carried over below (`carryChartDataAcrossCategories`),
277
+ // as Excel keeps the selected cells when the chart type changes.
234
278
  if (isCategoryChange) {
235
279
  const oldCategoryDataFields = CATEGORY_DATA_FIELDS[existingCategory];
236
280
  for (const field of oldCategoryDataFields) {
@@ -261,15 +305,58 @@ export const mergeChartSpec = (existingSpec, incomingSpec) => {
261
305
  const existingWithData = existingSpec;
262
306
  const incomingWithData = incomingSpec;
263
307
  const targetDataFields = CATEGORY_DATA_FIELDS[targetCategory];
308
+ const carried = isCategoryChange
309
+ ? carryChartDataAcrossCategories(existingWithData, existingCategory, targetCategory)
310
+ : undefined;
264
311
  for (const field of targetDataFields) {
265
- const existingData = isCategoryChange ? undefined : existingWithData[field];
312
+ const existingData = isCategoryChange
313
+ ? carried?.[field]
314
+ : existingWithData[field];
266
315
  const incomingData = incomingWithData[field];
267
316
  if (existingData !== undefined || incomingData !== undefined) {
268
317
  merged[field] = mergeChartDataArray(existingData, incomingData);
269
318
  }
270
319
  }
320
+ // Every data array of the target category exists on the result — the
321
+ // editor maps over them, and a chart type switched from another category
322
+ // (line → bubble) used to leave `series` / `domains` undefined and crash
323
+ // the editor on `series.some` (rowsncolumns/spreadsheet#1101).
324
+ for (const field of REQUIRED_DATA_FIELDS[targetCategory]) {
325
+ if (!Array.isArray(merged[field]))
326
+ merged[field] = [];
327
+ }
271
328
  return merged;
272
329
  };
330
+ /**
331
+ * The data arrays a category's spec type declares as required (the editor
332
+ * and the renderers map over them without a guard).
333
+ */
334
+ const REQUIRED_DATA_FIELDS = {
335
+ basic: ["domains", "series"],
336
+ bubble: ["domains", "series", "bubbleLabels"],
337
+ hierarchy: ["labels", "parentLabels", "sizeData"],
338
+ };
339
+ /**
340
+ * The selected cells survive a chart type change across categories, as in
341
+ * Excel: a column chart's categories become a scatter's X values and its
342
+ * series the Y values (and back); a treemap's labels become the categories
343
+ * and its sizes the first series (and back, with no parent levels).
344
+ */
345
+ const carryChartDataAcrossCategories = (existing, from, to) => {
346
+ const clone = (data) => data?.map((entry) => ({ ...entry, sources: [...(entry.sources ?? [])] }));
347
+ const categories = from === "hierarchy" ? clone(existing.labels) : clone(existing.domains);
348
+ const series = from === "hierarchy" ? clone(existing.sizeData) : clone(existing.series);
349
+ if (to === "hierarchy") {
350
+ return {
351
+ labels: categories ?? [],
352
+ parentLabels: [],
353
+ sizeData: series?.length ? [series[0]] : [],
354
+ };
355
+ }
356
+ // A bubble's labels and sizes cannot be guessed — the user picks them
357
+ // in the editor (the preset's placeholder entry is kept).
358
+ return { domains: categories ?? [], series: series ?? [] };
359
+ };
273
360
  /**
274
361
  * Extracts all SheetRange objects from a ChartSpec.
275
362
  * Useful for subscribing to data changes across all chart data sources.
@@ -9,6 +9,8 @@ type OverlaySeriesSpec = {
9
9
  color?: string | null;
10
10
  forecastForward?: number | null;
11
11
  forecastBackward?: number | null;
12
+ showEquation?: boolean | null;
13
+ showRSquared?: boolean | null;
12
14
  }> | null;
13
15
  errorBars?: {
14
16
  direction?: "x" | "y" | null;
@@ -1 +1 @@
1
- {"version":3,"file":"echarts-overlays.d.ts","sourceRoot":"","sources":["../../../utils/echarts-overlays.ts"],"names":[],"mappings":"AAkBA,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,UAAU,CAAC,EACP,KAAK,CAAC;QACJ,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CAAC,GACF,IAAI,CAAC;IACT,SAAS,CAAC,EAAE;QACV,SAAS,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;QAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;QAC3C,SAAS,CAAC,EAAE,GAAG,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QAC1B,SAAS,CAAC,EAAE,GAAG,CAAC;QAChB,UAAU,CAAC,EAAE,GAAG,CAAC;KAClB,GAAG,IAAI,CAAC;CACV,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,MAAM,GAAG,OAAO,IAAI;IACpD,MAAM,EAAE,iBAAiB,CAAC;IAC1B,2EAA2E;IAC3E,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC;IAC/C,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;CAC/D,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,GAAI,MAAM,GAAG,OAAO,EAAE,gFAQzD,qBAAqB,CAAC,MAAM,CAAC,KAAG,GAAG,EA4HrC,CAAC"}
1
+ {"version":3,"file":"echarts-overlays.d.ts","sourceRoot":"","sources":["../../../utils/echarts-overlays.ts"],"names":[],"mappings":"AAkBA,KAAK,iBAAiB,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,UAAU,CAAC,EACP,KAAK,CAAC;QACJ,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QAC9B,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;KAC/B,CAAC,GACF,IAAI,CAAC;IACT,SAAS,CAAC,EAAE;QACV,SAAS,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;QAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;QAC3C,SAAS,CAAC,EAAE,GAAG,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QAC1B,SAAS,CAAC,EAAE,GAAG,CAAC;QAChB,UAAU,CAAC,EAAE,GAAG,CAAC;KAClB,GAAG,IAAI,CAAC;CACV,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,MAAM,GAAG,OAAO,IAAI;IACpD,MAAM,EAAE,iBAAiB,CAAC;IAC1B,2EAA2E;IAC3E,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC;IAC/C,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;CAC/D,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,GAAI,MAAM,GAAG,OAAO,EAAE,gFAQzD,qBAAqB,CAAC,MAAM,CAAC,KAAG,GAAG,EA0IrC,CAAC"}