@rowsncolumns/charts 28.0.0 → 28.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/dist/cjs/atoms/pivot-chart.atom.d.ts +14 -0
  2. package/dist/cjs/atoms/pivot-chart.atom.d.ts.map +1 -0
  3. package/dist/cjs/atoms/pivot-chart.atom.js +9 -0
  4. package/dist/cjs/basic-chart/basic-chart.d.ts +1 -1
  5. package/dist/cjs/basic-chart/basic-chart.d.ts.map +1 -1
  6. package/dist/cjs/basic-chart/basic-chart.js +863 -371
  7. package/dist/cjs/components/dialogs/pivot-chart-dialog.d.ts +39 -0
  8. package/dist/cjs/components/dialogs/pivot-chart-dialog.d.ts.map +1 -0
  9. package/dist/cjs/components/dialogs/pivot-chart-dialog.js +100 -0
  10. package/dist/cjs/components/editors/chart-editor.d.ts +13 -1
  11. package/dist/cjs/components/editors/chart-editor.d.ts.map +1 -1
  12. package/dist/cjs/components/editors/chart-editor.js +225 -59
  13. package/dist/cjs/config.d.ts.map +1 -1
  14. package/dist/cjs/config.js +149 -12
  15. package/dist/cjs/hooks/use-charts.d.ts +21 -6
  16. package/dist/cjs/hooks/use-charts.d.ts.map +1 -1
  17. package/dist/cjs/hooks/use-charts.js +13 -1
  18. package/dist/cjs/hooks/use-on-create-chart.d.ts.map +1 -1
  19. package/dist/cjs/hooks/use-on-create-chart.js +7 -1
  20. package/dist/cjs/hooks/use-on-move-chart-to-sheet.d.ts +12 -0
  21. package/dist/cjs/hooks/use-on-move-chart-to-sheet.d.ts.map +1 -0
  22. package/dist/cjs/hooks/use-on-move-chart-to-sheet.js +26 -0
  23. package/dist/cjs/hooks/use-on-move-chart.d.ts +1 -1
  24. package/dist/cjs/hooks/use-on-move-chart.d.ts.map +1 -1
  25. package/dist/cjs/hooks/use-on-move-chart.js +2 -2
  26. package/dist/cjs/hooks/use-on-resize-chart.d.ts +1 -1
  27. package/dist/cjs/hooks/use-on-resize-chart.d.ts.map +1 -1
  28. package/dist/cjs/hooks/use-on-resize-chart.js +2 -2
  29. package/dist/cjs/index.d.ts +11 -0
  30. package/dist/cjs/index.d.ts.map +1 -1
  31. package/dist/cjs/index.js +34 -1
  32. package/dist/cjs/interface/create-chart.d.ts.map +1 -1
  33. package/dist/cjs/interface/create-chart.js +33 -42
  34. package/dist/cjs/interface/delete-chart.d.ts.map +1 -1
  35. package/dist/cjs/interface/delete-chart.js +4 -0
  36. package/dist/cjs/interface/move-chart-to-sheet.d.ts +13 -0
  37. package/dist/cjs/interface/move-chart-to-sheet.d.ts.map +1 -0
  38. package/dist/cjs/interface/move-chart-to-sheet.js +136 -0
  39. package/dist/cjs/interface/move-chart.d.ts +2 -2
  40. package/dist/cjs/interface/move-chart.d.ts.map +1 -1
  41. package/dist/cjs/interface/move-chart.js +7 -1
  42. package/dist/cjs/interface/resize-chart.d.ts +2 -2
  43. package/dist/cjs/interface/resize-chart.d.ts.map +1 -1
  44. package/dist/cjs/interface/resize-chart.js +7 -1
  45. package/dist/cjs/interface/update-chart.d.ts.map +1 -1
  46. package/dist/cjs/interface/update-chart.js +4 -0
  47. package/dist/cjs/plotly/basic-chart/basic-chart.d.ts +1 -1
  48. package/dist/cjs/plotly/basic-chart/basic-chart.d.ts.map +1 -1
  49. package/dist/cjs/plotly/basic-chart/basic-chart.js +970 -585
  50. package/dist/cjs/plotly/basic-chart/helpers.d.ts.map +1 -1
  51. package/dist/cjs/plotly/basic-chart/helpers.js +3 -0
  52. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  53. package/dist/cjs/types.d.ts +7 -0
  54. package/dist/cjs/types.d.ts.map +1 -1
  55. package/dist/cjs/utils/axis-number-format.d.ts +69 -0
  56. package/dist/cjs/utils/axis-number-format.d.ts.map +1 -0
  57. package/dist/cjs/utils/axis-number-format.js +217 -0
  58. package/dist/cjs/utils/category-levels.d.ts +27 -0
  59. package/dist/cjs/utils/category-levels.d.ts.map +1 -0
  60. package/dist/cjs/utils/category-levels.js +80 -0
  61. package/dist/cjs/utils/chart-image.d.ts +8 -0
  62. package/dist/cjs/utils/chart-image.d.ts.map +1 -0
  63. package/dist/cjs/utils/chart-image.js +28 -0
  64. package/dist/cjs/utils/chart-orientation.d.ts +67 -0
  65. package/dist/cjs/utils/chart-orientation.d.ts.map +1 -0
  66. package/dist/cjs/utils/chart-orientation.js +265 -0
  67. package/dist/cjs/utils/chart-spec-utils.d.ts +3 -0
  68. package/dist/cjs/utils/chart-spec-utils.d.ts.map +1 -1
  69. package/dist/cjs/utils/chart-spec-utils.js +12 -4
  70. package/dist/cjs/utils/chart-styles.d.ts +75 -0
  71. package/dist/cjs/utils/chart-styles.d.ts.map +1 -0
  72. package/dist/cjs/utils/chart-styles.js +283 -0
  73. package/dist/cjs/utils/empty-cells.d.ts +30 -0
  74. package/dist/cjs/utils/empty-cells.d.ts.map +1 -0
  75. package/dist/cjs/utils/empty-cells.js +91 -0
  76. package/dist/cjs/utils/overrides.d.ts +6 -1
  77. package/dist/cjs/utils/overrides.d.ts.map +1 -1
  78. package/dist/cjs/utils/overrides.js +19 -7
  79. package/dist/cjs/utils/pie-explosion.d.ts +30 -0
  80. package/dist/cjs/utils/pie-explosion.d.ts.map +1 -0
  81. package/dist/cjs/utils/pie-explosion.js +55 -0
  82. package/dist/cjs/utils/plotly-click.d.ts +34 -0
  83. package/dist/cjs/utils/plotly-click.d.ts.map +1 -0
  84. package/dist/cjs/utils/plotly-click.js +49 -0
  85. package/dist/cjs/utils/plotly-surface.d.ts +14 -0
  86. package/dist/cjs/utils/plotly-surface.d.ts.map +1 -0
  87. package/dist/cjs/utils/plotly-surface.js +64 -0
  88. package/dist/cjs/utils/plotly-title.d.ts +12 -0
  89. package/dist/cjs/utils/plotly-title.d.ts.map +1 -0
  90. package/dist/cjs/utils/plotly-title.js +24 -0
  91. package/dist/cjs/utils/series-click.d.ts +39 -0
  92. package/dist/cjs/utils/series-click.d.ts.map +1 -0
  93. package/dist/cjs/utils/series-click.js +75 -0
  94. package/dist/cjs/utils/three-d.d.ts +17 -1
  95. package/dist/cjs/utils/three-d.d.ts.map +1 -1
  96. package/dist/cjs/utils/three-d.js +32 -4
  97. package/dist/esm/atoms/pivot-chart.atom.d.ts +14 -0
  98. package/dist/esm/atoms/pivot-chart.atom.d.ts.map +1 -0
  99. package/dist/esm/atoms/pivot-chart.atom.js +4 -0
  100. package/dist/esm/basic-chart/basic-chart.d.ts +1 -1
  101. package/dist/esm/basic-chart/basic-chart.d.ts.map +1 -1
  102. package/dist/esm/basic-chart/basic-chart.js +680 -178
  103. package/dist/esm/components/dialogs/pivot-chart-dialog.d.ts +39 -0
  104. package/dist/esm/components/dialogs/pivot-chart-dialog.d.ts.map +1 -0
  105. package/dist/esm/components/dialogs/pivot-chart-dialog.js +89 -0
  106. package/dist/esm/components/editors/chart-editor.d.ts +13 -1
  107. package/dist/esm/components/editors/chart-editor.d.ts.map +1 -1
  108. package/dist/esm/components/editors/chart-editor.js +164 -20
  109. package/dist/esm/config.d.ts.map +1 -1
  110. package/dist/esm/config.js +149 -12
  111. package/dist/esm/hooks/use-charts.d.ts +21 -6
  112. package/dist/esm/hooks/use-charts.d.ts.map +1 -1
  113. package/dist/esm/hooks/use-charts.js +13 -1
  114. package/dist/esm/hooks/use-on-create-chart.d.ts.map +1 -1
  115. package/dist/esm/hooks/use-on-create-chart.js +7 -1
  116. package/dist/esm/hooks/use-on-move-chart-to-sheet.d.ts +12 -0
  117. package/dist/esm/hooks/use-on-move-chart-to-sheet.d.ts.map +1 -0
  118. package/dist/esm/hooks/use-on-move-chart-to-sheet.js +19 -0
  119. package/dist/esm/hooks/use-on-move-chart.d.ts +1 -1
  120. package/dist/esm/hooks/use-on-move-chart.d.ts.map +1 -1
  121. package/dist/esm/hooks/use-on-move-chart.js +2 -2
  122. package/dist/esm/hooks/use-on-resize-chart.d.ts +1 -1
  123. package/dist/esm/hooks/use-on-resize-chart.d.ts.map +1 -1
  124. package/dist/esm/hooks/use-on-resize-chart.js +2 -2
  125. package/dist/esm/index.d.ts +11 -0
  126. package/dist/esm/index.d.ts.map +1 -1
  127. package/dist/esm/index.js +14 -0
  128. package/dist/esm/interface/create-chart.d.ts.map +1 -1
  129. package/dist/esm/interface/create-chart.js +36 -58
  130. package/dist/esm/interface/delete-chart.d.ts.map +1 -1
  131. package/dist/esm/interface/delete-chart.js +4 -0
  132. package/dist/esm/interface/move-chart-to-sheet.d.ts +13 -0
  133. package/dist/esm/interface/move-chart-to-sheet.d.ts.map +1 -0
  134. package/dist/esm/interface/move-chart-to-sheet.js +126 -0
  135. package/dist/esm/interface/move-chart.d.ts +2 -2
  136. package/dist/esm/interface/move-chart.d.ts.map +1 -1
  137. package/dist/esm/interface/move-chart.js +7 -1
  138. package/dist/esm/interface/resize-chart.d.ts +2 -2
  139. package/dist/esm/interface/resize-chart.d.ts.map +1 -1
  140. package/dist/esm/interface/resize-chart.js +7 -1
  141. package/dist/esm/interface/update-chart.d.ts.map +1 -1
  142. package/dist/esm/interface/update-chart.js +4 -0
  143. package/dist/esm/plotly/basic-chart/basic-chart.d.ts +1 -1
  144. package/dist/esm/plotly/basic-chart/basic-chart.d.ts.map +1 -1
  145. package/dist/esm/plotly/basic-chart/basic-chart.js +858 -463
  146. package/dist/esm/plotly/basic-chart/helpers.d.ts.map +1 -1
  147. package/dist/esm/plotly/basic-chart/helpers.js +3 -0
  148. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  149. package/dist/esm/types.d.ts +7 -0
  150. package/dist/esm/types.d.ts.map +1 -1
  151. package/dist/esm/utils/axis-number-format.d.ts +69 -0
  152. package/dist/esm/utils/axis-number-format.d.ts.map +1 -0
  153. package/dist/esm/utils/axis-number-format.js +170 -0
  154. package/dist/esm/utils/category-levels.d.ts +27 -0
  155. package/dist/esm/utils/category-levels.d.ts.map +1 -0
  156. package/dist/esm/utils/category-levels.js +65 -0
  157. package/dist/esm/utils/chart-image.d.ts +8 -0
  158. package/dist/esm/utils/chart-image.d.ts.map +1 -0
  159. package/dist/esm/utils/chart-image.js +24 -0
  160. package/dist/esm/utils/chart-orientation.d.ts +67 -0
  161. package/dist/esm/utils/chart-orientation.d.ts.map +1 -0
  162. package/dist/esm/utils/chart-orientation.js +234 -0
  163. package/dist/esm/utils/chart-spec-utils.d.ts +3 -0
  164. package/dist/esm/utils/chart-spec-utils.d.ts.map +1 -1
  165. package/dist/esm/utils/chart-spec-utils.js +10 -2
  166. package/dist/esm/utils/chart-styles.d.ts +75 -0
  167. package/dist/esm/utils/chart-styles.d.ts.map +1 -0
  168. package/dist/esm/utils/chart-styles.js +357 -0
  169. package/dist/esm/utils/empty-cells.d.ts +30 -0
  170. package/dist/esm/utils/empty-cells.d.ts.map +1 -0
  171. package/dist/esm/utils/empty-cells.js +67 -0
  172. package/dist/esm/utils/overrides.d.ts +6 -1
  173. package/dist/esm/utils/overrides.d.ts.map +1 -1
  174. package/dist/esm/utils/overrides.js +14 -2
  175. package/dist/esm/utils/pie-explosion.d.ts +30 -0
  176. package/dist/esm/utils/pie-explosion.d.ts.map +1 -0
  177. package/dist/esm/utils/pie-explosion.js +43 -0
  178. package/dist/esm/utils/plotly-click.d.ts +34 -0
  179. package/dist/esm/utils/plotly-click.d.ts.map +1 -0
  180. package/dist/esm/utils/plotly-click.js +44 -0
  181. package/dist/esm/utils/plotly-surface.d.ts +14 -0
  182. package/dist/esm/utils/plotly-surface.d.ts.map +1 -0
  183. package/dist/esm/utils/plotly-surface.js +45 -0
  184. package/dist/esm/utils/plotly-title.d.ts +12 -0
  185. package/dist/esm/utils/plotly-title.d.ts.map +1 -0
  186. package/dist/esm/utils/plotly-title.js +20 -0
  187. package/dist/esm/utils/series-click.d.ts +39 -0
  188. package/dist/esm/utils/series-click.d.ts.map +1 -0
  189. package/dist/esm/utils/series-click.js +66 -0
  190. package/dist/esm/utils/three-d.d.ts +17 -1
  191. package/dist/esm/utils/three-d.d.ts.map +1 -1
  192. package/dist/esm/utils/three-d.js +29 -3
  193. package/package.json +10 -6
