@rowsncolumns/charts 28.1.14 → 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,16 @@
1
+ import type { ChartAxisOptions } from "@rowsncolumns/spreadsheet";
2
+ import React from "react";
3
+ /**
4
+ * One axis' options (`ChartAxisOptions`): a value axis has a scale
5
+ * (min / max / logarithmic), both have direction, gridlines, visibility
6
+ * and tick-label font; a value axis also has its number format.
7
+ */
8
+ export declare const AxisOptionsFields: ({ label, kind, value, onChange, gridlinesDefault, }: {
9
+ label: string;
10
+ kind: "value" | "category";
11
+ value: ChartAxisOptions | null | undefined;
12
+ onChange(next: ChartAxisOptions): void;
13
+ /** What an omitted `showMajorGridlines` means for this axis. */
14
+ gridlinesDefault?: boolean;
15
+ }) => React.JSX.Element;
16
+ //# sourceMappingURL=axis-options-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"axis-options-fields.d.ts","sourceRoot":"","sources":["../../../../../components/editors/fields/axis-options-fields.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,qDAM/B;IACD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,GAAG,UAAU,CAAC;IAC3B,KAAK,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACvC,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,sBAoEA,CAAC"}
@@ -0,0 +1,22 @@
1
+ import React from "react";
2
+ import { CheckboxField, NumberField, TextField } from "./primitives";
3
+ import { TextFormatFields } from "./text-format-fields";
4
+ /**
5
+ * One axis' options (`ChartAxisOptions`): a value axis has a scale
6
+ * (min / max / logarithmic), both have direction, gridlines, visibility
7
+ * and tick-label font; a value axis also has its number format.
8
+ */
9
+ export const AxisOptionsFields = ({ label, kind, value, onChange, gridlinesDefault = true, }) => {
10
+ const set = (patch) => onChange({ ...(value ?? {}), ...patch });
11
+ return (React.createElement("div", { className: "flex flex-col gap-2 pb-2" },
12
+ React.createElement("label", { className: "font-system text-sm" }, label),
13
+ kind === "value" ? (React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
14
+ React.createElement(NumberField, { label: "Min", ariaLabel: `${label} min`, value: value?.min, onChange: (min) => set({ min }), placeholder: "Auto" }),
15
+ React.createElement(NumberField, { label: "Max", ariaLabel: `${label} max`, value: value?.max, onChange: (max) => set({ max }), placeholder: "Auto" }))) : null,
16
+ kind === "value" ? (React.createElement(CheckboxField, { label: "Logarithmic scale", ariaLabel: `${label} logarithmic scale`, checked: Boolean(value?.logarithmic), onChange: (on) => set({ logarithmic: on || undefined }) })) : null,
17
+ React.createElement(CheckboxField, { label: "Reverse direction", ariaLabel: `${label} reverse direction`, checked: Boolean(value?.reverse), onChange: (on) => set({ reverse: on || undefined }) }),
18
+ React.createElement(CheckboxField, { label: "Gridlines", ariaLabel: `${label} gridlines`, checked: value?.showMajorGridlines ?? gridlinesDefault, onChange: (showMajorGridlines) => set({ showMajorGridlines }) }),
19
+ React.createElement(CheckboxField, { label: "Show axis", ariaLabel: `${label} visible`, checked: value?.visible !== false, onChange: (on) => set({ visible: on ? undefined : false }) }),
20
+ kind === "value" ? (React.createElement(TextField, { label: "Number format", ariaLabel: `${label} number format`, value: value?.numberFormatPattern, onChange: (numberFormatPattern) => set({ numberFormatPattern }), placeholder: "Linked to source" })) : null,
21
+ React.createElement(TextFormatFields, { label: `${label} font`, collapsible: true, value: value?.textFormat, onChange: (textFormat) => set({ textFormat }) })));
22
+ };
@@ -0,0 +1,25 @@
1
+ import type { EmbeddedChart } from "@rowsncolumns/spreadsheet";
2
+ import React from "react";
3
+ import type { ChartEditorCapabilities } from "../chart-editor-capabilities";
4
+ type ChartSpec = EmbeddedChart["spec"];
5
+ /** `totalIndices` (0-based) ⇄ the "1, 4, 7" the user types (1-based). */
6
+ export declare const parseTotalPoints: (text: string) => number[] | undefined;
7
+ export declare const formatTotalPoints: (indices: number[] | null | undefined) => string;
8
+ /** Whether `ChartTypeOptionsFields` renders anything for this chart. */
9
+ export declare const chartTypeHasOptions: (spec: Pick<ChartSpec, "chartType"> & {
10
+ sourceChartType?: unknown;
11
+ }, capabilities: Pick<ChartEditorCapabilities, "category" | "hasGapWidth" | "hasOverlap">) => boolean;
12
+ /**
13
+ * The options a chart type has beyond its series and axes — Excel's
14
+ * Format Data Series → Series Options for histogram bins, box & whisker,
15
+ * waterfall totals, pie-of-pie splits, bubble sizing, treemap labels,
16
+ * radar / stock variants, doughnut hole, explosion, gap width and overlap.
17
+ * Returns `null` when the chart type has none.
18
+ */
19
+ export declare const ChartTypeOptionsFields: ({ spec, capabilities, setFieldValue, }: {
20
+ spec: ChartSpec;
21
+ capabilities: ChartEditorCapabilities;
22
+ setFieldValue(field: string, value: unknown): void;
23
+ }) => React.JSX.Element | null;
24
+ export {};
25
+ //# sourceMappingURL=chart-type-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-type-options.d.ts","sourceRoot":"","sources":["../../../../../components/editors/fields/chart-type-options.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAG5E,KAAK,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAEvC,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,MAAM,EAAE,GAAG,SAQ1D,CAAC;AACF,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,KAAG,MAC3B,CAAC;AAE/C,wEAAwE;AACxE,eAAO,MAAM,mBAAmB,GAC9B,MAAM,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,EAClE,cAAc,IAAI,CAAC,uBAAuB,EAAE,UAAU,GAAG,aAAa,GAAG,YAAY,CAAC,KACrF,OAkBF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAI,wCAIpC;IACD,IAAI,EAAE,SAAS,CAAC;IAChB,YAAY,EAAE,uBAAuB,CAAC;IACtC,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CACpD,6BAuWA,CAAC"}
@@ -0,0 +1,151 @@
1
+ import { Stack } from "@rowsncolumns/ui";
2
+ import React from "react";
3
+ import { CheckboxField, ColorField, NumberField, SelectField, TextField } from "./primitives";
4
+ /** `totalIndices` (0-based) ⇄ the "1, 4, 7" the user types (1-based). */
5
+ export const parseTotalPoints = (text) => {
6
+ const points = text
7
+ .split(/[,\s;]+/)
8
+ .map((part) => Number.parseInt(part, 10))
9
+ .filter((n) => Number.isFinite(n) && n >= 1)
10
+ .map((n) => n - 1);
11
+ const unique = [...new Set(points)].sort((a, b) => a - b);
12
+ return unique.length ? unique : undefined;
13
+ };
14
+ export const formatTotalPoints = (indices) => (indices ?? []).map((i) => i + 1).join(", ");
15
+ /** Whether `ChartTypeOptionsFields` renders anything for this chart. */
16
+ export const chartTypeHasOptions = (spec, capabilities) => {
17
+ const type = spec.chartType;
18
+ const token = String(spec.sourceChartType ?? "").toUpperCase();
19
+ return (type === "histogram" ||
20
+ type === "boxplot" ||
21
+ type === "waterfall" ||
22
+ (type === "pie" && token === "OF_PIE") ||
23
+ type === "bubble" ||
24
+ type === "scatter" ||
25
+ capabilities.category === "hierarchy" ||
26
+ type === "radar" ||
27
+ type === "stock" ||
28
+ type === "doughnut" ||
29
+ type === "pie" ||
30
+ capabilities.hasGapWidth ||
31
+ capabilities.hasOverlap);
32
+ };
33
+ /**
34
+ * The options a chart type has beyond its series and axes — Excel's
35
+ * Format Data Series → Series Options for histogram bins, box & whisker,
36
+ * waterfall totals, pie-of-pie splits, bubble sizing, treemap labels,
37
+ * radar / stock variants, doughnut hole, explosion, gap width and overlap.
38
+ * Returns `null` when the chart type has none.
39
+ */
40
+ export const ChartTypeOptionsFields = ({ spec, capabilities, setFieldValue, }) => {
41
+ const s = spec;
42
+ const type = spec.chartType;
43
+ const isPareto = type === "histogram" && String(s.sourceChartType ?? "").toUpperCase() === "PARETO";
44
+ const isOfPie = type === "pie" && String(s.sourceChartType ?? "").toUpperCase() === "OF_PIE";
45
+ const controls = [];
46
+ if (type === "histogram") {
47
+ controls.push(React.createElement(Stack, { key: "bins", direction: "vertical", className: "gap-2 pb-2" },
48
+ React.createElement("label", { className: "font-system text-sm" }, "Bins"),
49
+ React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
50
+ React.createElement(NumberField, { label: "Bins (leave blank for auto)", ariaLabel: "Bins (leave blank for auto)", value: s.binCount, min: 1, onChange: (binCount) => setFieldValue("spec.binCount", binCount), placeholder: "Auto", className: "text-xs w-28" }),
51
+ React.createElement(NumberField, { label: "Bin width", ariaLabel: "Bin width", value: s.binSize, min: 0, onChange: (binSize) => setFieldValue("spec.binSize", binSize), placeholder: "Auto" }),
52
+ React.createElement(SelectField, { label: "Interval closed on", ariaLabel: "Interval closed on", value: s.intervalClosed ?? "r", options: [
53
+ { value: "r", label: "Right (a, b]" },
54
+ { value: "l", label: "Left [a, b)" },
55
+ ], onChange: (intervalClosed) => setFieldValue("spec.intervalClosed", intervalClosed === "r" ? undefined : intervalClosed) })),
56
+ React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
57
+ React.createElement(NumberField, { label: "Overflow bin (values above)", ariaLabel: "Overflow bin", value: s.overflow, onChange: (overflow) => setFieldValue("spec.overflow", overflow), placeholder: "None", className: "text-xs w-28" }),
58
+ React.createElement(NumberField, { label: "Underflow bin (values below)", ariaLabel: "Underflow bin", value: s.underflow, onChange: (underflow) => setFieldValue("spec.underflow", underflow), placeholder: "None", className: "text-xs w-28" })),
59
+ isPareto ? (React.createElement(ColorField, { label: "Pareto line color", ariaLabel: "Pareto line color", value: s.paretoLineColor, onChange: (color) => setFieldValue("spec.paretoLineColor", color), onClear: () => setFieldValue("spec.paretoLineColor", undefined) })) : null));
60
+ }
61
+ if (type === "boxplot") {
62
+ controls.push(React.createElement(Stack, { key: "box", direction: "vertical", className: "gap-1 pb-2" },
63
+ React.createElement("label", { className: "font-system text-sm" }, "Box & whisker"),
64
+ React.createElement(SelectField, { label: "Quartile calculation", ariaLabel: "Quartile calculation", value: s.quartileMethod ?? "exclusive", options: [
65
+ { value: "exclusive", label: "Exclusive median" },
66
+ { value: "inclusive", label: "Inclusive median" },
67
+ ], onChange: (quartileMethod) => setFieldValue("spec.quartileMethod", quartileMethod), className: "w-40" }),
68
+ React.createElement(CheckboxField, { label: "Show outlier points", checked: s.showOutliers !== false, onChange: (on) => setFieldValue("spec.showOutliers", on ? undefined : false) }),
69
+ React.createElement(CheckboxField, { label: "Show mean markers", checked: Boolean(s.showMeanMarker), onChange: (on) => setFieldValue("spec.showMeanMarker", on || undefined) }),
70
+ React.createElement(CheckboxField, { label: "Show inner points", checked: Boolean(s.showInnerPoints), onChange: (on) => setFieldValue("spec.showInnerPoints", on || undefined) }),
71
+ React.createElement(CheckboxField, { label: "Show mean line", checked: Boolean(s.showMeanLine), onChange: (on) => setFieldValue("spec.showMeanLine", on || undefined) })));
72
+ }
73
+ if (type === "waterfall") {
74
+ controls.push(React.createElement(Stack, { key: "waterfall", direction: "vertical", className: "gap-1 pb-2" },
75
+ React.createElement(TextField, { label: "Total points (1-based, comma-separated)", ariaLabel: "Total points", value: formatTotalPoints(s.totalIndices), onChange: (text) => setFieldValue("spec.totalIndices", parseTotalPoints(text ?? "")), placeholder: "e.g. 4, 8", className: "text-xs w-40" }),
76
+ React.createElement("p", { className: "m-0 text-xs text-rnc-text-weak" }, "A total bar starts from zero instead of the running sum (Excel's \"Set as total\"). Decreases take each series' negative fill.")));
77
+ }
78
+ if (isOfPie) {
79
+ controls.push(React.createElement(Stack, { key: "ofpie", direction: "vertical", className: "gap-2 pb-2" },
80
+ React.createElement("label", { className: "font-system text-sm" }, "Second plot"),
81
+ React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
82
+ React.createElement(SelectField, { label: "Split series by", ariaLabel: "Split series by", value: s.splitType ?? "position", options: [
83
+ { value: "position", label: "Position" },
84
+ { value: "value", label: "Value" },
85
+ { value: "percent", label: "Percentage value" },
86
+ ], onChange: (splitType) => setFieldValue("spec.splitType", splitType) }),
87
+ React.createElement(NumberField, { label: (s.splitType ?? "position") === "position"
88
+ ? "Values in second plot"
89
+ : (s.splitType === "value" ? "Values less than" : "Values less than %"), ariaLabel: "Split position", value: s.splitPos, min: 0, onChange: (splitPos) => setFieldValue("spec.splitPos", splitPos), placeholder: "3" }),
90
+ React.createElement(NumberField, { label: "Second plot size (%)", ariaLabel: "Second plot size", value: s.secondPieSize, min: 5, max: 200, onChange: (secondPieSize) => setFieldValue("spec.secondPieSize", secondPieSize), placeholder: "75" }))));
91
+ }
92
+ if (type === "bubble") {
93
+ controls.push(React.createElement(Stack, { key: "bubble", direction: "vertical", className: "gap-2 pb-2" },
94
+ React.createElement("label", { className: "font-system text-sm" }, "Bubble size"),
95
+ React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
96
+ React.createElement(NumberField, { label: "Scale bubble size to (%)", ariaLabel: "Bubble scale", value: s.bubbleScale, min: 0, max: 300, onChange: (bubbleScale) => setFieldValue("spec.bubbleScale", bubbleScale), placeholder: "100", className: "text-xs w-28" }),
97
+ React.createElement(SelectField, { label: "Size represents", ariaLabel: "Size represents", value: s.sizeRepresents ?? "area", options: [
98
+ { value: "area", label: "Area of bubbles" },
99
+ { value: "width", label: "Width of bubbles" },
100
+ ], onChange: (sizeRepresents) => setFieldValue("spec.sizeRepresents", sizeRepresents === "area" ? undefined : sizeRepresents) }))));
101
+ }
102
+ if (type === "scatter") {
103
+ controls.push(React.createElement(SelectField, { key: "scatter", label: "Scatter style", ariaLabel: "Scatter style", value: s.scatterStyle ?? "lineMarker", options: [
104
+ { value: "lineMarker", label: "Straight lines with markers" },
105
+ { value: "line", label: "Straight lines" },
106
+ { value: "marker", label: "Markers only" },
107
+ { value: "smoothMarker", label: "Smooth lines with markers" },
108
+ { value: "smooth", label: "Smooth lines" },
109
+ { value: "none", label: "No lines or markers" },
110
+ ], onChange: (scatterStyle) => setFieldValue("spec.scatterStyle", scatterStyle), className: "w-56" }));
111
+ }
112
+ if (capabilities.category === "hierarchy") {
113
+ controls.push(React.createElement(Stack, { key: "hierarchy", direction: "vertical", className: "gap-1 pb-2" },
114
+ type === "treemap" ? (React.createElement(SelectField, { label: "Category labels", ariaLabel: "Category label layout", value: s.parentLabelLayout ?? "banner", options: [
115
+ { value: "banner", label: "Banner" },
116
+ { value: "overlapping", label: "Overlapping" },
117
+ { value: "none", label: "None" },
118
+ ], onChange: (parentLabelLayout) => setFieldValue("spec.parentLabelLayout", parentLabelLayout === "banner" ? undefined : parentLabelLayout), className: "w-40" })) : null,
119
+ React.createElement(CheckboxField, { label: "Drill down on click", checked: Boolean(s.drillDown), onChange: (on) => setFieldValue("spec.drillDown", on || undefined) })));
120
+ }
121
+ if (type === "radar") {
122
+ controls.push(React.createElement(SelectField, { key: "radar", label: "Radar style", ariaLabel: "Radar style", value: s.radarStyle ?? "standard", options: [
123
+ { value: "standard", label: "Standard" },
124
+ { value: "marker", label: "With markers" },
125
+ { value: "filled", label: "Filled" },
126
+ ], onChange: (radarStyle) => setFieldValue("spec.radarStyle", radarStyle), className: "w-40" }));
127
+ }
128
+ if (type === "stock") {
129
+ controls.push(React.createElement(SelectField, { key: "stock", label: "Stock variant", ariaLabel: "Stock variant", value: s.stockVariant ?? "HLC", options: [
130
+ { value: "HLC", label: "High-Low-Close" },
131
+ { value: "OHLC", label: "Open-High-Low-Close" },
132
+ { value: "VHLC", label: "Volume-High-Low-Close" },
133
+ { value: "VOHLC", label: "Volume-Open-High-Low-Close" },
134
+ ], onChange: (stockVariant) => setFieldValue("spec.stockVariant", stockVariant), className: "w-56" }));
135
+ }
136
+ if (type === "doughnut") {
137
+ controls.push(React.createElement(NumberField, { key: "hole", label: "Doughnut hole size (0-0.9)", ariaLabel: "Doughnut hole size (0-0.9)", value: s.doughnutHoleSize, min: 0, max: 0.9, step: 0.05, onChange: (doughnutHoleSize) => setFieldValue("spec.doughnutHoleSize", doughnutHoleSize), placeholder: "0.5", className: "text-xs w-32" }));
138
+ }
139
+ if (type === "pie" || type === "doughnut") {
140
+ controls.push(React.createElement(NumberField, { key: "explosion", label: "Explosion (% of radius, 0-400)", ariaLabel: "Explosion", value: s.explosion, min: 0, max: 400, step: 5, onChange: (explosion) => setFieldValue("spec.explosion", explosion), placeholder: "0", className: "text-xs w-32" }));
141
+ }
142
+ if (capabilities.hasGapWidth) {
143
+ controls.push(React.createElement(NumberField, { key: "gap", label: "Gap width (0-500)", ariaLabel: "Gap width (0-500)", value: s.gapWidth, min: 0, max: 500, onChange: (gapWidth) => setFieldValue("spec.gapWidth", gapWidth), placeholder: type === "histogram" ? "0" : "150", className: "text-xs w-32" }));
144
+ }
145
+ if (capabilities.hasOverlap) {
146
+ controls.push(React.createElement(NumberField, { key: "overlap", label: "Series overlap (-100 to 100)", ariaLabel: "Series overlap (-100 to 100)", value: s.overlap, min: -100, max: 100, onChange: (overlap) => setFieldValue("spec.overlap", overlap), placeholder: "0", className: "text-xs w-32" }));
147
+ }
148
+ if (!controls.length)
149
+ return null;
150
+ return React.createElement(React.Fragment, null, controls);
151
+ };
@@ -0,0 +1,15 @@
1
+ import type { ChartDataLabelsOptions } from "@rowsncolumns/spreadsheet";
2
+ import React from "react";
3
+ import type { ChartEditorCapabilities } from "../chart-editor-capabilities";
4
+ /**
5
+ * What a data label shows and where (`ChartDataLabelsOptions`) — the chart's
6
+ * labels, or one series' own when `perSeries` (Excel's Format Data Labels on
7
+ * one series: inherit the chart's, show its own, or hide them).
8
+ */
9
+ export declare const DataLabelsFields: ({ value, onChange, capabilities, perSeries, }: {
10
+ value: ChartDataLabelsOptions | null | undefined;
11
+ onChange(next: ChartDataLabelsOptions | undefined): void;
12
+ capabilities: Pick<ChartEditorCapabilities, "hasPercentLabels" | "hasBubbleSizeLabels">;
13
+ perSeries?: boolean;
14
+ }) => React.JSX.Element;
15
+ //# sourceMappingURL=data-labels-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-labels-fields.d.ts","sourceRoot":"","sources":["../../../../../components/editors/fields/data-labels-fields.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAoB5E;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,+CAK9B;IACD,KAAK,EAAE,sBAAsB,GAAG,IAAI,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,IAAI,EAAE,sBAAsB,GAAG,SAAS,GAAG,IAAI,CAAC;IACzD,YAAY,EAAE,IAAI,CAChB,uBAAuB,EACvB,kBAAkB,GAAG,qBAAqB,CAC3C,CAAC;IACF,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,sBA2FA,CAAC"}
@@ -0,0 +1,47 @@
1
+ import React from "react";
2
+ import { CheckboxField, SelectField, TextField } from "./primitives";
3
+ import { TextFormatFields } from "./text-format-fields";
4
+ const POSITIONS = [
5
+ { value: "center", label: "Center" },
6
+ { value: "inside", label: "Inside" },
7
+ { value: "outside", label: "Outside" },
8
+ { value: "insideEnd", label: "Inside end" },
9
+ { value: "outsideEnd", label: "Outside end" },
10
+ { value: "bestFit", label: "Best fit" },
11
+ { value: "above", label: "Above" },
12
+ { value: "below", label: "Below" },
13
+ { value: "left", label: "Left" },
14
+ { value: "right", label: "Right" },
15
+ ];
16
+ /**
17
+ * What a data label shows and where (`ChartDataLabelsOptions`) — the chart's
18
+ * labels, or one series' own when `perSeries` (Excel's Format Data Labels on
19
+ * one series: inherit the chart's, show its own, or hide them).
20
+ */
21
+ export const DataLabelsFields = ({ value, onChange, capabilities, perSeries = false, }) => {
22
+ const set = (patch) => onChange({ ...(value ?? {}), ...patch });
23
+ const mode = !value
24
+ ? "inherit"
25
+ : value.show
26
+ ? "show"
27
+ : "hide";
28
+ return (React.createElement("div", { className: "flex flex-col gap-1" },
29
+ perSeries ? (React.createElement(SelectField, { label: "Data labels", value: mode, options: [
30
+ { value: "inherit", label: "Same as chart" },
31
+ { value: "show", label: "Show" },
32
+ { value: "hide", label: "Hide" },
33
+ ], onChange: (next) => onChange(next === "inherit"
34
+ ? undefined
35
+ : next === "show"
36
+ ? { ...(value ?? {}), show: true }
37
+ : { show: false }), className: "w-32" })) : (React.createElement(CheckboxField, { small: false, label: "Show data labels", checked: Boolean(value?.show), onChange: (show) => set({ show }) })),
38
+ value?.show ? (React.createElement("div", { className: "pl-4 flex flex-col gap-1" },
39
+ React.createElement(CheckboxField, { label: "Value", checked: value.showValue !== false, onChange: (showValue) => set({ showValue }) }),
40
+ React.createElement(CheckboxField, { label: "Category name", checked: Boolean(value.showCategoryName), onChange: (showCategoryName) => set({ showCategoryName }) }),
41
+ React.createElement(CheckboxField, { label: "Series name", checked: Boolean(value.showSeriesName), onChange: (showSeriesName) => set({ showSeriesName }) }),
42
+ capabilities.hasPercentLabels ? (React.createElement(CheckboxField, { label: "Percentage", checked: Boolean(value.showPercent), onChange: (showPercent) => set({ showPercent }) })) : null,
43
+ capabilities.hasBubbleSizeLabels ? (React.createElement(CheckboxField, { label: "Bubble size", checked: Boolean(value.showBubbleSize), onChange: (showBubbleSize) => set({ showBubbleSize }) })) : null,
44
+ React.createElement(SelectField, { label: "Label position", value: value.position ?? "outside", options: POSITIONS, onChange: (position) => set({ position }), className: "w-32" }),
45
+ React.createElement(TextField, { label: "Number format pattern", value: value.numberFormatPattern, onChange: (numberFormatPattern) => set({ numberFormatPattern }), placeholder: "#,##0.00" }),
46
+ React.createElement(TextFormatFields, { label: "Label font", value: value.textFormat, onChange: (textFormat) => set({ textFormat }) }))) : null));
47
+ };
@@ -0,0 +1,54 @@
1
+ import React from "react";
2
+ /**
3
+ * The editor's small native controls, styled like the rest of the dialog.
4
+ * They stay native (`<select>`, `<input type=checkbox|color>`) so the
5
+ * editor's test mocks of `@rowsncolumns/ui` keep covering it.
6
+ */
7
+ export declare const SELECT_CLASS = "border border-rnc-border rounded-sm px-1 py-1 text-xs bg-transparent";
8
+ export declare const COLOR_CLASS = "h-6 w-8 p-0 border border-rnc-border rounded-sm bg-transparent cursor-pointer";
9
+ export declare const CheckboxField: ({ label, checked, onChange, small, ariaLabel, }: {
10
+ label: React.ReactNode;
11
+ checked: boolean;
12
+ onChange(checked: boolean): void;
13
+ small?: boolean;
14
+ ariaLabel?: string;
15
+ }) => React.JSX.Element;
16
+ export declare const SelectField: <T extends string>({ label, value, options, onChange, ariaLabel, className, }: {
17
+ label?: React.ReactNode;
18
+ value: T;
19
+ options: ReadonlyArray<{
20
+ value: T;
21
+ label: string;
22
+ }>;
23
+ onChange(value: T): void;
24
+ ariaLabel?: string;
25
+ className?: string;
26
+ }) => React.JSX.Element;
27
+ export declare const NumberField: ({ label, value, onChange, placeholder, min, max, step, ariaLabel, className, }: {
28
+ label?: React.ReactNode;
29
+ value: number | null | undefined;
30
+ onChange(value: number | undefined): void;
31
+ placeholder?: string;
32
+ min?: number;
33
+ max?: number;
34
+ step?: number;
35
+ ariaLabel?: string;
36
+ className?: string;
37
+ }) => React.JSX.Element;
38
+ export declare const TextField: ({ label, value, onChange, placeholder, ariaLabel, className, }: {
39
+ label?: React.ReactNode;
40
+ value: string | null | undefined;
41
+ onChange(value: string | undefined): void;
42
+ placeholder?: string;
43
+ ariaLabel?: string;
44
+ className?: string;
45
+ }) => React.JSX.Element;
46
+ export declare const ColorField: ({ label, value, fallback, onChange, onClear, ariaLabel, }: {
47
+ label?: React.ReactNode;
48
+ value: string | null | undefined;
49
+ fallback?: string;
50
+ onChange(value: string): void;
51
+ onClear?(): void;
52
+ ariaLabel?: string;
53
+ }) => React.JSX.Element;
54
+ //# sourceMappingURL=primitives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../../../components/editors/fields/primitives.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;GAIG;AAEH,eAAO,MAAM,YAAY,yEAC+C,CAAC;AACzE,eAAO,MAAM,WAAW,kFACyD,CAAC;AAElF,eAAO,MAAM,aAAa,GAAI,iDAM3B;IACD,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,sBAYA,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAAE,4DAO3C;IACD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,KAAK,EAAE,CAAC,CAAC;IACT,OAAO,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,sBAgBA,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,gFAUzB;IACD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,sBAiBA,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,gEAOvB;IACD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,sBAYA,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,2DAOxB;IACD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,IAAI,IAAI,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,sBAsBA,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { Input, Stack } from "@rowsncolumns/ui";
2
+ import React from "react";
3
+ /**
4
+ * The editor's small native controls, styled like the rest of the dialog.
5
+ * They stay native (`<select>`, `<input type=checkbox|color>`) so the
6
+ * editor's test mocks of `@rowsncolumns/ui` keep covering it.
7
+ */
8
+ export const SELECT_CLASS = "border border-rnc-border rounded-sm px-1 py-1 text-xs bg-transparent";
9
+ export const COLOR_CLASS = "h-6 w-8 p-0 border border-rnc-border rounded-sm bg-transparent cursor-pointer";
10
+ export const CheckboxField = ({ label, checked, onChange, small = true, ariaLabel, }) => (React.createElement("label", { className: `font-system ${small ? "text-xs" : "text-sm"} flex items-center gap-1` },
11
+ React.createElement("input", { type: "checkbox", checked: checked, "aria-label": ariaLabel, onChange: (e) => onChange(e.target.checked) }),
12
+ label));
13
+ export const SelectField = ({ label, value, options, onChange, ariaLabel, className, }) => (React.createElement(Stack, { direction: "vertical", className: "gap-1" },
14
+ label ? React.createElement("label", { className: "font-system text-xs" }, label) : null,
15
+ React.createElement("select", { className: `${SELECT_CLASS} ${className ?? ""}`, "aria-label": ariaLabel ?? (typeof label === "string" ? label : undefined), value: value, onChange: (e) => onChange(e.target.value) }, options.map((option) => (React.createElement("option", { key: option.value, value: option.value }, option.label))))));
16
+ export const NumberField = ({ label, value, onChange, placeholder, min, max, step, ariaLabel, className = "text-xs w-20", }) => (React.createElement(Stack, { direction: "vertical", className: "gap-1" },
17
+ label ? React.createElement("label", { className: "font-system text-xs" }, label) : null,
18
+ React.createElement(Input, { type: "number", value: value ?? "", min: min, max: max, step: step, "aria-label": ariaLabel ?? (typeof label === "string" ? label : undefined), onChange: (e) => onChange(e.target.value === "" ? undefined : Number(e.target.value)), className: className, placeholder: placeholder })));
19
+ export const TextField = ({ label, value, onChange, placeholder, ariaLabel, className = "text-xs w-32", }) => (React.createElement(Stack, { direction: "vertical", className: "gap-1" },
20
+ label ? React.createElement("label", { className: "font-system text-xs" }, label) : null,
21
+ React.createElement(Input, { type: "text", value: value ?? "", "aria-label": ariaLabel ?? (typeof label === "string" ? label : undefined), onChange: (e) => onChange(e.target.value || undefined), className: className, placeholder: placeholder })));
22
+ export const ColorField = ({ label, value, fallback = "#4285F4", onChange, onClear, ariaLabel, }) => (React.createElement(Stack, { direction: "vertical", className: "gap-1" },
23
+ label ? React.createElement("label", { className: "font-system text-xs" }, label) : null,
24
+ React.createElement("div", { className: "flex items-center gap-1" },
25
+ React.createElement("input", { type: "color", value: value ?? fallback, "aria-label": ariaLabel ?? (typeof label === "string" ? label : undefined), onChange: (e) => onChange(e.target.value), className: COLOR_CLASS }),
26
+ onClear && value ? (React.createElement("button", { type: "button", className: "font-system text-xs text-rnc-muted-foreground underline", onClick: onClear }, "Clear")) : null)));
@@ -0,0 +1,17 @@
1
+ import type { ChartData } from "@rowsncolumns/spreadsheet";
2
+ import React from "react";
3
+ import type { ChartEditorCapabilities } from "../chart-editor-capabilities";
4
+ /**
5
+ * Excel's Format Data Series for one series: axis, trendline (every
6
+ * option of Format Trendline), error bars (Format Error Bars), fill
7
+ * (gradient / no fill / per-point colours / invert if negative), markers
8
+ * and the series' own data labels. Only the groups the chart type has
9
+ * (`capabilities`) render.
10
+ */
11
+ export declare const SeriesFormatFields: ({ sheetId, series, capabilities, onChange, }: {
12
+ sheetId: number;
13
+ series: ChartData;
14
+ capabilities: ChartEditorCapabilities;
15
+ onChange(patch: Partial<ChartData>): void;
16
+ }) => React.JSX.Element;
17
+ //# sourceMappingURL=series-format-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"series-format-fields.d.ts","sourceRoot":"","sources":["../../../../../components/editors/fields/series-format-fields.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAGV,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAqC5E;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,8CAKhC;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,uBAAuB,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;CAC3C,sBAoXA,CAAC"}
@@ -0,0 +1,143 @@
1
+ import { Button, Input, Stack } from "@rowsncolumns/ui";
2
+ import React from "react";
3
+ import { ChartRangeInput } from "../chart-range-input";
4
+ import { DataLabelsFields } from "./data-labels-fields";
5
+ import { CheckboxField, ColorField, NumberField, SelectField, TextField, } from "./primitives";
6
+ const TRENDLINE_TYPES = [
7
+ { value: "linear", label: "Linear" },
8
+ { value: "exp", label: "Exponential" },
9
+ { value: "log", label: "Logarithmic" },
10
+ { value: "poly", label: "Polynomial" },
11
+ { value: "power", label: "Power" },
12
+ { value: "movingAvg", label: "Moving average" },
13
+ ];
14
+ const MARKER_SYMBOLS = [
15
+ { value: "", label: "Auto" },
16
+ { value: "circle", label: "Circle" },
17
+ { value: "square", label: "Square" },
18
+ { value: "diamond", label: "Diamond" },
19
+ { value: "triangle", label: "Triangle" },
20
+ { value: "x", label: "X" },
21
+ { value: "plus", label: "Plus" },
22
+ { value: "star", label: "Star" },
23
+ { value: "dash", label: "Dash" },
24
+ { value: "dot", label: "Dot" },
25
+ { value: "none", label: "None" },
26
+ ];
27
+ /**
28
+ * Excel's Format Data Series for one series: axis, trendline (every
29
+ * option of Format Trendline), error bars (Format Error Bars), fill
30
+ * (gradient / no fill / per-point colours / invert if negative), markers
31
+ * and the series' own data labels. Only the groups the chart type has
32
+ * (`capabilities`) render.
33
+ */
34
+ export const SeriesFormatFields = ({ sheetId, series, capabilities, onChange, }) => {
35
+ const trendline = series.trendlines?.[0];
36
+ const setTrendline = (patch) => onChange({ trendlines: [{ ...(trendline ?? { type: "linear" }), ...patch }] });
37
+ const errorBars = series.errorBars;
38
+ const setErrorBars = (patch) => onChange({ errorBars: { ...(errorBars ?? {}), ...patch } });
39
+ const pointColors = series.dataPointColors ?? [];
40
+ return (React.createElement("div", { className: "flex flex-col gap-2 pt-2 border border-rnc-border border-solid mt-2 p-2" },
41
+ capabilities.hasSecondaryAxis ? (React.createElement(CheckboxField, { small: false, label: "Plot on secondary axis", checked: Boolean(series.useSecondaryAxis), onChange: (on) => onChange({ useSecondaryAxis: on || undefined }) })) : null,
42
+ capabilities.hasTrendlines ? (React.createElement("div", { className: "flex flex-col gap-1" },
43
+ React.createElement(CheckboxField, { small: false, label: "Trendline", checked: Boolean(trendline), onChange: (on) => onChange({ trendlines: on ? [trendline ?? { type: "linear" }] : undefined }) }),
44
+ trendline ? (React.createElement("div", { className: "pl-4 flex flex-col gap-1" },
45
+ React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
46
+ React.createElement(SelectField, { label: "Type", ariaLabel: "Trendline type", value: trendline.type ?? "linear", options: TRENDLINE_TYPES, onChange: (type) => setTrendline({
47
+ type,
48
+ ...(type === "poly" ? { order: trendline.order ?? 2 } : {}),
49
+ ...(type === "movingAvg" ? { period: trendline.period ?? 2 } : {}),
50
+ }) }),
51
+ trendline.type === "poly" ? (React.createElement(NumberField, { label: "Order", ariaLabel: "Trendline order", value: trendline.order, min: 2, max: 6, onChange: (order) => setTrendline({ order }), placeholder: "2" })) : null,
52
+ trendline.type === "movingAvg" ? (React.createElement(NumberField, { label: "Period", ariaLabel: "Trendline period", value: trendline.period, min: 2, onChange: (period) => setTrendline({ period }), placeholder: "2" })) : null,
53
+ React.createElement(TextField, { label: "Name", ariaLabel: "Trendline name", value: trendline.name, onChange: (name) => setTrendline({ name }), placeholder: "Automatic" }),
54
+ React.createElement(ColorField, { label: "Color", ariaLabel: "Trendline color", value: trendline.color, onChange: (color) => setTrendline({ color }) })),
55
+ trendline.type !== "movingAvg" ? (React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
56
+ React.createElement(NumberField, { label: "Forecast forward", value: trendline.forecastForward, min: 0, onChange: (forecastForward) => setTrendline({ forecastForward }), placeholder: "0" }),
57
+ React.createElement(NumberField, { label: "Forecast backward", value: trendline.forecastBackward, min: 0, onChange: (forecastBackward) => setTrendline({ forecastBackward }), placeholder: "0" }))) : null,
58
+ trendline.type !== "movingAvg" ? (React.createElement(React.Fragment, null,
59
+ React.createElement(CheckboxField, { label: "Display equation on chart", checked: Boolean(trendline.showEquation), onChange: (showEquation) => setTrendline({ showEquation: showEquation || undefined }) }),
60
+ React.createElement(CheckboxField, { label: "Display R-squared value on chart", checked: Boolean(trendline.showRSquared), onChange: (showRSquared) => setTrendline({ showRSquared: showRSquared || undefined }) }))) : null)) : null)) : null,
61
+ capabilities.hasErrorBars ? (React.createElement("div", { className: "flex flex-col gap-1" },
62
+ React.createElement(CheckboxField, { small: false, label: "Error bars", checked: Boolean(errorBars), onChange: (on) => onChange({
63
+ errorBars: on ? errorBars ?? { valueType: "percentage", value: 5 } : undefined,
64
+ }) }),
65
+ errorBars ? (React.createElement("div", { className: "pl-4 flex flex-col gap-1" },
66
+ React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
67
+ React.createElement(SelectField, { label: "Direction", ariaLabel: "Error bar direction", value: errorBars.barType ?? "both", options: [
68
+ { value: "both", label: "Both" },
69
+ { value: "plus", label: "Plus" },
70
+ { value: "minus", label: "Minus" },
71
+ ], onChange: (barType) => setErrorBars({ barType }) }),
72
+ capabilities.category === "bubble" ? (React.createElement(SelectField, { label: "Axis", ariaLabel: "Error bar axis", value: errorBars.direction ?? "y", options: [
73
+ { value: "y", label: "Vertical" },
74
+ { value: "x", label: "Horizontal" },
75
+ ], onChange: (direction) => setErrorBars({ direction }) })) : null,
76
+ React.createElement(SelectField, { label: "Error amount", ariaLabel: "Error bar value type", value: errorBars.valueType ?? "percentage", options: [
77
+ { value: "fixedVal", label: "Fixed value" },
78
+ { value: "percentage", label: "Percentage" },
79
+ { value: "stdDev", label: "Standard deviation(s)" },
80
+ { value: "stdErr", label: "Standard error" },
81
+ { value: "custom", label: "Custom" },
82
+ ], onChange: (valueType) => setErrorBars({ valueType }) }),
83
+ errorBars.valueType !== "stdErr" && errorBars.valueType !== "custom" ? (React.createElement(NumberField, { label: "Value", ariaLabel: "Error bar value", value: errorBars.value, onChange: (value) => setErrorBars({ value }), placeholder: "5" })) : null),
84
+ errorBars.valueType === "custom" ? (React.createElement("div", { className: "flex flex-col gap-1" },
85
+ React.createElement("label", { className: "font-system text-xs" }, "Positive error value"),
86
+ React.createElement(ChartRangeInput, { sheetId: sheetId, range: errorBars.plusRange ?? undefined, onChangeRange: (plusRange) => setErrorBars({ plusRange }), placeholder: "Select a range", className: "mb-0" }),
87
+ React.createElement("label", { className: "font-system text-xs" }, "Negative error value"),
88
+ React.createElement(ChartRangeInput, { sheetId: sheetId, range: errorBars.minusRange ?? undefined, onChangeRange: (minusRange) => setErrorBars({ minusRange }), placeholder: "Select a range", className: "mb-0" }))) : null,
89
+ React.createElement(CheckboxField, { label: "No end cap", checked: Boolean(errorBars.noEndCap), onChange: (noEndCap) => setErrorBars({ noEndCap: noEndCap || undefined }) }))) : null)) : null,
90
+ capabilities.hasSeriesFill ? (React.createElement(React.Fragment, null,
91
+ React.createElement(CheckboxField, { small: false, label: "Gradient fill", checked: Boolean(series.gradient), onChange: (on) => onChange({
92
+ gradient: on
93
+ ? series.gradient ?? {
94
+ type: "linear",
95
+ degree: 90,
96
+ stops: [
97
+ { position: 0, color: series.color ?? "#4285F4" },
98
+ { position: 1, color: "#FFFFFF" },
99
+ ],
100
+ }
101
+ : undefined,
102
+ }) }),
103
+ React.createElement(CheckboxField, { small: false, label: "Transparent (no fill)", checked: Boolean(series.noFill), onChange: (noFill) => onChange({ noFill: noFill || undefined }) }))) : null,
104
+ capabilities.hasInvertIfNegative ? (React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
105
+ React.createElement(CheckboxField, { small: false, label: "Invert if negative", checked: Boolean(series.invertIfNegative), onChange: (on) => onChange({ invertIfNegative: on || undefined }) }),
106
+ series.invertIfNegative ? (React.createElement(ColorField, { label: "Negative fill", ariaLabel: "Negative fill", value: series.negativeColor, fallback: "#FFFFFF", onChange: (negativeColor) => onChange({ negativeColor }), onClear: () => onChange({ negativeColor: undefined }) })) : null)) : null,
107
+ capabilities.hasMarkers ? (React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
108
+ React.createElement(SelectField, { label: "Marker", ariaLabel: "Marker", value: series.marker?.symbol ?? "", options: MARKER_SYMBOLS, onChange: (symbol) => onChange({ marker: { ...(series.marker ?? {}), symbol: symbol || undefined } }) }),
109
+ React.createElement(NumberField, { label: "Marker size", ariaLabel: "Marker size", value: series.marker?.size, min: 1, onChange: (size) => onChange({ marker: { ...(series.marker ?? {}), size } }), placeholder: "6" }),
110
+ React.createElement(ColorField, { label: "Marker color", ariaLabel: "Marker color", value: series.marker?.color, onChange: (color) => onChange({ marker: { ...(series.marker ?? {}), color } }), onClear: () => onChange({ marker: { ...(series.marker ?? {}), color: undefined } }) }))) : null,
111
+ capabilities.hasPointColors ? (React.createElement("div", { className: "flex flex-col gap-1" },
112
+ React.createElement("label", { className: "font-system text-sm" }, "Point colors"),
113
+ pointColors.map((point, index) => (React.createElement("div", { className: "flex items-center gap-2", key: `${index}-${point.idx}` },
114
+ React.createElement(Input, { type: "number", min: 1, value: point.idx + 1, "aria-label": `Point ${index + 1} number`, onChange: (e) => {
115
+ const next = [...pointColors];
116
+ next[index] = {
117
+ ...point,
118
+ idx: Math.max(0, Math.round(Number(e.target.value) || 1) - 1),
119
+ };
120
+ onChange({ dataPointColors: next });
121
+ }, className: "text-xs w-16" }),
122
+ React.createElement("input", { type: "color", value: point.color, "aria-label": `Point ${index + 1} color`, onChange: (e) => {
123
+ const next = [...pointColors];
124
+ next[index] = { ...point, color: e.target.value };
125
+ onChange({ dataPointColors: next });
126
+ }, className: "h-6 w-8 p-0 border border-rnc-border rounded-sm bg-transparent cursor-pointer" }),
127
+ React.createElement("button", { type: "button", className: "font-system text-xs text-rnc-muted-foreground underline", onClick: () => onChange({
128
+ dataPointColors: pointColors.filter((_, i) => i !== index).length
129
+ ? pointColors.filter((_, i) => i !== index)
130
+ : undefined,
131
+ }) }, "Remove")))),
132
+ React.createElement(Stack, { direction: "horizontal", className: "gap-1" },
133
+ React.createElement(Button, { variant: "link", type: "button", className: "cursor-pointer", onClick: () => onChange({
134
+ dataPointColors: [
135
+ ...pointColors,
136
+ {
137
+ idx: pointColors.length ? pointColors[pointColors.length - 1].idx + 1 : 0,
138
+ color: series.color ?? "#4285F4",
139
+ },
140
+ ],
141
+ }) }, "Add point color")))) : null,
142
+ capabilities.hasDataLabels ? (React.createElement(DataLabelsFields, { perSeries: true, value: series.dataLabels, capabilities: capabilities, onChange: (dataLabels) => onChange({ dataLabels }) })) : null));
143
+ };
@@ -0,0 +1,16 @@
1
+ import type { ChartData } from "@rowsncolumns/spreadsheet";
2
+ import React from "react";
3
+ import type { ChartCellLabelGetter } from "../../../utils/chart-orientation";
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 declare const SeriesNameField: ({ sheetId, series, getFormattedValue, onChange, }: {
11
+ sheetId: number;
12
+ series: Pick<ChartData, "dataLabel" | "dataLabelSource">;
13
+ getFormattedValue?: ChartCellLabelGetter;
14
+ onChange(patch: Pick<ChartData, "dataLabel" | "dataLabelSource">): void;
15
+ }) => React.JSX.Element;
16
+ //# sourceMappingURL=series-name-field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"series-name-field.d.ts","sourceRoot":"","sources":["../../../../../components/editors/fields/series-name-field.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,2BAA2B,CAAC;AAEvE,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAG7E;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAI,mDAK7B;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,GAAG,iBAAiB,CAAC,CAAC;IACzD,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,GAAG,iBAAiB,CAAC,GAAG,IAAI,CAAC;CACzE,sBA0CA,CAAC"}