@rowsncolumns/spreadsheet-state 29.2.0 → 29.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/api/border.d.ts +1 -1
- package/dist/cjs/api/border.d.ts.map +1 -1
- package/dist/cjs/api/paste-special.d.ts +33 -2
- package/dist/cjs/api/paste-special.d.ts.map +1 -1
- package/dist/cjs/api/paste-special.js +62 -19
- package/dist/cjs/commands.d.ts +208 -3
- package/dist/cjs/commands.d.ts.map +1 -1
- package/dist/cjs/components/editors/cell-format/alignment-tab.d.ts +27 -0
- package/dist/cjs/components/editors/cell-format/alignment-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/alignment-tab.js +83 -0
- package/dist/cjs/components/editors/cell-format/border-edges.d.ts +42 -0
- package/dist/cjs/components/editors/cell-format/border-edges.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/border-edges.js +118 -0
- package/dist/cjs/components/editors/cell-format/border-tab.d.ts +21 -0
- package/dist/cjs/components/editors/cell-format/border-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/border-tab.js +123 -0
- package/dist/cjs/components/editors/cell-format/fill-tab.d.ts +14 -0
- package/dist/cjs/components/editors/cell-format/fill-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/fill-tab.js +54 -0
- package/dist/cjs/components/editors/cell-format/font-tab.d.ts +18 -0
- package/dist/cjs/components/editors/cell-format/font-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/font-tab.js +99 -0
- package/dist/cjs/components/editors/cell-format/list-box.d.ts +35 -0
- package/dist/cjs/components/editors/cell-format/list-box.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/list-box.js +37 -0
- package/dist/cjs/components/editors/cell-format/number-formats.d.ts +90 -0
- package/dist/cjs/components/editors/cell-format/number-formats.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/number-formats.js +403 -0
- package/dist/cjs/components/editors/cell-format/number-tab.d.ts +12 -0
- package/dist/cjs/components/editors/cell-format/number-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/number-tab.js +194 -0
- package/dist/cjs/components/editors/cell-format/protection-tab.d.ts +13 -0
- package/dist/cjs/components/editors/cell-format/protection-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/protection-tab.js +13 -0
- package/dist/cjs/components/editors/cell-format-editor.d.ts +31 -3
- package/dist/cjs/components/editors/cell-format-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/cell-format-editor.js +182 -636
- package/dist/cjs/components/editors/conditional-format-data-bar-options.d.ts +16 -0
- package/dist/cjs/components/editors/conditional-format-data-bar-options.d.ts.map +1 -0
- package/dist/cjs/components/editors/conditional-format-data-bar-options.js +166 -0
- package/dist/cjs/components/editors/conditional-format-editor.d.ts +7 -1
- package/dist/cjs/components/editors/conditional-format-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/conditional-format-editor.js +51 -9
- package/dist/cjs/components/editors/conditional-format-icon-set-options.d.ts +17 -0
- package/dist/cjs/components/editors/conditional-format-icon-set-options.d.ts.map +1 -0
- package/dist/cjs/components/editors/conditional-format-icon-set-options.js +163 -0
- package/dist/cjs/components/editors/conditional-format-rule-editor.d.ts +9 -0
- package/dist/cjs/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/conditional-format-rule-editor.js +97 -125
- package/dist/cjs/components/editors/sheet-filter.d.ts +20 -9
- package/dist/cjs/components/editors/sheet-filter.d.ts.map +1 -1
- package/dist/cjs/components/editors/sheet-filter.js +44 -12
- package/dist/cjs/constants.d.ts +3 -1
- package/dist/cjs/constants.d.ts.map +1 -1
- package/dist/cjs/constants.js +3 -0
- package/dist/cjs/hooks/use-conditional-formatting-rules.d.ts +2 -0
- package/dist/cjs/hooks/use-conditional-formatting-rules.d.ts.map +1 -1
- package/dist/cjs/hooks/use-conditional-formatting-rules.js +22 -1
- package/dist/cjs/hooks/use-on-paste.d.ts.map +1 -1
- package/dist/cjs/hooks/use-on-paste.js +8 -1
- package/dist/cjs/hooks/use-sparkline-groups.d.ts +1 -0
- package/dist/cjs/hooks/use-sparkline-groups.d.ts.map +1 -1
- package/dist/cjs/hooks/use-sparkline-groups.js +28 -1
- package/dist/cjs/hooks/use-spreadsheet-state.d.ts +3 -0
- package/dist/cjs/hooks/use-spreadsheet-state.d.ts.map +1 -1
- package/dist/cjs/hooks/use-spreadsheet-state.js +11 -6
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/interface/change-border.d.ts.map +1 -1
- package/dist/cjs/interface/change-border.js +8 -1
- package/dist/cjs/interface/conditional-formatting-rules.d.ts +11 -1
- package/dist/cjs/interface/conditional-formatting-rules.d.ts.map +1 -1
- package/dist/cjs/interface/conditional-formatting-rules.js +44 -1
- package/dist/cjs/sheet-cell.d.ts +8 -0
- package/dist/cjs/sheet-cell.d.ts.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/api/border.d.ts +1 -1
- package/dist/esm/api/border.d.ts.map +1 -1
- package/dist/esm/api/paste-special.d.ts +33 -2
- package/dist/esm/api/paste-special.d.ts.map +1 -1
- package/dist/esm/api/paste-special.js +62 -13
- package/dist/esm/commands.d.ts +208 -3
- package/dist/esm/commands.d.ts.map +1 -1
- package/dist/esm/components/editors/cell-format/alignment-tab.d.ts +27 -0
- package/dist/esm/components/editors/cell-format/alignment-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/alignment-tab.js +81 -0
- package/dist/esm/components/editors/cell-format/border-edges.d.ts +42 -0
- package/dist/esm/components/editors/cell-format/border-edges.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/border-edges.js +79 -0
- package/dist/esm/components/editors/cell-format/border-tab.d.ts +21 -0
- package/dist/esm/components/editors/cell-format/border-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/border-tab.js +103 -0
- package/dist/esm/components/editors/cell-format/fill-tab.d.ts +14 -0
- package/dist/esm/components/editors/cell-format/fill-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/fill-tab.js +49 -0
- package/dist/esm/components/editors/cell-format/font-tab.d.ts +18 -0
- package/dist/esm/components/editors/cell-format/font-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/font-tab.js +88 -0
- package/dist/esm/components/editors/cell-format/list-box.d.ts +35 -0
- package/dist/esm/components/editors/cell-format/list-box.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/list-box.js +30 -0
- package/dist/esm/components/editors/cell-format/number-formats.d.ts +90 -0
- package/dist/esm/components/editors/cell-format/number-formats.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/number-formats.js +383 -0
- package/dist/esm/components/editors/cell-format/number-tab.d.ts +12 -0
- package/dist/esm/components/editors/cell-format/number-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/number-tab.js +165 -0
- package/dist/esm/components/editors/cell-format/protection-tab.d.ts +13 -0
- package/dist/esm/components/editors/cell-format/protection-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/protection-tab.js +9 -0
- package/dist/esm/components/editors/cell-format-editor.d.ts +31 -3
- package/dist/esm/components/editors/cell-format-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/cell-format-editor.js +148 -615
- package/dist/esm/components/editors/conditional-format-data-bar-options.d.ts +16 -0
- package/dist/esm/components/editors/conditional-format-data-bar-options.d.ts.map +1 -0
- package/dist/esm/components/editors/conditional-format-data-bar-options.js +145 -0
- package/dist/esm/components/editors/conditional-format-editor.d.ts +7 -1
- package/dist/esm/components/editors/conditional-format-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/conditional-format-editor.js +39 -8
- package/dist/esm/components/editors/conditional-format-icon-set-options.d.ts +17 -0
- package/dist/esm/components/editors/conditional-format-icon-set-options.d.ts.map +1 -0
- package/dist/esm/components/editors/conditional-format-icon-set-options.js +139 -0
- package/dist/esm/components/editors/conditional-format-rule-editor.d.ts +9 -0
- package/dist/esm/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/conditional-format-rule-editor.js +60 -85
- package/dist/esm/components/editors/sheet-filter.d.ts +20 -9
- package/dist/esm/components/editors/sheet-filter.d.ts.map +1 -1
- package/dist/esm/components/editors/sheet-filter.js +31 -11
- package/dist/esm/constants.d.ts +3 -1
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.js +3 -0
- package/dist/esm/hooks/use-conditional-formatting-rules.d.ts +2 -0
- package/dist/esm/hooks/use-conditional-formatting-rules.d.ts.map +1 -1
- package/dist/esm/hooks/use-conditional-formatting-rules.js +19 -1
- package/dist/esm/hooks/use-on-paste.d.ts.map +1 -1
- package/dist/esm/hooks/use-on-paste.js +8 -1
- package/dist/esm/hooks/use-sparkline-groups.d.ts +1 -0
- package/dist/esm/hooks/use-sparkline-groups.d.ts.map +1 -1
- package/dist/esm/hooks/use-sparkline-groups.js +20 -1
- package/dist/esm/hooks/use-spreadsheet-state.d.ts +3 -0
- package/dist/esm/hooks/use-spreadsheet-state.d.ts.map +1 -1
- package/dist/esm/hooks/use-spreadsheet-state.js +11 -4
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/interface/change-border.d.ts.map +1 -1
- package/dist/esm/interface/change-border.js +8 -1
- package/dist/esm/interface/conditional-formatting-rules.d.ts +11 -1
- package/dist/esm/interface/conditional-formatting-rules.d.ts.map +1 -1
- package/dist/esm/interface/conditional-formatting-rules.js +29 -1
- package/dist/esm/sheet-cell.d.ts +8 -0
- package/dist/esm/sheet-cell.d.ts.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DataBarRule, SpreadsheetTheme } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import React from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Excel's "New Formatting Rule ▸ Data Bar" defaults: Automatic bounds,
|
|
5
|
+
* gradient fill in blue with a matching solid border, red negative bars,
|
|
6
|
+
* an automatic black axis and full-width (0–100 %) bars.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_DATA_BAR_RULE: DataBarRule;
|
|
9
|
+
export type ConditionalFormatDataBarOptionsProps = {
|
|
10
|
+
rule: DataBarRule | null | undefined;
|
|
11
|
+
theme: SpreadsheetTheme;
|
|
12
|
+
onChange(next: DataBarRule): void;
|
|
13
|
+
};
|
|
14
|
+
/** Excel-depth data-bar options: bounds, fill, border, direction, negatives and axis, bar only. */
|
|
15
|
+
export declare const ConditionalFormatDataBarOptions: ({ rule, theme, onChange, }: ConditionalFormatDataBarOptionsProps) => React.JSX.Element;
|
|
16
|
+
//# sourceMappingURL=conditional-format-data-bar-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conditional-format-data-bar-options.d.ts","sourceRoot":"","sources":["../../../../components/editors/conditional-format-data-bar-options.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,WAAW,EACX,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AAYnC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAanC,CAAC;AAwCF,MAAM,MAAM,oCAAoC,GAAG;IACjD,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;CACnC,CAAC;AAEF,mGAAmG;AACnG,eAAO,MAAM,+BAA+B,GAAI,4BAI7C,oCAAoC,sBAuPtC,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { getStringifiedColor } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import { Input, Select, SelectContent, SelectItem, SelectPortal, SelectTrigger, SelectValue, Stack, } from "@rowsncolumns/ui";
|
|
3
|
+
import React from "react";
|
|
4
|
+
/**
|
|
5
|
+
* Excel's "New Formatting Rule ▸ Data Bar" defaults: Automatic bounds,
|
|
6
|
+
* gradient fill in blue with a matching solid border, red negative bars,
|
|
7
|
+
* an automatic black axis and full-width (0–100 %) bars.
|
|
8
|
+
*/
|
|
9
|
+
export const DEFAULT_DATA_BAR_RULE = {
|
|
10
|
+
minpoint: { type: "AUTOMATIC" },
|
|
11
|
+
maxpoint: { type: "AUTOMATIC" },
|
|
12
|
+
color: "#638EC6",
|
|
13
|
+
borderColor: "#638EC6",
|
|
14
|
+
gradient: true,
|
|
15
|
+
negativeColor: "#FF0000",
|
|
16
|
+
negativeBorderColor: "#FF0000",
|
|
17
|
+
axisPosition: "automatic",
|
|
18
|
+
axisColor: "#000000",
|
|
19
|
+
direction: "context",
|
|
20
|
+
minLength: 0,
|
|
21
|
+
maxLength: 100,
|
|
22
|
+
};
|
|
23
|
+
const BOUND_TYPES = [
|
|
24
|
+
{ value: "AUTOMATIC", min: "Automatic", max: "Automatic" },
|
|
25
|
+
{ value: "MIN", min: "Lowest Value", max: "Highest Value" },
|
|
26
|
+
{ value: "NUMBER", min: "Number", max: "Number" },
|
|
27
|
+
{ value: "PERCENT", min: "Percent", max: "Percent" },
|
|
28
|
+
{ value: "FORMULA", min: "Formula", max: "Formula" },
|
|
29
|
+
{ value: "PERCENTILE", min: "Percentile", max: "Percentile" },
|
|
30
|
+
];
|
|
31
|
+
const defaultBoundValue = (type, bound) => type === "NUMBER" || type === "FORMULA"
|
|
32
|
+
? bound === "min"
|
|
33
|
+
? "0"
|
|
34
|
+
: "100"
|
|
35
|
+
: type === "PERCENT" || type === "PERCENTILE"
|
|
36
|
+
? bound === "min"
|
|
37
|
+
? "10"
|
|
38
|
+
: "90"
|
|
39
|
+
: undefined;
|
|
40
|
+
const colorInputValue = (color, theme, fallback) => {
|
|
41
|
+
const css = color ? getStringifiedColor(color, theme) : undefined;
|
|
42
|
+
return typeof css === "string" && /^#[0-9a-f]{6}$/i.test(css)
|
|
43
|
+
? css
|
|
44
|
+
: fallback;
|
|
45
|
+
};
|
|
46
|
+
/** Excel-depth data-bar options: bounds, fill, border, direction, negatives and axis, bar only. */
|
|
47
|
+
export const ConditionalFormatDataBarOptions = ({ rule, theme, onChange, }) => {
|
|
48
|
+
const value = rule ?? DEFAULT_DATA_BAR_RULE;
|
|
49
|
+
const update = (patch) => onChange({ ...value, ...patch });
|
|
50
|
+
const boundEditor = (bound) => {
|
|
51
|
+
const key = bound === "min" ? "minpoint" : "maxpoint";
|
|
52
|
+
const threshold = value[key];
|
|
53
|
+
const showValue = threshold.type !== "AUTOMATIC" &&
|
|
54
|
+
threshold.type !== "MIN" &&
|
|
55
|
+
threshold.type !== "MAX";
|
|
56
|
+
return (React.createElement(Stack, { direction: "vertical", className: "gap-1 flex-1" },
|
|
57
|
+
React.createElement("label", { className: "font-system text-sm" }, bound === "min" ? "Minimum" : "Maximum"),
|
|
58
|
+
React.createElement(Select, { value: threshold.type === "MAX" ? "MIN" : threshold.type, onValueChange: (type) => {
|
|
59
|
+
const nextType = type === "MIN" && bound === "max"
|
|
60
|
+
? "MAX"
|
|
61
|
+
: type;
|
|
62
|
+
update({
|
|
63
|
+
[key]: {
|
|
64
|
+
type: nextType,
|
|
65
|
+
value: defaultBoundValue(nextType, bound),
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
} },
|
|
69
|
+
React.createElement(SelectTrigger, { className: "text-sm", "aria-label": bound === "min" ? "Minimum type" : "Maximum type" },
|
|
70
|
+
React.createElement(SelectValue, null)),
|
|
71
|
+
React.createElement(SelectPortal, null,
|
|
72
|
+
React.createElement(SelectContent, null, BOUND_TYPES.map((option) => (React.createElement(SelectItem, { key: option.value, value: option.value }, bound === "min" ? option.min : option.max)))))),
|
|
73
|
+
showValue ? (React.createElement(Input, { "aria-label": bound === "min" ? "Minimum value" : "Maximum value", className: "text-xs", value: String(threshold.value ?? ""), onChange: (e) => update({ [key]: { ...threshold, value: e.target.value } }) })) : null));
|
|
74
|
+
};
|
|
75
|
+
const negativeSameFill = !value.negativeColor;
|
|
76
|
+
const negativeSameBorder = !value.negativeBorderColor;
|
|
77
|
+
const hasBorder = !!value.borderColor;
|
|
78
|
+
return (React.createElement(Stack, { direction: "vertical", className: "gap-2 pb-1" },
|
|
79
|
+
React.createElement(Stack, { direction: "horizontal", className: "gap-2" },
|
|
80
|
+
boundEditor("min"),
|
|
81
|
+
boundEditor("max")),
|
|
82
|
+
React.createElement("label", { className: "font-system text-sm" }, "Bar appearance"),
|
|
83
|
+
React.createElement(Stack, { direction: "horizontal", className: "gap-2 items-center" },
|
|
84
|
+
React.createElement(Select, { value: value.gradient === false ? "solid" : "gradient", onValueChange: (fill) => update({ gradient: fill === "gradient" }) },
|
|
85
|
+
React.createElement(SelectTrigger, { className: "text-sm w-36", "aria-label": "Fill" },
|
|
86
|
+
React.createElement(SelectValue, null)),
|
|
87
|
+
React.createElement(SelectPortal, null,
|
|
88
|
+
React.createElement(SelectContent, null,
|
|
89
|
+
React.createElement(SelectItem, { value: "solid" }, "Solid Fill"),
|
|
90
|
+
React.createElement(SelectItem, { value: "gradient" }, "Gradient Fill")))),
|
|
91
|
+
React.createElement(Input, { type: "color", "aria-label": "Fill color", className: "w-16 h-8", value: colorInputValue(value.color, theme, "#638ec6"), onChange: (e) => update({ color: e.target.value }) })),
|
|
92
|
+
React.createElement(Stack, { direction: "horizontal", className: "gap-2 items-center" },
|
|
93
|
+
React.createElement(Select, { value: hasBorder ? "solid" : "none", onValueChange: (border) => update({
|
|
94
|
+
borderColor: border === "solid"
|
|
95
|
+
? colorInputValue(value.color, theme, "#638ec6")
|
|
96
|
+
: undefined,
|
|
97
|
+
...(border === "none" ? { negativeBorderColor: undefined } : {}),
|
|
98
|
+
}) },
|
|
99
|
+
React.createElement(SelectTrigger, { className: "text-sm w-36", "aria-label": "Border" },
|
|
100
|
+
React.createElement(SelectValue, null)),
|
|
101
|
+
React.createElement(SelectPortal, null,
|
|
102
|
+
React.createElement(SelectContent, null,
|
|
103
|
+
React.createElement(SelectItem, { value: "none" }, "No Border"),
|
|
104
|
+
React.createElement(SelectItem, { value: "solid" }, "Solid Border")))),
|
|
105
|
+
hasBorder ? (React.createElement(Input, { type: "color", "aria-label": "Border color", className: "w-16 h-8", value: colorInputValue(value.borderColor, theme, "#638ec6"), onChange: (e) => update({ borderColor: e.target.value }) })) : null),
|
|
106
|
+
React.createElement(Stack, { direction: "horizontal", className: "gap-2 items-center" },
|
|
107
|
+
React.createElement("label", { className: "font-system text-sm w-24" }, "Bar direction"),
|
|
108
|
+
React.createElement(Select, { value: value.direction ?? "context", onValueChange: (direction) => update({ direction: direction }) },
|
|
109
|
+
React.createElement(SelectTrigger, { className: "text-sm w-36", "aria-label": "Bar direction" },
|
|
110
|
+
React.createElement(SelectValue, null)),
|
|
111
|
+
React.createElement(SelectPortal, null,
|
|
112
|
+
React.createElement(SelectContent, null,
|
|
113
|
+
React.createElement(SelectItem, { value: "context" }, "Context"),
|
|
114
|
+
React.createElement(SelectItem, { value: "leftToRight" }, "Left-to-Right"),
|
|
115
|
+
React.createElement(SelectItem, { value: "rightToLeft" }, "Right-to-Left"))))),
|
|
116
|
+
React.createElement("label", { className: "font-system text-sm inline-flex items-center gap-2" },
|
|
117
|
+
React.createElement("input", { type: "checkbox", checked: value.showValue === false, onChange: (e) => update({ showValue: e.target.checked ? false : undefined }) }),
|
|
118
|
+
"Show Bar Only"),
|
|
119
|
+
React.createElement("label", { className: "font-system text-sm mt-1" }, "Negative value and axis"),
|
|
120
|
+
React.createElement(Stack, { direction: "horizontal", className: "gap-2 items-center" },
|
|
121
|
+
React.createElement("label", { className: "font-system text-xs inline-flex items-center gap-1" },
|
|
122
|
+
React.createElement("input", { type: "checkbox", checked: negativeSameFill, onChange: (e) => update({
|
|
123
|
+
negativeColor: e.target.checked ? undefined : "#FF0000",
|
|
124
|
+
}) }),
|
|
125
|
+
"Same fill color as positive bar"),
|
|
126
|
+
!negativeSameFill ? (React.createElement(Input, { type: "color", "aria-label": "Negative fill color", className: "w-16 h-8", value: colorInputValue(value.negativeColor, theme, "#ff0000"), onChange: (e) => update({ negativeColor: e.target.value }) })) : null),
|
|
127
|
+
hasBorder ? (React.createElement(Stack, { direction: "horizontal", className: "gap-2 items-center" },
|
|
128
|
+
React.createElement("label", { className: "font-system text-xs inline-flex items-center gap-1" },
|
|
129
|
+
React.createElement("input", { type: "checkbox", checked: negativeSameBorder, onChange: (e) => update({
|
|
130
|
+
negativeBorderColor: e.target.checked ? undefined : "#FF0000",
|
|
131
|
+
}) }),
|
|
132
|
+
"Same border color as positive bar"),
|
|
133
|
+
!negativeSameBorder ? (React.createElement(Input, { type: "color", "aria-label": "Negative border color", className: "w-16 h-8", value: colorInputValue(value.negativeBorderColor, theme, "#ff0000"), onChange: (e) => update({ negativeBorderColor: e.target.value }) })) : null)) : null,
|
|
134
|
+
React.createElement(Stack, { direction: "horizontal", className: "gap-2 items-center" },
|
|
135
|
+
React.createElement("label", { className: "font-system text-sm w-24" }, "Axis"),
|
|
136
|
+
React.createElement(Select, { value: value.axisPosition ?? "none", onValueChange: (axis) => update({ axisPosition: axis }) },
|
|
137
|
+
React.createElement(SelectTrigger, { className: "text-sm w-36", "aria-label": "Axis position" },
|
|
138
|
+
React.createElement(SelectValue, null)),
|
|
139
|
+
React.createElement(SelectPortal, null,
|
|
140
|
+
React.createElement(SelectContent, null,
|
|
141
|
+
React.createElement(SelectItem, { value: "automatic" }, "Automatic"),
|
|
142
|
+
React.createElement(SelectItem, { value: "middle" }, "Cell midpoint"),
|
|
143
|
+
React.createElement(SelectItem, { value: "none" }, "None")))),
|
|
144
|
+
value.axisPosition && value.axisPosition !== "none" ? (React.createElement(Input, { type: "color", "aria-label": "Axis color", className: "w-16 h-8", value: colorInputValue(value.axisColor, theme, "#000000"), onChange: (e) => update({ axisColor: e.target.value }) })) : null)));
|
|
145
|
+
};
|
|
@@ -36,12 +36,18 @@ export type ConditionalFormatEditorProps = {
|
|
|
36
36
|
* @param rule
|
|
37
37
|
*/
|
|
38
38
|
onPreviewRule: ReturnType<typeof useSpreadsheetState>["onPreviewConditionalFormattingRule"];
|
|
39
|
+
/**
|
|
40
|
+
* Move Up / Move Down: the `priority` updates that realise the new order, applied as ONE undoable
|
|
41
|
+
* change (`onReorderConditionalFormattingRules`). Without it each update goes through
|
|
42
|
+
* `onUpdateRule`.
|
|
43
|
+
*/
|
|
44
|
+
onReorderRules?: ReturnType<typeof useSpreadsheetState>["onReorderConditionalFormattingRules"];
|
|
39
45
|
/**
|
|
40
46
|
* Id creation strategy
|
|
41
47
|
*/
|
|
42
48
|
idCreationStrategy?: UseSpreadsheetProps["idCreationStrategy"];
|
|
43
49
|
};
|
|
44
|
-
export declare const ConditionalFormatEditor: ({ sheets, sheetId, theme, conditionalFormats, functionDescriptions, locale, idCreationStrategy, onCreateRule, onDeleteRule, onUpdateRule, onPreviewRule, }: ConditionalFormatEditorProps) => React.JSX.Element;
|
|
50
|
+
export declare const ConditionalFormatEditor: ({ sheets, sheetId, theme, conditionalFormats, functionDescriptions, locale, idCreationStrategy, onCreateRule, onDeleteRule, onUpdateRule, onPreviewRule, onReorderRules, }: ConditionalFormatEditorProps) => React.JSX.Element;
|
|
45
51
|
export declare const ConditionalFormatDialog: ({ children, }: {
|
|
46
52
|
children: React.ReactNode;
|
|
47
53
|
}) => React.JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conditional-format-editor.d.ts","sourceRoot":"","sources":["../../../../components/editors/conditional-format-editor.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"conditional-format-editor.d.ts","sourceRoot":"","sources":["../../../../components/editors/conditional-format-editor.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACrB,KAAK,EACL,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AAoBnC,OAAO,KAAyC,MAAM,OAAO,CAAC;AAG9D,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,mCAAmC,CAAC;AAW3C,MAAM,MAAM,4BAA4B,GAAG;IACzC,KAAK,EAAE,gBAAgB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB,CAAC,EAAE,eAAe,CAAC,sBAAsB,CAAC,CAAC;IAC/D,kBAAkB,EAAE,qBAAqB,EAAE,CAAC;IAC5C;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;IAC/C;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,YAAY,EAAE,UAAU,CACtB,OAAO,mBAAmB,CAC3B,CAAC,mCAAmC,CAAC,CAAC;IACvC;;;;OAIG;IACH,YAAY,EAAE,UAAU,CACtB,OAAO,mBAAmB,CAC3B,CAAC,mCAAmC,CAAC,CAAC;IACvC;;;OAGG;IACH,YAAY,EAAE,UAAU,CACtB,OAAO,mBAAmB,CAC3B,CAAC,mCAAmC,CAAC,CAAC;IACvC;;;OAGG;IACH,aAAa,EAAE,UAAU,CACvB,OAAO,mBAAmB,CAC3B,CAAC,oCAAoC,CAAC,CAAC;IACxC;;;;OAIG;IACH,cAAc,CAAC,EAAE,UAAU,CACzB,OAAO,mBAAmB,CAC3B,CAAC,qCAAqC,CAAC,CAAC;IACzC;;OAEG;IACH,kBAAkB,CAAC,EAAE,mBAAmB,CAAC,oBAAoB,CAAC,CAAC;CAChE,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,4KAarC,4BAA4B,sBA+U9B,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,eAErC;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,sBAyBA,CAAC"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { selectionFromActiveCell } from "@rowsncolumns/grid";
|
|
2
|
-
import { CopyIcon, Pencil2Icon, TrashIcon } from "@rowsncolumns/icons";
|
|
2
|
+
import { ArrowDownIcon, ArrowUpIcon, CopyIcon, Pencil2Icon, TrashIcon, } from "@rowsncolumns/icons";
|
|
3
3
|
import { BoxIcon, CheckIcon, Cross2Icon, PlusIcon } from "@rowsncolumns/icons";
|
|
4
|
-
import { getGradientColors, useFocusSheet, useFormulaRangeHelpers, useSpreadsheetApi, } from "@rowsncolumns/spreadsheet";
|
|
4
|
+
import { getGradientColors, planConditionalFormatMove, sortConditionalFormatRules, useFocusSheet, useFormulaRangeHelpers, useSpreadsheetApi, } from "@rowsncolumns/spreadsheet";
|
|
5
5
|
import { Button, Dialog, DialogBody, DialogCloseButton, DialogContent, DialogTitle, IconButton, Separator, } from "@rowsncolumns/ui";
|
|
6
6
|
import { uuid } from "@rowsncolumns/utils";
|
|
7
7
|
import React, { useCallback, useMemo, useState } from "react";
|
|
8
8
|
import { useConditionalFormatDialogState } from "../../atoms/dialog-state.atom";
|
|
9
9
|
import { ConditionalFormatRuleEditor, createRulePreviewStyle, } from "./conditional-format-rule-editor";
|
|
10
10
|
import { SheetFilterEmptyState, SheetFilterSelect, useSheetFilter, } from "./sheet-filter";
|
|
11
|
-
export const ConditionalFormatEditor = ({ sheets, sheetId, theme, conditionalFormats, functionDescriptions, locale, idCreationStrategy, onCreateRule, onDeleteRule, onUpdateRule, onPreviewRule, }) => {
|
|
11
|
+
export const ConditionalFormatEditor = ({ sheets, sheetId, theme, conditionalFormats, functionDescriptions, locale, idCreationStrategy, onCreateRule, onDeleteRule, onUpdateRule, onPreviewRule, onReorderRules, }) => {
|
|
12
12
|
const [editingId, setEditingId] = useState();
|
|
13
13
|
// Deferred create: "Add another rule" holds the new rule as a local draft and only
|
|
14
14
|
// persists it on Save — Excel/Google Sheets create the rule on OK/Done, and an
|
|
@@ -20,7 +20,32 @@ export const ConditionalFormatEditor = ({ sheets, sheetId, theme, conditionalFor
|
|
|
20
20
|
sheetId,
|
|
21
21
|
});
|
|
22
22
|
const workbookSheetIds = useMemo(() => sheets?.map((sheet) => sheet.sheetId), [sheets]);
|
|
23
|
-
|
|
23
|
+
// Excel lists rules in precedence order: the first rule wins a conflicting format.
|
|
24
|
+
const rulesInPrecedenceOrder = useMemo(() => sortConditionalFormatRules(conditionalFormats), [conditionalFormats]);
|
|
25
|
+
const { sheetFilter, setSheetFilter, filterableSheetIds, visibleRules, showFilter, } = useSheetFilter(sheetId, rulesInPrecedenceOrder, workbookSheetIds, () => {
|
|
26
|
+
const activeSheet = api?.getActiveSheet();
|
|
27
|
+
const selections = activeSheet?.getSelections();
|
|
28
|
+
const activeCell = activeSheet?.getActiveCell();
|
|
29
|
+
if (!selections?.length && !activeCell)
|
|
30
|
+
return [];
|
|
31
|
+
const ranges = (selections?.length
|
|
32
|
+
? selections
|
|
33
|
+
: selectionFromActiveCell(activeCell)).map((selection) => selection.range);
|
|
34
|
+
return ranges.map((range) => ({ ...range, sheetId }));
|
|
35
|
+
});
|
|
36
|
+
// Move Up / Move Down among the rules the list shows ("Show formatting rules for" may hide some).
|
|
37
|
+
const moveRule = (rule, direction) => {
|
|
38
|
+
const updates = planConditionalFormatMove(conditionalFormats, rule.id, direction, visibleRules);
|
|
39
|
+
if (!updates.length)
|
|
40
|
+
return;
|
|
41
|
+
if (onReorderRules) {
|
|
42
|
+
onReorderRules(updates);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
for (const { rule: target, priority } of updates) {
|
|
46
|
+
onUpdateRule?.({ ...target, priority }, target);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
24
49
|
const onNewRule = () => {
|
|
25
50
|
const activeCell = api?.getActiveSheet()?.getActiveCell();
|
|
26
51
|
const selections = api?.getActiveSheet()?.getSelections();
|
|
@@ -59,9 +84,11 @@ export const ConditionalFormatEditor = ({ sheets, sheetId, theme, conditionalFor
|
|
|
59
84
|
// Duplicate a rule
|
|
60
85
|
const onDuplicate = (rule) => {
|
|
61
86
|
const id = idCreationStrategy?.("conditional-format") ?? uuid();
|
|
62
|
-
//
|
|
87
|
+
// A copy is a new rule: drop the source's priority so it lands at the top of the list, as every
|
|
88
|
+
// new rule does in Excel, instead of tying with the source.
|
|
89
|
+
const { priority: _priority, ...copy } = rule;
|
|
63
90
|
onCreateRule?.({
|
|
64
|
-
...
|
|
91
|
+
...copy,
|
|
65
92
|
id,
|
|
66
93
|
});
|
|
67
94
|
};
|
|
@@ -88,9 +115,9 @@ export const ConditionalFormatEditor = ({ sheets, sheetId, theme, conditionalFor
|
|
|
88
115
|
setDraftRule(undefined);
|
|
89
116
|
setEditingId(undefined);
|
|
90
117
|
}, onSubmit: onSave, onChange: onPreviewRule, idCreationStrategy: idCreationStrategy })) : (React.createElement("div", { className: "flex flex-col overflow-auto max-h-[600px]" },
|
|
91
|
-
showFilter ? (React.createElement(SheetFilterSelect, { value: sheetFilter, sheetIds: filterableSheetIds, onValueChange: setSheetFilter })) : null,
|
|
118
|
+
showFilter ? (React.createElement(SheetFilterSelect, { offerSelection: true, value: sheetFilter, sheetIds: filterableSheetIds, onValueChange: setSheetFilter })) : null,
|
|
92
119
|
visibleRules.length === 0 ? (React.createElement(SheetFilterEmptyState, { sheetFilter: sheetFilter, label: "conditional format rules" })) : null,
|
|
93
|
-
visibleRules.map((rule) => {
|
|
120
|
+
visibleRules.map((rule, ruleIndex) => {
|
|
94
121
|
const title = rule.gradientRule
|
|
95
122
|
? "Color scale"
|
|
96
123
|
: rule.topBottomRule
|
|
@@ -136,6 +163,10 @@ export const ConditionalFormatEditor = ({ sheets, sheetId, theme, conditionalFor
|
|
|
136
163
|
React.createElement("input", { type: "checkbox", checked: Boolean(rule.stopIfTrue), onChange: (event) => toggleStopIfTrue(rule.id, event.target.checked) }),
|
|
137
164
|
"Stop if true")),
|
|
138
165
|
React.createElement("div", null,
|
|
166
|
+
React.createElement(IconButton, { tooltip: "Move up", "aria-label": "Move up", disabled: ruleIndex === 0, onClick: () => moveRule(rule, -1) },
|
|
167
|
+
React.createElement(ArrowUpIcon, null)),
|
|
168
|
+
React.createElement(IconButton, { tooltip: "Move down", "aria-label": "Move down", disabled: ruleIndex === visibleRules.length - 1, onClick: () => moveRule(rule, 1) },
|
|
169
|
+
React.createElement(ArrowDownIcon, null)),
|
|
139
170
|
React.createElement(IconButton, { tooltip: `${enabled ? "Disable" : "Enable"} this rule`, onClick: () => toggleEnable(rule.id, !enabled), className: "relative" },
|
|
140
171
|
React.createElement(BoxIcon, null),
|
|
141
172
|
enabled ? (React.createElement(CheckIcon, { className: "left-[4px] top-[5px] absolute" })) : null),
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CfThreshold, IconSetFamily, IconSetRule } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import React from "react";
|
|
3
|
+
/** Excel's 20 icon styles, in the order of its Icon Style list. */
|
|
4
|
+
export declare const ICON_SET_OPTIONS: Array<[IconSetFamily, string]>;
|
|
5
|
+
/** Excel's default thresholds for an n-icon set: equal percent slices. */
|
|
6
|
+
export declare const defaultIconThresholds: (count: number) => CfThreshold[];
|
|
7
|
+
export type ConditionalFormatIconSetOptionsProps = {
|
|
8
|
+
rule: IconSetRule | null | undefined;
|
|
9
|
+
onChange(next: IconSetRule): void;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Excel-depth icon-set options: icon style, reverse order, icon only, and
|
|
13
|
+
* one row per icon with its own icon (custom mixes), operator (>= / >),
|
|
14
|
+
* value and type.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ConditionalFormatIconSetOptions: ({ rule, onChange, }: ConditionalFormatIconSetOptionsProps) => React.JSX.Element;
|
|
17
|
+
//# sourceMappingURL=conditional-format-icon-set-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conditional-format-icon-set-options.d.ts","sourceRoot":"","sources":["../../../../components/editors/conditional-format-icon-set-options.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,WAAW,EACZ,MAAM,2BAA2B,CAAC;AAYnC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,mEAAmE;AACnE,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,CAAC,aAAa,EAAE,MAAM,CAAC,CAqB3D,CAAC;AAIF,0EAA0E;AAC1E,eAAO,MAAM,qBAAqB,GAAI,OAAO,MAAM,KAAG,WAAW,EAI5D,CAAC;AAKN,MAAM,MAAM,oCAAoC,GAAG;IACjD,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;CACnC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,GAAI,qBAG7C,oCAAoC,sBA6MtC,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { CF_ICON_SETS, CfIconPreview } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import { Input, Select, SelectContent, SelectItem, SelectPortal, SelectTrigger, SelectValue, Stack, } from "@rowsncolumns/ui";
|
|
3
|
+
import React from "react";
|
|
4
|
+
/** Excel's 20 icon styles, in the order of its Icon Style list. */
|
|
5
|
+
export const ICON_SET_OPTIONS = [
|
|
6
|
+
["3Arrows", "3 Arrows (Colored)"],
|
|
7
|
+
["3ArrowsGray", "3 Arrows (Gray)"],
|
|
8
|
+
["3Triangles", "3 Triangles"],
|
|
9
|
+
["4Arrows", "4 Arrows (Colored)"],
|
|
10
|
+
["4ArrowsGray", "4 Arrows (Gray)"],
|
|
11
|
+
["5Arrows", "5 Arrows (Colored)"],
|
|
12
|
+
["5ArrowsGray", "5 Arrows (Gray)"],
|
|
13
|
+
["3TrafficLights1", "3 Traffic Lights (Unrimmed)"],
|
|
14
|
+
["3TrafficLights2", "3 Traffic Lights (Rimmed)"],
|
|
15
|
+
["3Signs", "3 Signs"],
|
|
16
|
+
["4TrafficLights", "4 Traffic Lights"],
|
|
17
|
+
["4RedToBlack", "Red To Black"],
|
|
18
|
+
["3Symbols", "3 Symbols (Circled)"],
|
|
19
|
+
["3Symbols2", "3 Symbols (Uncircled)"],
|
|
20
|
+
["3Flags", "3 Flags"],
|
|
21
|
+
["3Stars", "3 Stars"],
|
|
22
|
+
["4Rating", "4 Ratings"],
|
|
23
|
+
["5Quarters", "5 Quarters"],
|
|
24
|
+
["5Rating", "5 Ratings"],
|
|
25
|
+
["5Boxes", "5 Boxes"],
|
|
26
|
+
];
|
|
27
|
+
const NO_ICON = "NoIcons:0";
|
|
28
|
+
/** Excel's default thresholds for an n-icon set: equal percent slices. */
|
|
29
|
+
export const defaultIconThresholds = (count) => Array.from({ length: count - 1 }, (_, i) => ({
|
|
30
|
+
type: "PERCENT",
|
|
31
|
+
value: Math.round(((i + 1) * 100) / count),
|
|
32
|
+
}));
|
|
33
|
+
const iconCount = (iconSet) => CF_ICON_SETS[iconSet]?.length ?? 3;
|
|
34
|
+
/**
|
|
35
|
+
* Excel-depth icon-set options: icon style, reverse order, icon only, and
|
|
36
|
+
* one row per icon with its own icon (custom mixes), operator (>= / >),
|
|
37
|
+
* value and type.
|
|
38
|
+
*/
|
|
39
|
+
export const ConditionalFormatIconSetOptions = ({ rule, onChange, }) => {
|
|
40
|
+
const value = rule ?? {
|
|
41
|
+
iconSet: "3TrafficLights1",
|
|
42
|
+
thresholds: defaultIconThresholds(3),
|
|
43
|
+
};
|
|
44
|
+
const count = iconCount(value.iconSet);
|
|
45
|
+
const update = (patch) => onChange({ ...value, ...patch });
|
|
46
|
+
// The icon each bucket shows, lowest bucket first — the custom list when
|
|
47
|
+
// set, else the style's icons (reversed when asked).
|
|
48
|
+
const bucketIcons = Array.from({ length: count }, (_, bucket) => {
|
|
49
|
+
const custom = value.icons?.[bucket];
|
|
50
|
+
if (custom)
|
|
51
|
+
return custom;
|
|
52
|
+
const iconId = value.reverse ? count - 1 - bucket : bucket;
|
|
53
|
+
return { iconSet: value.iconSet, iconId };
|
|
54
|
+
});
|
|
55
|
+
const setBucketIcon = (bucket, key) => {
|
|
56
|
+
const [iconSet, id] = key.split(":");
|
|
57
|
+
const icons = bucketIcons.map((icon, i) => i === bucket
|
|
58
|
+
? { iconSet: iconSet, iconId: Number(id) }
|
|
59
|
+
: icon);
|
|
60
|
+
update({ icons, reverse: undefined });
|
|
61
|
+
};
|
|
62
|
+
const setThreshold = (index, patch) => {
|
|
63
|
+
const thresholds = value.thresholds.slice();
|
|
64
|
+
thresholds[index] = { ...thresholds[index], ...patch };
|
|
65
|
+
update({ thresholds });
|
|
66
|
+
};
|
|
67
|
+
// Rows top-down from the highest bucket, like Excel's dialog.
|
|
68
|
+
const rows = Array.from({ length: count }, (_, i) => count - 1 - i);
|
|
69
|
+
return (React.createElement(Stack, { direction: "vertical", className: "gap-2 pb-1" },
|
|
70
|
+
React.createElement("label", { className: "font-system text-sm" }, "Icon style"),
|
|
71
|
+
React.createElement(Select, { value: value.iconSet, onValueChange: (next) => {
|
|
72
|
+
const family = next;
|
|
73
|
+
update({
|
|
74
|
+
iconSet: family,
|
|
75
|
+
icons: undefined,
|
|
76
|
+
thresholds: iconCount(family) === count
|
|
77
|
+
? value.thresholds
|
|
78
|
+
: defaultIconThresholds(iconCount(family)),
|
|
79
|
+
});
|
|
80
|
+
} },
|
|
81
|
+
React.createElement(SelectTrigger, { className: "text-sm w-72", "aria-label": "Icon style" },
|
|
82
|
+
React.createElement(SelectValue, null)),
|
|
83
|
+
React.createElement(SelectPortal, null,
|
|
84
|
+
React.createElement(SelectContent, null, ICON_SET_OPTIONS.map(([family, label]) => (React.createElement(SelectItem, { key: family, value: family },
|
|
85
|
+
React.createElement("span", { className: "inline-flex items-center gap-2" },
|
|
86
|
+
React.createElement("span", { className: "inline-flex gap-0.5" }, CF_ICON_SETS[family].map((_, iconId) => (React.createElement(CfIconPreview, { key: iconId, iconSet: family, iconId: iconId })))),
|
|
87
|
+
React.createElement("span", null, label)))))))),
|
|
88
|
+
React.createElement(Stack, { direction: "horizontal", className: "gap-4" },
|
|
89
|
+
React.createElement("label", { className: "font-system text-sm inline-flex items-center gap-2" },
|
|
90
|
+
React.createElement("input", { type: "checkbox", checked: !!value.reverse, onChange: (e) => {
|
|
91
|
+
// Reversing a custom mix reverses the list itself (Excel).
|
|
92
|
+
if (value.icons) {
|
|
93
|
+
update({ icons: value.icons.slice().reverse() });
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
update({ reverse: e.target.checked || undefined });
|
|
97
|
+
}
|
|
98
|
+
} }),
|
|
99
|
+
"Reverse Icon Order"),
|
|
100
|
+
React.createElement("label", { className: "font-system text-sm inline-flex items-center gap-2" },
|
|
101
|
+
React.createElement("input", { type: "checkbox", checked: value.showValue === false, onChange: (e) => update({ showValue: e.target.checked ? false : undefined }) }),
|
|
102
|
+
"Show Icon Only")),
|
|
103
|
+
rows.map((bucket) => {
|
|
104
|
+
const icon = bucketIcons[bucket];
|
|
105
|
+
const threshold = bucket > 0 ? value.thresholds[bucket - 1] : undefined;
|
|
106
|
+
return (React.createElement(Stack, { key: bucket, direction: "horizontal", className: "gap-1 items-center" },
|
|
107
|
+
React.createElement(Select, { value: `${icon.iconSet}:${icon.iconId}`, onValueChange: (key) => setBucketIcon(bucket, key) },
|
|
108
|
+
React.createElement(SelectTrigger, { className: "text-sm w-16", "aria-label": `Icon ${count - bucket}` },
|
|
109
|
+
React.createElement(SelectValue, null)),
|
|
110
|
+
React.createElement(SelectPortal, null,
|
|
111
|
+
React.createElement(SelectContent, null,
|
|
112
|
+
React.createElement(SelectItem, { value: NO_ICON }, "No Cell Icon"),
|
|
113
|
+
ICON_SET_OPTIONS.flatMap(([family]) => CF_ICON_SETS[family].map((_, iconId) => (React.createElement(SelectItem, { key: `${family}:${iconId}`, value: `${family}:${iconId}` },
|
|
114
|
+
React.createElement(CfIconPreview, { iconSet: family, iconId: iconId })))))))),
|
|
115
|
+
threshold ? (React.createElement(React.Fragment, null,
|
|
116
|
+
React.createElement("span", { className: "font-system text-xs" }, "when value is"),
|
|
117
|
+
React.createElement(Select, { value: threshold.gte === false ? ">" : ">=", onValueChange: (op) => setThreshold(bucket - 1, {
|
|
118
|
+
gte: op === ">" ? false : undefined,
|
|
119
|
+
}) },
|
|
120
|
+
React.createElement(SelectTrigger, { className: "text-sm w-14", "aria-label": `Operator ${count - bucket}` },
|
|
121
|
+
React.createElement(SelectValue, null)),
|
|
122
|
+
React.createElement(SelectPortal, null,
|
|
123
|
+
React.createElement(SelectContent, null,
|
|
124
|
+
React.createElement(SelectItem, { value: ">=" }, ">="),
|
|
125
|
+
React.createElement(SelectItem, { value: ">" }, ">")))),
|
|
126
|
+
React.createElement(Input, { className: "text-xs w-20", "aria-label": `Value ${count - bucket}`, value: String(threshold.value ?? ""), onChange: (e) => setThreshold(bucket - 1, { value: e.target.value }) }),
|
|
127
|
+
React.createElement(Select, { value: threshold.type, onValueChange: (type) => setThreshold(bucket - 1, {
|
|
128
|
+
type: type,
|
|
129
|
+
}) },
|
|
130
|
+
React.createElement(SelectTrigger, { className: "text-sm w-28", "aria-label": `Type ${count - bucket}` },
|
|
131
|
+
React.createElement(SelectValue, null)),
|
|
132
|
+
React.createElement(SelectPortal, null,
|
|
133
|
+
React.createElement(SelectContent, null,
|
|
134
|
+
React.createElement(SelectItem, { value: "NUMBER" }, "Number"),
|
|
135
|
+
React.createElement(SelectItem, { value: "PERCENT" }, "Percent"),
|
|
136
|
+
React.createElement(SelectItem, { value: "FORMULA" }, "Formula"),
|
|
137
|
+
React.createElement(SelectItem, { value: "PERCENTILE" }, "Percentile")))))) : (React.createElement("span", { className: "font-system text-xs" }, "otherwise"))));
|
|
138
|
+
})));
|
|
139
|
+
};
|
|
@@ -23,5 +23,14 @@ export type ConditionalFormatRuleEditorProps = {
|
|
|
23
23
|
};
|
|
24
24
|
export declare const createBorderCSSFromBorder: (borders: Borders | undefined | null, theme: SpreadsheetTheme) => React.CSSProperties;
|
|
25
25
|
export declare const createRulePreviewStyle: (format: CellFormat | undefined, theme: SpreadsheetTheme) => React.CSSProperties;
|
|
26
|
+
/** Excel's "Format only values that are above or below average" choices. */
|
|
27
|
+
export declare const AVERAGE_OPTIONS: Array<{
|
|
28
|
+
key: string;
|
|
29
|
+
label: string;
|
|
30
|
+
type: "NUMBER_ABOVE_AVERAGE" | "NUMBER_BELOW_AVERAGE";
|
|
31
|
+
equalAverage?: boolean;
|
|
32
|
+
stdDev?: number;
|
|
33
|
+
}>;
|
|
34
|
+
export declare const averageOptionKey: (rule: ConditionalFormatRule["booleanRule"]) => string;
|
|
26
35
|
export declare const ConditionalFormatRuleEditor: ({ sheetId, conditionalFormatRule, theme, functionDescriptions, locale, idCreationStrategy, onSubmit, onCancel, onChange, }: ConditionalFormatRuleEditorProps) => React.JSX.Element;
|
|
27
36
|
//# sourceMappingURL=conditional-format-rule-editor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conditional-format-rule-editor.d.ts","sourceRoot":"","sources":["../../../../components/editors/conditional-format-rule-editor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,4BAA4B,CAAC;AAG5E,OAAO,KAAK,EAEV,OAAO,EACP,eAAe,EACf,qBAAqB,EAGrB,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"conditional-format-rule-editor.d.ts","sourceRoot":"","sources":["../../../../components/editors/conditional-format-rule-editor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,4BAA4B,CAAC;AAG5E,OAAO,KAAK,EAEV,OAAO,EACP,eAAe,EACf,qBAAqB,EAGrB,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AAkCnC,OAAO,KAA+C,MAAM,OAAO,CAAC;AAMpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAU7E,MAAM,MAAM,gCAAgC,GAAG;IAC7C,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,KAAK,EAAE,gBAAgB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB,CAAC,EAAE,eAAe,CAAC,sBAAsB,CAAC,CAAC;IAC/D;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,mBAAmB,CAAC,oBAAoB,CAAC,CAAC;IAC/D,QAAQ,CAAC,CACP,qBAAqB,EAAE,qBAAqB,EAC5C,YAAY,EAAE,qBAAqB,GAClC,IAAI,CAAC;IACR,QAAQ,CAAC,CAAC,qBAAqB,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC9D,QAAQ,CAAC,IAAI,IAAI,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,SAAS,OAAO,GAAG,SAAS,GAAG,IAAI,EACnC,OAAO,gBAAgB,KACtB,KAAK,CAAC,aA0BR,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,QAAQ,UAAU,GAAG,SAAS,EAC9B,OAAO,gBAAgB,KACtB,KAAK,CAAC,aAYR,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,sBAAsB,GAAG,sBAAsB,CAAC;IACtD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CA2BA,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,MAAM,qBAAqB,CAAC,aAAa,CAAC,KACzC,MAOF,CAAC;AA6CF,eAAO,MAAM,2BAA2B,GAAI,4HAUzC,gCAAgC,sBAk7BlC,CAAC"}
|