@@ -0,0 +1,39 @@
1
+ import type { CellInterface } from "@rowsncolumns/common-types";
2
+ import type { PivotTable } from "@rowsncolumns/spreadsheet";
3
+ import React from "react";
4
+ import { type PivotChartRequest } from "../../atoms/pivot-chart.atom";
5
+ /**
6
+ * What the PivotChart dialog hands back: bind to an existing pivot, or
7
+ * create `newPivotTable` first (Excel's Insert → PivotChart on a plain
8
+ * range creates an empty PivotTable and an empty PivotChart side by side;
9
+ * both fill in as fields are added). `anchorCell` is where the chart frame
10
+ * goes — to the right of a new pivot, at the active cell otherwise.
11
+ */
12
+ export type PivotChartSubmission = {
13
+ sheetId: number;
14
+ anchorCell: CellInterface;
15
+ } & ({
16
+ pivotId: PivotTable["pivotId"];
17
+ } | {
18
+ newPivotTable: PivotTable;
19
+ });
20
+ /** Excel names pivots `PivotTable1`, `PivotTable2`, …; unnamed ones show that way. */
21
+ export declare const pivotTableLabel: (pivot: PivotTable, index: number) => string;
22
+ export type PivotChartPickerProps = {
23
+ request: PivotChartRequest;
24
+ pivotTables: PivotTable[];
25
+ onSubmit(submission: PivotChartSubmission): void;
26
+ onClose(): void;
27
+ };
28
+ export declare const PivotChartPicker: ({ request, pivotTables, onSubmit, onClose, }: PivotChartPickerProps) => React.JSX.Element;
29
+ export type PivotChartDialogProps = {
30
+ pivotTables: PivotTable[];
31
+ onSubmit(submission: PivotChartSubmission): void;
32
+ };
33
+ export declare const PivotChartDialog: ({ pivotTables, onSubmit, }: PivotChartDialogProps) => React.JSX.Element;
34
+ /**
35
+ * The grid's `onRequestCreatePivotChart`: a request from a pivot's own
36
+ * context menu binds straight away; Insert → PivotChart opens the dialog.
37
+ */
38
+ export declare const useRequestCreatePivotChart: (onSubmit: (submission: PivotChartSubmission) => void) => (sheetId: number, activeCell: CellInterface, selections: PivotChartRequest["selections"], pivotId?: PivotTable["pivotId"]) => void;
39
+ //# sourceMappingURL=pivot-chart-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pivot-chart-dialog.d.ts","sourceRoot":"","sources":["../../../../components/dialogs/pivot-chart-dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAY5D,OAAO,KAAgC,MAAM,OAAO,CAAC;AAErD,OAAO,EACL,KAAK,iBAAiB,EAGvB,MAAM,8BAA8B,CAAC;AAEtC;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,aAAa,CAAC;CAC3B,GAAG,CAAC;IAAE,OAAO,EAAE,UAAU,CAAC,SAAS,CAAC,CAAA;CAAE,GAAG;IAAE,aAAa,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC;AAEzE,sFAAsF;AACtF,eAAO,MAAM,eAAe,GAAI,OAAO,UAAU,EAAE,OAAO,MAAM,WAChB,CAAC;AAOjD,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACjD,OAAO,IAAI,IAAI,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,8CAK9B,qBAAqB,sBAmFvB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAClD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,4BAG9B,qBAAqB,sBA8BvB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GACrC,UAAU,CAAC,UAAU,EAAE,oBAAoB,KAAK,IAAI,eAKvC,MAAM,cACH,aAAa,cACb,iBAAiB,CAAC,YAAY,CAAC,YACjC,UAAU,CAAC,SAAS,CAAC,SAUpC,CAAC"}
@@ -0,0 +1,89 @@
1
+ import { Cross2Icon } from "@rowsncolumns/icons";
2
+ import { useFocusSheet } from "@rowsncolumns/spreadsheet";
3
+ import { Button, Dialog, DialogBody, DialogCloseButton, DialogContent, DialogTitle, Stack, } from "@rowsncolumns/ui";
4
+ import { uuidString } from "@rowsncolumns/utils";
5
+ import React, { useCallback, useState } from "react";
6
+ import { usePivotChartRequest, useSetPivotChartRequest, } from "../../atoms/pivot-chart.atom";
7
+ /** Excel names pivots `PivotTable1`, `PivotTable2`, …; unnamed ones show that way. */
8
+ export const pivotTableLabel = (pivot, index) => pivot.name?.trim() || `PivotTable${index + 1}`;
9
+ const NEW_PIVOT = "__new__";
10
+ /** Columns between a new pivot's top-left cell and its PivotChart's anchor. */
11
+ const CHART_GAP_COLUMNS = 4;
12
+ export const PivotChartPicker = ({ request, pivotTables, onSubmit, onClose, }) => {
13
+ const { sheetId, activeCell, selections } = request;
14
+ const selection = selections[selections.length - 1]?.range;
15
+ const canCreate = selection !== undefined;
16
+ const [choice, setChoice] = useState(pivotTables.length
17
+ ? String(pivotTables[0].pivotId)
18
+ : canCreate
19
+ ? NEW_PIVOT
20
+ : "");
21
+ const submit = (event) => {
22
+ event.preventDefault();
23
+ if (choice === NEW_PIVOT && selection) {
24
+ onSubmit({
25
+ sheetId,
26
+ anchorCell: {
27
+ rowIndex: activeCell.rowIndex,
28
+ columnIndex: activeCell.columnIndex + CHART_GAP_COLUMNS,
29
+ },
30
+ newPivotTable: {
31
+ pivotId: uuidString(),
32
+ rows: [],
33
+ columns: [],
34
+ values: [],
35
+ source: { ...selection, sheetId },
36
+ targetPosition: { ...activeCell, sheetId },
37
+ },
38
+ });
39
+ }
40
+ else {
41
+ const pivot = pivotTables.find((p) => String(p.pivotId) === choice);
42
+ if (!pivot)
43
+ return;
44
+ onSubmit({ sheetId, anchorCell: activeCell, pivotId: pivot.pivotId });
45
+ }
46
+ onClose();
47
+ };
48
+ return (React.createElement("form", { onSubmit: submit },
49
+ React.createElement(Stack, { direction: "vertical", className: "pb-2 gap-2" },
50
+ React.createElement("div", { className: "font-system text-sm" }, "Choose the PivotTable to chart"),
51
+ React.createElement(Stack, { direction: "vertical", className: "gap-1", role: "radiogroup" },
52
+ pivotTables.map((pivot, index) => (React.createElement("label", { key: String(pivot.pivotId), className: "font-system text-sm items-center flex gap-1" },
53
+ React.createElement("input", { type: "radio", name: "pivot", className: "m-0", value: String(pivot.pivotId), checked: choice === String(pivot.pivotId), onChange: () => setChoice(String(pivot.pivotId)) }),
54
+ pivotTableLabel(pivot, index)))),
55
+ React.createElement("label", { className: "font-system text-sm items-center flex gap-1" },
56
+ React.createElement("input", { type: "radio", name: "pivot", className: "m-0", value: NEW_PIVOT, disabled: !canCreate, checked: choice === NEW_PIVOT, onChange: () => setChoice(NEW_PIVOT) }),
57
+ "New PivotTable from the current selection"))),
58
+ React.createElement("div", { className: "flex gap-1 pt-2" },
59
+ React.createElement(Button, { type: "submit", variant: "primary", size: "xs", disabled: !choice }, "Insert"),
60
+ React.createElement(Button, { size: "xs", type: "button", onClick: onClose }, "Cancel"))));
61
+ };
62
+ export const PivotChartDialog = ({ pivotTables, onSubmit, }) => {
63
+ const [request, setRequest] = usePivotChartRequest();
64
+ const focusSheet = useFocusSheet();
65
+ const closeDialog = () => {
66
+ setRequest(undefined);
67
+ focusSheet?.();
68
+ };
69
+ return (React.createElement(Dialog, { modal: false, open: request !== undefined },
70
+ React.createElement(DialogContent, { onEscapeKeyDown: closeDialog, className: "translate-y-1/2" },
71
+ React.createElement(DialogTitle, { className: "rnc-drag-handle cursor-move" }, "Insert PivotChart"),
72
+ React.createElement(DialogBody, null, request ? (React.createElement(PivotChartPicker, { key: `${request.sheetId}:${request.activeCell.rowIndex}:${request.activeCell.columnIndex}`, request: request, pivotTables: pivotTables, onSubmit: onSubmit, onClose: closeDialog })) : null),
73
+ React.createElement(DialogCloseButton, { onClick: closeDialog },
74
+ React.createElement(Cross2Icon, null)))));
75
+ };
76
+ /**
77
+ * The grid's `onRequestCreatePivotChart`: a request from a pivot's own
78
+ * context menu binds straight away; Insert → PivotChart opens the dialog.
79
+ */
80
+ export const useRequestCreatePivotChart = (onSubmit) => {
81
+ const setRequest = useSetPivotChartRequest();
82
+ return useCallback((sheetId, activeCell, selections, pivotId) => {
83
+ if (pivotId !== undefined) {
84
+ onSubmit({ sheetId, anchorCell: activeCell, pivotId });
85
+ return;
86
+ }
87
+ setRequest({ sheetId, activeCell, selections });
88
+ }, [onSubmit, setRequest]);
89
+ };
@@ -1,10 +1,22 @@
1
1
  import type { EmbeddedChart } from "@rowsncolumns/spreadsheet";
2
2
  import React from "react";
3
+ import { type ChartCellLabelGetter } from "../../utils/chart-orientation";
3
4
  type ChartEditorProps = {
4
5
  chart?: EmbeddedChart;
5
6
  sheetId: number;
6
7
  onSubmit?(chart: EmbeddedChart): void;
8
+ /**
9
+ * Excel's "Move Chart…" (Design → Move Chart): offered as a button in the
10
+ * Properties section when provided — the host opens its dialog (e.g.
11
+ * `useOpenMoveChartDialog`).
12
+ */
13
+ onRequestMoveChart?(chart: EmbeddedChart): void;
14
+ /**
15
+ * Formatted cell text — names the series Switch Row/Column derives
16
+ * from the data range. Without it the switched series are unnamed.
17
+ */
18
+ getFormattedValue?: ChartCellLabelGetter;
7
19
  };
8
- export declare const ChartEditor: ({ chart, sheetId, onSubmit }: ChartEditorProps) => React.JSX.Element;
20
+ export declare const ChartEditor: ({ chart, sheetId, onSubmit, onRequestMoveChart, getFormattedValue, }: ChartEditorProps) => React.JSX.Element;
9
21
  export default ChartEditor;
10
22
  //# sourceMappingURL=chart-editor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-editor.d.ts","sourceRoot":"","sources":["../../../../components/editors/chart-editor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,aAAa,EAEd,MAAM,2BAA2B,CAAC;AAuBnC,OAAO,KAAkB,MAAM,OAAO,CAAC;AAuBvC,KAAK,gBAAgB,GAAG;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;CACvC,CAAC;AAuBF,eAAO,MAAM,WAAW,GAAI,8BAA8B,gBAAgB,sBAo9CzE,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"chart-editor.d.ts","sourceRoot":"","sources":["../../../../components/editors/chart-editor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,aAAa,EAGd,MAAM,2BAA2B,CAAC;AAuBnC,OAAO,KAAkB,MAAM,OAAO,CAAC;AAMvC,OAAO,EAEL,KAAK,oBAAoB,EAG1B,MAAM,+BAA+B,CAAC;AA4CvC,KAAK,gBAAgB,GAAG;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC;;;;OAIG;IACH,kBAAkB,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAChD;;;OAGG;IACH,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;CAC1C,CAAC;AAuBF,eAAO,MAAM,WAAW,GAAI,sEAMzB,gBAAgB,sBA+5DlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -9,7 +9,9 @@ import { useSetChartEditorDialogState } from "../../atoms/editing-chart.atom";
9
9
  import { ChartRangeInput } from "./chart-range-input";
10
10
  import { CHART_TYPES, getChartPresetLabel } from "../../config";
11
11
  import { uuid } from "@rowsncolumns/utils";
12
+ import { canSwitchRowColumn, inferSeriesOrientation, switchRowColumn, } from "../../utils/chart-orientation";
12
13
  import { isBasicChartSpec, isBubbleChartSpec, isHierarchyChartSpec, mergeChartSpec, } from "../../utils/chart-spec-utils";
14
+ import { applyChartColorPalette, applyChartQuickLayout, applyChartStyle, CHART_COLOR_PALETTES, CHART_QUICK_LAYOUTS, CHART_STYLES, resetChartToMatchStyle, } from "../../utils/chart-styles";
13
15
  const AGGREGATE_OPTIONS = [
14
16
  { label: "Sum", value: "SUM" },
15
17
  { label: "Average", value: "AVERAGE" },
@@ -18,12 +20,27 @@ const AGGREGATE_OPTIONS = [
18
20
  { label: "Min", value: "MIN" },
19
21
  { label: "Max", value: "MAX" },
20
22
  ];
23
+ /** Swatch for the theme-accent palette tile (the theme itself is resolved at render time). */
24
+ const THEME_PALETTE_PREVIEW = [
25
+ "#4472C4",
26
+ "#ED7D31",
27
+ "#A5A5A5",
28
+ "#FFC000",
29
+ "#5B9BD5",
30
+ "#70AD47",
31
+ ];
32
+ /** Excel's placement modes, in the order its Properties pane lists them. */
33
+ const CHART_PLACEMENT_OPTIONS = [
34
+ { label: "Move and size with cells", value: "moveAndSize" },
35
+ { label: "Move but don't size with cells", value: "moveOnly" },
36
+ { label: "Don't move or size with cells", value: "absolute" },
37
+ ];
21
38
  const Section = ({ title, defaultOpen = false, children, }) => (React.createElement("details", { open: defaultOpen, className: "group border border-rnc-border border-solid rounded-md mb-2 px-3" },
22
39
  React.createElement("summary", { className: "flex items-center gap-1.5 cursor-pointer list-none py-2 font-system text-sm font-medium select-none [&::-webkit-details-marker]:hidden" },
23
40
  React.createElement(ChevronRightIcon, { className: "shrink-0 transition-transform group-open:rotate-90" }),
24
41
  title),
25
42
  React.createElement("div", { className: "flex flex-col gap-2 pb-3" }, children)));
26
- export const ChartEditor = ({ chart, sheetId, onSubmit }) => {
43
+ export const ChartEditor = ({ chart, sheetId, onSubmit, onRequestMoveChart, getFormattedValue, }) => {
27
44
  const setChartDialogState = useSetChartEditorDialogState();
28
45
  // Close dialog
29
46
  const closeDialog = () => setChartDialogState(false);
@@ -45,8 +62,20 @@ export const ChartEditor = ({ chart, sheetId, onSubmit }) => {
45
62
  enableReinitialize: true,
46
63
  onSubmit(values) {
47
64
  // Submit against the live position so edits do not revert a
48
- // chart moved or resized while the editor was open.
49
- onSubmit?.(chart ? { ...values, position: chart.position } : values);
65
+ // chart moved or resized while the editor was open; the placement
66
+ // mode is the one property of the position the form owns.
67
+ onSubmit?.(chart
68
+ ? {
69
+ ...values,
70
+ position: {
71
+ ...chart.position,
72
+ overlayPosition: {
73
+ ...chart.position.overlayPosition,
74
+ placement: values.position.overlayPosition.placement,
75
+ },
76
+ },
77
+ }
78
+ : values);
50
79
  // Close dialog
51
80
  closeDialog();
52
81
  },
@@ -74,6 +103,19 @@ export const ChartEditor = ({ chart, sheetId, onSubmit }) => {
74
103
  const isBarOrColumnBasic = basicSpec
75
104
  ? basicSpec.chartType === "bar" || basicSpec.chartType === "column"
76
105
  : false;
106
+ // Customize → "Chart options": each control names the chart types it
107
+ // applies to and the section renders when any of them does, so a chart type
108
+ // is never left out by a separately maintained list (pie was, until #783).
109
+ const chartOptionControls = {
110
+ binCount: basicSpec?.chartType === "histogram",
111
+ radarStyle: basicSpec?.chartType === "radar",
112
+ stockVariant: basicSpec?.chartType === "stock",
113
+ doughnutHoleSize: basicSpec?.chartType === "doughnut",
114
+ explosion: basicSpec?.chartType === "pie" || basicSpec?.chartType === "doughnut",
115
+ gapWidth: isBarOrColumnBasic,
116
+ overlap: isBarOrColumnBasic,
117
+ };
118
+ const showChartOptions = Object.values(chartOptionControls).some(Boolean);
77
119
  // Check aggregate
78
120
  const isAggregateType = basicSpec
79
121
  ? basicSpec.series.some((serie) => serie.aggregateType)
@@ -125,9 +167,23 @@ export const ChartEditor = ({ chart, sheetId, onSubmit }) => {
125
167
  }))))),
126
168
  React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
127
169
  React.createElement("label", { className: "font-system text-sm" }, "Chart data range"),
128
- React.createElement(ChartRangeInput, { key: values.chartId, sheetId: sheetId, range: values.spec?.dataRange ?? undefined, onChangeRange: (range) => {
170
+ values.spec?.pivotTableId != null ? (
171
+ // A PivotChart's range follows its pivot's data area; it is not
172
+ // editable here (Excel greys the range on a PivotChart too).
173
+ React.createElement("span", { className: "font-system text-xs text-rnc-muted-foreground" }, "Bound to PivotTable \u2014 the data range follows the pivot.")) : (React.createElement(ChartRangeInput, { key: values.chartId, sheetId: sheetId, range: values.spec?.dataRange ?? undefined, onChangeRange: (range) => {
129
174
  setFieldValue("spec.dataRange", range);
130
- }, required: true, placeholder: "Select a range", className: "mb-0" })),
175
+ }, required: true, placeholder: "Select a range", className: "mb-0" }))),
176
+ basicSpec ? (React.createElement(Stack, { direction: "horizontal", className: "gap-2 pb-2 items-center" },
177
+ React.createElement(Button, { type: "button", variant: "outline", size: "xs", disabled: !canSwitchRowColumn(values.spec), onClick: () => {
178
+ const next = switchRowColumn(values.spec, {
179
+ getFormattedValue,
180
+ });
181
+ if (next)
182
+ setFieldValue("spec", next);
183
+ } }, "Switch Row/Column"),
184
+ React.createElement("span", { className: "font-system text-xs text-rnc-muted-foreground" },
185
+ "Series in ",
186
+ inferSeriesOrientation(values.spec)))) : null,
131
187
  basicSpec ? (React.createElement(React.Fragment, null,
132
188
  React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
133
189
  React.createElement("label", { className: "font-system text-sm" }, "Horizontal (category) axis labels"),
@@ -376,6 +432,21 @@ export const ChartEditor = ({ chart, sheetId, onSubmit }) => {
376
432
  renderChartDataSection("Labels", "labels", treemapSpec.labels ?? [], "Select the cells that contain node labels."),
377
433
  renderChartDataSection("Parent labels", "parentLabels", treemapSpec.parentLabels ?? [], "Choose the cells that define each node's parent label."),
378
434
  renderChartDataSection("Size data", "sizeData", treemapSpec.sizeData ?? [], "Provide numeric values to determine each node's size."))) : null,
435
+ basicSpec ? (React.createElement(React.Fragment, null,
436
+ React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2 w-56" },
437
+ React.createElement("label", { className: "font-system text-sm" }, "Show empty cells as"),
438
+ React.createElement("select", { className: "border border-rnc-border rounded-sm px-1 py-1 text-xs bg-transparent", "aria-label": "Show empty cells as", value: values.spec.emptyCells ?? "gaps", onChange: (event) => {
439
+ const emptyCells = event.target.value;
440
+ setFieldValue("spec.emptyCells", emptyCells === "gaps" ? undefined : emptyCells);
441
+ } },
442
+ React.createElement("option", { value: "gaps" }, "Gaps"),
443
+ React.createElement("option", { value: "zero" }, "Zero"),
444
+ React.createElement("option", { value: "connect" }, "Connect data points with line"))),
445
+ React.createElement("label", { className: "font-system text-sm flex items-center gap-1" },
446
+ React.createElement("input", { type: "checkbox", checked: values.spec.showNaAsEmpty !== false, onChange: (e) => {
447
+ setFieldValue("spec.showNaAsEmpty", e.target.checked ? undefined : false);
448
+ } }),
449
+ "Show #N/A as an empty cell"))) : null,
379
450
  React.createElement("label", { className: "font-system text-sm flex items-center gap-1" },
380
451
  React.createElement("input", { type: "checkbox", checked: values.spec.hiddenDimensionStrategy === "SHOW_ALL", name: "showColumnStripes", onChange: (e) => {
381
452
  setFieldValue("spec.hiddenDimensionStrategy", e.target.checked
@@ -387,7 +458,68 @@ export const ChartEditor = ({ chart, sheetId, onSubmit }) => {
387
458
  React.createElement(Section, { title: "Chart style", defaultOpen: true },
388
459
  React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
389
460
  React.createElement("label", { className: "font-system text-sm" }, "Chart title"),
390
- React.createElement(Input, { value: values?.spec.title ?? "", type: "text", onChange: (e) => setFieldValue(`spec.title`, e.target.value), className: "text-xs", placeholder: "Enter chart title" }))),
461
+ React.createElement(Input, { value: values?.spec.title ?? "", type: "text", onChange: (e) => setFieldValue(`spec.title`, e.target.value), className: "text-xs", placeholder: "Enter chart title" })),
462
+ React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
463
+ React.createElement("label", { className: "font-system text-sm" }, "Style"),
464
+ React.createElement("div", { className: "grid grid-cols-4 gap-1", role: "radiogroup" }, CHART_STYLES.map((style) => {
465
+ const isActive = values.spec.chartStyle === style.id;
466
+ return (React.createElement("button", { key: style.id, type: "button", role: "radio", "aria-checked": isActive, "aria-label": style.label, title: style.label, onClick: () => setFieldValue("spec", applyChartStyle(values.spec, style)), className: `flex items-end justify-center gap-0.5 h-8 rounded-sm border border-solid p-1 ${isActive
467
+ ? "border-rnc-primary"
468
+ : "border-rnc-border"}`, style: { background: style.preview.background } }, style.preview.bars.map((color, i) => (React.createElement("span", { key: `${style.id}-${i}`, className: "w-1.5 rounded-[1px]", style: { height: 6 + i * 4, background: color } })))));
469
+ }))),
470
+ React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
471
+ React.createElement("label", { className: "font-system text-sm" }, "Colors"),
472
+ React.createElement("div", { className: "flex flex-col gap-1", role: "radiogroup" }, CHART_COLOR_PALETTES.map((palette) => {
473
+ const current = values.spec.palette ?? undefined;
474
+ const isActive = palette.colors
475
+ ? !!current &&
476
+ current.length === palette.colors.length &&
477
+ current.every((c, i) => c === palette.colors?.[i])
478
+ : !current || current.length === 0;
479
+ return (React.createElement("button", { key: palette.id, type: "button", role: "radio", "aria-checked": isActive, "aria-label": palette.label, title: palette.label, onClick: () => setFieldValue("spec", applyChartColorPalette(values.spec, palette)), className: `flex items-center gap-1 rounded-sm border border-solid px-1 py-0.5 ${isActive ? "border-rnc-primary" : "border-rnc-border"}` },
480
+ (palette.colors ?? THEME_PALETTE_PREVIEW).map((color, i) => (React.createElement("span", { key: `${palette.id}-${i}`, className: "h-3 w-3 rounded-[1px]", style: { background: color } }))),
481
+ React.createElement("span", { className: "font-system text-xs text-rnc-text-weak" }, palette.label)));
482
+ }))),
483
+ React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
484
+ React.createElement("label", { className: "font-system text-sm" }, "Quick layout"),
485
+ React.createElement("select", { className: "border border-rnc-border rounded-sm px-1 py-1 text-xs bg-transparent w-32", value: "", "aria-label": "Quick layout", onChange: (e) => {
486
+ const layout = CHART_QUICK_LAYOUTS.find((entry) => String(entry.id) === e.target.value);
487
+ if (layout) {
488
+ setFieldValue("spec", applyChartQuickLayout(values.spec, layout));
489
+ }
490
+ } },
491
+ React.createElement("option", { value: "" }, "Choose a layout\u2026"),
492
+ CHART_QUICK_LAYOUTS.map((layout) => (React.createElement("option", { key: layout.id, value: layout.id }, layout.label))))),
493
+ React.createElement("div", null,
494
+ React.createElement(Button, { type: "button", size: "xs", onClick: () => setFieldValue("spec", resetChartToMatchStyle(values.spec)) }, "Reset to match style")),
495
+ React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
496
+ React.createElement("label", { className: "font-system text-sm" }, "Title font"),
497
+ React.createElement("div", { className: "flex items-center gap-1 flex-wrap" },
498
+ React.createElement(Input, { value: values.spec.titleTextFormat?.fontFamily ?? "", type: "text", onChange: (e) => setFieldValue("spec.titleTextFormat.fontFamily", e.target.value || undefined), className: "text-xs w-32", placeholder: "Font family", "aria-label": "Title font family" }),
499
+ React.createElement(Input, { value: values.spec.titleTextFormat?.fontSize ?? "", type: "number", min: 1, onChange: (e) => setFieldValue("spec.titleTextFormat.fontSize", e.target.value === "" ? undefined : Number(e.target.value)), className: "text-xs w-16", placeholder: "Size", "aria-label": "Title font size" }),
500
+ React.createElement("input", { type: "color", value: values.spec.titleTextFormat?.color ?? "#000000", onChange: (e) => setFieldValue("spec.titleTextFormat.color", e.target.value), className: "h-6 w-8 p-0 border border-rnc-border rounded-sm bg-transparent cursor-pointer", "aria-label": "Title color" }),
501
+ React.createElement("label", { className: "font-system text-xs flex items-center gap-1" },
502
+ React.createElement("input", { type: "checkbox", checked: Boolean(values.spec.titleTextFormat?.bold), onChange: (e) => setFieldValue("spec.titleTextFormat.bold", e.target.checked) }),
503
+ "Bold"),
504
+ React.createElement("label", { className: "font-system text-xs flex items-center gap-1" },
505
+ React.createElement("input", { type: "checkbox", checked: Boolean(values.spec.titleTextFormat?.italic), onChange: (e) => setFieldValue("spec.titleTextFormat.italic", e.target.checked) }),
506
+ "Italic")))),
507
+ React.createElement(Section, { title: "Chart area" },
508
+ React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
509
+ React.createElement("label", { className: "font-system text-sm" }, "Fill"),
510
+ React.createElement("div", { className: "flex items-center gap-1" },
511
+ React.createElement("input", { type: "color", value: values.spec.backgroundColor ?? "#FFFFFF", onChange: (e) => setFieldValue("spec.backgroundColor", e.target.value), className: "h-6 w-8 p-0 border border-rnc-border rounded-sm bg-transparent cursor-pointer", "aria-label": "Chart area fill" }),
512
+ values.spec.backgroundColor ? (React.createElement(IconButton, { type: "button", onClick: () => setFieldValue("spec.backgroundColor", undefined), "aria-label": "No fill", title: "No fill" },
513
+ React.createElement(CrossCircledIcon, null))) : (React.createElement("span", { className: "font-system text-xs text-rnc-text-weak" }, "Automatic")))),
514
+ React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
515
+ React.createElement("label", { className: "font-system text-sm" }, "Border"),
516
+ React.createElement("div", { className: "flex items-center gap-1" },
517
+ React.createElement("input", { type: "color", value: values.borderColor ?? "#D9D9D9", onChange: (e) => setFieldValue("borderColor", e.target.value), className: "h-6 w-8 p-0 border border-rnc-border rounded-sm bg-transparent cursor-pointer", "aria-label": "Chart area border" }),
518
+ values.borderColor ? (React.createElement(IconButton, { type: "button", onClick: () => setFieldValue("borderColor", undefined), "aria-label": "No border", title: "No border" },
519
+ React.createElement(CrossCircledIcon, null))) : (React.createElement("span", { className: "font-system text-xs text-rnc-text-weak" }, "None")))),
520
+ React.createElement("label", { className: "font-system text-sm flex items-center gap-1" },
521
+ React.createElement("input", { type: "checkbox", checked: Boolean(values.spec.roundedCorners), onChange: (e) => setFieldValue("spec.roundedCorners", e.target.checked) }),
522
+ "Rounded corners")),
391
523
  basicSpec ? (React.createElement(React.Fragment, null,
392
524
  React.createElement(Section, { title: "Legend" },
393
525
  React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
@@ -426,6 +558,9 @@ export const ChartEditor = ({ chart, sheetId, onSubmit }) => {
426
558
  React.createElement("input", { type: "checkbox", checked: values?.spec.valueAxisOptions?.showMajorGridlines !==
427
559
  false, onChange: (e) => setFieldValue("spec.valueAxisOptions.showMajorGridlines", e.target.checked) }),
428
560
  "Gridlines"),
561
+ React.createElement("label", { className: "font-system text-xs" }, "Number format"),
562
+ React.createElement(Input, { value: values?.spec.valueAxisOptions?.numberFormatPattern ??
563
+ "", type: "text", onChange: (e) => setFieldValue("spec.valueAxisOptions.numberFormatPattern", e.target.value || undefined), className: "text-xs w-32", placeholder: "Linked to source" }),
429
564
  basicSpec.series.some((s) => s.useSecondaryAxis) ? (React.createElement(React.Fragment, null,
430
565
  React.createElement("label", { className: "font-system text-sm pt-1" }, "Secondary value axis"),
431
566
  React.createElement("div", { className: "flex flex-wrap gap-2 items-end" },
@@ -448,7 +583,10 @@ export const ChartEditor = ({ chart, sheetId, onSubmit }) => {
448
583
  React.createElement("label", { className: "font-system text-xs flex items-center gap-1" },
449
584
  React.createElement("input", { type: "checkbox", checked: values?.spec.secondaryValueAxisOptions
450
585
  ?.showMajorGridlines !== false, onChange: (e) => setFieldValue("spec.secondaryValueAxisOptions.showMajorGridlines", e.target.checked) }),
451
- "Gridlines"))) : null)) : null),
586
+ "Gridlines"),
587
+ React.createElement("label", { className: "font-system text-xs" }, "Number format"),
588
+ React.createElement(Input, { value: values?.spec.secondaryValueAxisOptions
589
+ ?.numberFormatPattern ?? "", type: "text", onChange: (e) => setFieldValue("spec.secondaryValueAxisOptions.numberFormatPattern", e.target.value || undefined), className: "text-xs w-32", placeholder: "Linked to source" }))) : null)) : null),
452
590
  React.createElement(Section, { title: "Horizontal axis" },
453
591
  React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
454
592
  React.createElement("label", { className: "font-system text-sm" }, "Horizontal axis title"),
@@ -487,42 +625,42 @@ export const ChartEditor = ({ chart, sheetId, onSubmit }) => {
487
625
  React.createElement("option", { value: "bestFit" }, "Best fit")),
488
626
  React.createElement("label", { className: "font-system text-xs" }, "Number format pattern"),
489
627
  React.createElement(Input, { value: values?.spec.dataLabels?.numberFormatPattern ?? "", type: "text", onChange: (e) => setFieldValue("spec.dataLabels.numberFormatPattern", e.target.value || undefined), className: "text-xs w-32", placeholder: "#,##0.00" }))) : null)),
490
- basicSpec &&
491
- (basicSpec.chartType === "histogram" ||
492
- basicSpec.chartType === "radar" ||
493
- basicSpec.chartType === "stock" ||
494
- basicSpec.chartType === "doughnut" ||
495
- isBarOrColumnBasic) ? (React.createElement(Section, { title: "Chart options" },
496
- basicSpec.chartType === "histogram" ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
628
+ basicSpec && showChartOptions ? (React.createElement(Section, { title: "Chart options" },
629
+ chartOptionControls.binCount ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
497
630
  React.createElement("label", { className: "font-system text-sm" }, "Bins (leave blank for auto)"),
498
631
  React.createElement(Input, { value: basicSpec.binCount ?? "", type: "number", min: 1, onChange: (e) => {
499
632
  const raw = e.target.value;
500
633
  setFieldValue("spec.binCount", raw === "" ? undefined : Number(raw));
501
634
  }, className: "text-xs", placeholder: "Auto (Sturges)" }))) : null,
502
- basicSpec.chartType === "radar" ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
635
+ chartOptionControls.radarStyle ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
503
636
  React.createElement("label", { className: "font-system text-sm" }, "Radar style"),
504
637
  React.createElement("select", { className: "border border-rnc-border rounded-sm px-1 py-1 text-xs bg-transparent", value: basicSpec.radarStyle ?? "standard", onChange: (e) => setFieldValue("spec.radarStyle", e.target.value) },
505
638
  React.createElement("option", { value: "standard" }, "Standard"),
506
639
  React.createElement("option", { value: "marker" }, "With markers"),
507
640
  React.createElement("option", { value: "filled" }, "Filled")))) : null,
508
- basicSpec.chartType === "stock" ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
641
+ chartOptionControls.stockVariant ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
509
642
  React.createElement("label", { className: "font-system text-sm" }, "Stock variant"),
510
643
  React.createElement("select", { className: "border border-rnc-border rounded-sm px-1 py-1 text-xs bg-transparent", value: basicSpec.stockVariant ?? "HLC", onChange: (e) => setFieldValue("spec.stockVariant", e.target.value) },
511
644
  React.createElement("option", { value: "HLC" }, "High-Low-Close"),
512
645
  React.createElement("option", { value: "OHLC" }, "Open-High-Low-Close"),
513
646
  React.createElement("option", { value: "VHLC" }, "Volume-High-Low-Close"),
514
647
  React.createElement("option", { value: "VOHLC" }, "Volume-Open-High-Low-Close")))) : null,
515
- basicSpec.chartType === "doughnut" ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
648
+ chartOptionControls.doughnutHoleSize ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
516
649
  React.createElement("label", { className: "font-system text-sm" }, "Doughnut hole size (0-0.9)"),
517
650
  React.createElement(Input, { type: "number", min: 0, max: 0.9, step: 0.05, value: basicSpec.doughnutHoleSize ?? "", onChange: (e) => setFieldValue("spec.doughnutHoleSize", e.target.value === ""
518
651
  ? undefined
519
652
  : Number(e.target.value)), className: "text-xs w-32", placeholder: "0.5" }))) : null,
520
- isBarOrColumnBasic ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
653
+ chartOptionControls.explosion ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
654
+ React.createElement("label", { className: "font-system text-sm" }, "Explosion (% of radius, 0-400)"),
655
+ React.createElement(Input, { type: "number", min: 0, max: 400, step: 5, "aria-label": "Explosion", value: basicSpec.explosion ?? "", onChange: (e) => setFieldValue("spec.explosion", e.target.value === ""
656
+ ? undefined
657
+ : Number(e.target.value)), className: "text-xs w-32", placeholder: "0" }))) : null,
658
+ chartOptionControls.gapWidth ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
521
659
  React.createElement("label", { className: "font-system text-sm" }, "Gap width (0-500)"),
522
660
  React.createElement(Input, { type: "number", min: 0, max: 500, value: basicSpec.gapWidth ?? "", onChange: (e) => setFieldValue("spec.gapWidth", e.target.value === ""
523
661
  ? undefined
524
662
  : Number(e.target.value)), className: "text-xs w-32", placeholder: "150" }))) : null,
525
- isBarOrColumnBasic ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
663
+ chartOptionControls.overlap ? (React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
526
664
  React.createElement("label", { className: "font-system text-sm" }, "Series overlap (-100 to 100)"),
527
665
  React.createElement(Input, { type: "number", min: -100, max: 100, value: basicSpec.overlap ?? "", onChange: (e) => setFieldValue("spec.overlap", e.target.value === ""
528
666
  ? undefined
@@ -542,7 +680,13 @@ export const ChartEditor = ({ chart, sheetId, onSubmit }) => {
542
680
  React.createElement(Input, { value: values?.spec.verticalAxisTitle ?? "", type: "text", onChange: (e) => setFieldValue(`spec.verticalAxisTitle`, e.target.value), className: "text-xs", placeholder: "Vertical axis title" })),
543
681
  React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2" },
544
682
  React.createElement("label", { className: "font-system text-sm" }, "Horizontal axis title"),
545
- React.createElement(Input, { value: values?.spec.horizontalAxisTitle ?? "", type: "text", onChange: (e) => setFieldValue(`spec.horizontalAxisTitle`, e.target.value), className: "text-xs", placeholder: "Horizontal axis title" })))) : null)),
683
+ React.createElement(Input, { value: values?.spec.horizontalAxisTitle ?? "", type: "text", onChange: (e) => setFieldValue(`spec.horizontalAxisTitle`, e.target.value), className: "text-xs", placeholder: "Horizontal axis title" })))) : null,
684
+ React.createElement(Section, { title: "Properties" },
685
+ React.createElement(Stack, { direction: "vertical", className: "gap-1 pb-2", role: "radiogroup" }, CHART_PLACEMENT_OPTIONS.map(({ label, value }) => (React.createElement("label", { key: value, className: "font-system text-sm flex items-center gap-1" },
686
+ React.createElement("input", { type: "radio", name: "placement", value: value, checked: (values.position.overlayPosition.placement ??
687
+ "moveAndSize") === value, onChange: () => setFieldValue("position.overlayPosition.placement", value) }),
688
+ label)))),
689
+ onRequestMoveChart && chart ? (React.createElement(Button, { type: "button", size: "xs", className: "mb-2", onClick: () => onRequestMoveChart(chart) }, "Move chart\u2026")) : null))),
546
690
  React.createElement("div", { className: "flex gap-1 py-2 mt-1" },
547
691
  React.createElement(Button, { type: "submit", variant: "primary", size: "xs" }, "Save"),
548
692
  React.createElement(Button, { size: "xs", onClick: onCancelForm, type: "button" }, "Cancel"))));
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAqJ3D,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;AAiBF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,OAAO,CAAC,SAAS,CAAC,KAAG,MAmB9D,CAAC"}
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"}