@rowsncolumns/spreadsheet 10.6.0 → 10.6.5
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/cf-data-bar.d.ts +73 -0
- package/dist/cjs/api/cf-data-bar.d.ts.map +1 -0
- package/dist/cjs/api/cf-data-bar.js +182 -0
- package/dist/cjs/api/cf-icons.d.ts +73 -0
- package/dist/cjs/api/cf-icons.d.ts.map +1 -0
- package/dist/cjs/api/cf-icons.js +322 -0
- package/dist/cjs/api/cf-overlays.d.ts +89 -3
- package/dist/cjs/api/cf-overlays.d.ts.map +1 -1
- package/dist/cjs/api/cf-overlays.js +256 -80
- package/dist/cjs/api/cf-priority.d.ts +34 -0
- package/dist/cjs/api/cf-priority.d.ts.map +1 -0
- package/dist/cjs/api/cf-priority.js +94 -0
- package/dist/cjs/api/heatmap.d.ts +7 -1
- package/dist/cjs/api/heatmap.d.ts.map +1 -1
- package/dist/cjs/api/heatmap.js +27 -11
- package/dist/cjs/api/selections.d.ts +2 -2
- package/dist/cjs/api/validation.d.ts +6 -0
- package/dist/cjs/api/validation.d.ts.map +1 -1
- package/dist/cjs/api/validation.js +10 -1
- package/dist/cjs/components/canvas-grid/index.d.ts.map +1 -1
- package/dist/cjs/components/canvas-grid/index.js +194 -51
- package/dist/cjs/components/canvas-grid/overflow.d.ts +37 -0
- package/dist/cjs/components/canvas-grid/overflow.d.ts.map +1 -0
- package/dist/cjs/components/canvas-grid/overflow.js +49 -0
- package/dist/cjs/components/canvas-grid/page-breaks.d.ts +15 -0
- package/dist/cjs/components/canvas-grid/page-breaks.d.ts.map +1 -0
- package/dist/cjs/components/canvas-grid/page-breaks.js +77 -0
- package/dist/cjs/components/canvas-grid/typings.d.ts +25 -0
- package/dist/cjs/components/canvas-grid/typings.d.ts.map +1 -1
- package/dist/cjs/components/cell/alignment.d.ts +83 -1
- package/dist/cjs/components/cell/alignment.d.ts.map +1 -1
- package/dist/cjs/components/cell/alignment.js +182 -1
- package/dist/cjs/components/cell/cell-background.d.ts +18 -0
- package/dist/cjs/components/cell/cell-background.d.ts.map +1 -1
- package/dist/cjs/components/cell/cell-background.js +145 -59
- package/dist/cjs/components/cell/cell-backgrounds.d.ts.map +1 -1
- package/dist/cjs/components/cell/cell-backgrounds.js +5 -1
- package/dist/cjs/components/cell/cell-text-runs.d.ts +12 -5
- package/dist/cjs/components/cell/cell-text-runs.d.ts.map +1 -1
- package/dist/cjs/components/cell/cell-text-runs.js +19 -21
- package/dist/cjs/components/cell/index.d.ts.map +1 -1
- package/dist/cjs/components/cell/index.js +392 -45
- package/dist/cjs/components/cell/number-format-layout.d.ts +35 -0
- package/dist/cjs/components/cell/number-format-layout.d.ts.map +1 -0
- package/dist/cjs/components/cell/number-format-layout.js +106 -0
- package/dist/cjs/components/cell/typings.d.ts +22 -0
- package/dist/cjs/components/cell/typings.d.ts.map +1 -1
- package/dist/cjs/components/cell-editor/index.js +2 -2
- package/dist/cjs/components/cell-filter/index.d.ts.map +1 -1
- package/dist/cjs/components/cell-filter/index.js +3 -3
- package/dist/cjs/components/cell-overlay/index.d.ts +20 -0
- package/dist/cjs/components/cell-overlay/index.d.ts.map +1 -1
- package/dist/cjs/components/cell-overlay/index.js +155 -28
- package/dist/cjs/components/cf-icon-preview/index.d.ts +16 -0
- package/dist/cjs/components/cf-icon-preview/index.d.ts.map +1 -0
- package/dist/cjs/components/cf-icon-preview/index.js +48 -0
- package/dist/cjs/components/embeds/embed-component.d.ts.map +1 -1
- package/dist/cjs/components/embeds/embed-component.js +3 -2
- package/dist/cjs/components/hidden-markers/index.d.ts.map +1 -1
- package/dist/cjs/components/hidden-markers/index.js +8 -7
- package/dist/cjs/components/hidden-markers/style.d.ts +7 -0
- package/dist/cjs/components/hidden-markers/style.d.ts.map +1 -1
- package/dist/cjs/components/hidden-markers/style.js +13 -2
- package/dist/cjs/components/protect-sheet-dialog/index.d.ts +67 -0
- package/dist/cjs/components/protect-sheet-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/protect-sheet-dialog/index.js +196 -0
- package/dist/cjs/components/toolbar/types.d.ts +1 -1
- package/dist/cjs/components/toolbar/types.d.ts.map +1 -1
- package/dist/cjs/config.d.ts +13 -1
- package/dist/cjs/config.d.ts.map +1 -1
- package/dist/cjs/config.js +15 -3
- package/dist/cjs/helpers.d.ts +15 -5
- package/dist/cjs/helpers.d.ts.map +1 -1
- package/dist/cjs/helpers.js +51 -35
- package/dist/cjs/hooks/use-border-styles.d.ts.map +1 -1
- package/dist/cjs/hooks/use-border-styles.js +5 -28
- package/dist/cjs/hooks/use-cell-renderer.d.ts +35 -3
- package/dist/cjs/hooks/use-cell-renderer.d.ts.map +1 -1
- package/dist/cjs/hooks/use-cell-renderer.js +85 -47
- package/dist/cjs/hooks/use-conditional-formatting.d.ts +13 -1
- package/dist/cjs/hooks/use-conditional-formatting.d.ts.map +1 -1
- package/dist/cjs/hooks/use-conditional-formatting.js +281 -230
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +5 -0
- package/dist/cjs/release-date.js +1 -1
- package/dist/cjs/themes.d.ts +8 -0
- package/dist/cjs/themes.d.ts.map +1 -1
- package/dist/cjs/themes.js +21 -3
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/cjs/types.d.ts +81 -4
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/esm/api/cf-data-bar.d.ts +73 -0
- package/dist/esm/api/cf-data-bar.d.ts.map +1 -0
- package/dist/esm/api/cf-data-bar.js +178 -0
- package/dist/esm/api/cf-icons.d.ts +73 -0
- package/dist/esm/api/cf-icons.d.ts.map +1 -0
- package/dist/esm/api/cf-icons.js +306 -0
- package/dist/esm/api/cf-overlays.d.ts +89 -3
- package/dist/esm/api/cf-overlays.d.ts.map +1 -1
- package/dist/esm/api/cf-overlays.js +223 -67
- package/dist/esm/api/cf-priority.d.ts +34 -0
- package/dist/esm/api/cf-priority.d.ts.map +1 -0
- package/dist/esm/api/cf-priority.js +61 -0
- package/dist/esm/api/heatmap.d.ts +7 -1
- package/dist/esm/api/heatmap.d.ts.map +1 -1
- package/dist/esm/api/heatmap.js +24 -9
- package/dist/esm/api/selections.d.ts +2 -2
- package/dist/esm/api/validation.d.ts +6 -0
- package/dist/esm/api/validation.d.ts.map +1 -1
- package/dist/esm/api/validation.js +6 -0
- package/dist/esm/components/canvas-grid/index.d.ts.map +1 -1
- package/dist/esm/components/canvas-grid/index.js +163 -47
- package/dist/esm/components/canvas-grid/overflow.d.ts +37 -0
- package/dist/esm/components/canvas-grid/overflow.d.ts.map +1 -0
- package/dist/esm/components/canvas-grid/overflow.js +39 -0
- package/dist/esm/components/canvas-grid/page-breaks.d.ts +15 -0
- package/dist/esm/components/canvas-grid/page-breaks.d.ts.map +1 -0
- package/dist/esm/components/canvas-grid/page-breaks.js +50 -0
- package/dist/esm/components/canvas-grid/typings.d.ts +25 -0
- package/dist/esm/components/canvas-grid/typings.d.ts.map +1 -1
- package/dist/esm/components/cell/alignment.d.ts +83 -1
- package/dist/esm/components/cell/alignment.d.ts.map +1 -1
- package/dist/esm/components/cell/alignment.js +143 -1
- package/dist/esm/components/cell/cell-background.d.ts +18 -0
- package/dist/esm/components/cell/cell-background.d.ts.map +1 -1
- package/dist/esm/components/cell/cell-background.js +110 -41
- package/dist/esm/components/cell/cell-backgrounds.d.ts.map +1 -1
- package/dist/esm/components/cell/cell-backgrounds.js +5 -1
- package/dist/esm/components/cell/cell-text-runs.d.ts +12 -5
- package/dist/esm/components/cell/cell-text-runs.d.ts.map +1 -1
- package/dist/esm/components/cell/cell-text-runs.js +19 -24
- package/dist/esm/components/cell/index.d.ts.map +1 -1
- package/dist/esm/components/cell/index.js +352 -46
- package/dist/esm/components/cell/number-format-layout.d.ts +35 -0
- package/dist/esm/components/cell/number-format-layout.d.ts.map +1 -0
- package/dist/esm/components/cell/number-format-layout.js +99 -0
- package/dist/esm/components/cell/typings.d.ts +22 -0
- package/dist/esm/components/cell/typings.d.ts.map +1 -1
- package/dist/esm/components/cell-editor/index.js +2 -2
- package/dist/esm/components/cell-filter/index.d.ts.map +1 -1
- package/dist/esm/components/cell-filter/index.js +4 -4
- package/dist/esm/components/cell-overlay/index.d.ts +20 -0
- package/dist/esm/components/cell-overlay/index.d.ts.map +1 -1
- package/dist/esm/components/cell-overlay/index.js +111 -25
- package/dist/esm/components/cf-icon-preview/index.d.ts +16 -0
- package/dist/esm/components/cf-icon-preview/index.d.ts.map +1 -0
- package/dist/esm/components/cf-icon-preview/index.js +41 -0
- package/dist/esm/components/embeds/embed-component.d.ts.map +1 -1
- package/dist/esm/components/embeds/embed-component.js +4 -3
- package/dist/esm/components/hidden-markers/index.d.ts.map +1 -1
- package/dist/esm/components/hidden-markers/index.js +9 -8
- package/dist/esm/components/hidden-markers/style.d.ts +7 -0
- package/dist/esm/components/hidden-markers/style.d.ts.map +1 -1
- package/dist/esm/components/hidden-markers/style.js +8 -1
- package/dist/esm/components/protect-sheet-dialog/index.d.ts +67 -0
- package/dist/esm/components/protect-sheet-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/protect-sheet-dialog/index.js +154 -0
- package/dist/esm/components/toolbar/types.d.ts +1 -1
- package/dist/esm/components/toolbar/types.d.ts.map +1 -1
- package/dist/esm/config.d.ts +13 -1
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/config.js +13 -1
- package/dist/esm/helpers.d.ts +15 -5
- package/dist/esm/helpers.d.ts.map +1 -1
- package/dist/esm/helpers.js +48 -32
- package/dist/esm/hooks/use-border-styles.d.ts.map +1 -1
- package/dist/esm/hooks/use-border-styles.js +5 -26
- package/dist/esm/hooks/use-cell-renderer.d.ts +35 -3
- package/dist/esm/hooks/use-cell-renderer.d.ts.map +1 -1
- package/dist/esm/hooks/use-cell-renderer.js +83 -42
- package/dist/esm/hooks/use-conditional-formatting.d.ts +13 -1
- package/dist/esm/hooks/use-conditional-formatting.d.ts.map +1 -1
- package/dist/esm/hooks/use-conditional-formatting.js +215 -120
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +5 -0
- package/dist/esm/release-date.js +1 -1
- package/dist/esm/themes.d.ts +8 -0
- package/dist/esm/themes.d.ts.map +1 -1
- package/dist/esm/themes.js +20 -3
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/types.d.ts +81 -4
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/spreadsheet.min.css +1 -1
- package/package.json +4 -4
|
@@ -1,7 +1,93 @@
|
|
|
1
|
-
import type { CfThreshold, IconSetFamily } from "../types";
|
|
1
|
+
import type { CellFormat, CfThreshold, ConditionalFormatRule, IconSetFamily } from "../types";
|
|
2
2
|
export declare const ICON_SET_GLYPHS: Record<IconSetFamily, string[]>;
|
|
3
|
+
/** The colour each icon is painted in — what text stand-ins use. */
|
|
3
4
|
export declare const ICON_SET_COLORS: Record<IconSetFamily, string[]>;
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Numeric statistics of a rule's covered cells — what cfvo thresholds
|
|
7
|
+
* resolve against. `sorted` (ascending) backs PERCENTILE thresholds; it may
|
|
8
|
+
* be omitted when the caller already knows the rule needs no percentile.
|
|
9
|
+
*/
|
|
10
|
+
export type CfRangeStats = {
|
|
11
|
+
count: number;
|
|
12
|
+
min: number;
|
|
13
|
+
max: number;
|
|
14
|
+
sorted?: number[];
|
|
15
|
+
/**
|
|
16
|
+
* Engine-backed stand-ins for `sorted` on windowed hosts: PERCENTILE.INC
|
|
17
|
+
* at `p` (0..100), the k-th largest / smallest value (`k` a percent of the
|
|
18
|
+
* count when `percent`), the mean and the sample standard deviation.
|
|
19
|
+
*/
|
|
20
|
+
percentile?: (p: number) => number;
|
|
21
|
+
rankValue?: (k: number, top: boolean, percent?: boolean) => number;
|
|
22
|
+
mean?: number;
|
|
23
|
+
stdDev?: number;
|
|
24
|
+
};
|
|
25
|
+
/** What a rule needs from its full-range statistics (the engine request). */
|
|
26
|
+
export type CfRuleStatsRequest = {
|
|
27
|
+
percentiles: number[];
|
|
28
|
+
ranks: Array<{
|
|
29
|
+
k: number;
|
|
30
|
+
top: boolean;
|
|
31
|
+
percent?: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
};
|
|
34
|
+
/** The engine's reply to a {@link CfRuleStatsRequest} (`conditionalFormatRuleStats`). */
|
|
35
|
+
export type CfRuleStatsResponse = {
|
|
36
|
+
count: number;
|
|
37
|
+
min: number | null;
|
|
38
|
+
max: number | null;
|
|
39
|
+
mean: number | null;
|
|
40
|
+
stdDev: number | null;
|
|
41
|
+
percentiles: Array<number | null>;
|
|
42
|
+
ranks: Array<number | null>;
|
|
43
|
+
};
|
|
44
|
+
/** The percentiles / ranks a rule's thresholds resolve with. */
|
|
45
|
+
export declare const buildCfRuleStatsRequest: (rule: ConditionalFormatRule) => CfRuleStatsRequest;
|
|
46
|
+
/**
|
|
47
|
+
* Turn the engine's reply into {@link CfRangeStats} for the CF hook — what a
|
|
48
|
+
* windowed host returns from `getConditionalFormatRuleStats`.
|
|
49
|
+
*/
|
|
50
|
+
export declare const toCfRangeStats: (request: CfRuleStatsRequest, response: CfRuleStatsResponse | null | undefined) => CfRangeStats | undefined;
|
|
51
|
+
export declare const buildCfRangeStats: (values: number[]) => CfRangeStats;
|
|
52
|
+
/** Excel's PERCENTILE.INC over ascending values (`p` in 0..100). */
|
|
53
|
+
export declare const percentileInc: (sorted: number[], p: number) => number;
|
|
54
|
+
/**
|
|
55
|
+
* Resolves a FORMULA threshold's text (e.g. `=$B$1`, `=10`) to a number,
|
|
56
|
+
* or `undefined` when it can't be evaluated.
|
|
57
|
+
*/
|
|
58
|
+
export type CfFormulaResolver = (formula: string) => number | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Resolve a cfvo threshold against the rule's range statistics (OOXML cfvo
|
|
61
|
+
* semantics). `role` picks the AUTOMATIC bound (data bars only): the lower
|
|
62
|
+
* bound is `min(0, lowest)`, the upper `max(0, highest)`. Returns NaN when
|
|
63
|
+
* the threshold can't be resolved.
|
|
64
|
+
*/
|
|
65
|
+
export declare const resolveCfThreshold: (threshold: CfThreshold, stats: CfRangeStats, options?: {
|
|
66
|
+
role?: "min" | "max";
|
|
67
|
+
resolveFormula?: CfFormulaResolver;
|
|
68
|
+
}) => number;
|
|
69
|
+
export declare const resolveThreshold: (threshold: CfThreshold, rangeMin: number, rangeMax: number, sorted?: number[]) => number;
|
|
70
|
+
export declare const pickIconBucket: (value: number, thresholds: number[], strict?: boolean[]) => number;
|
|
6
71
|
export declare const computeDataBarFill: (value: number, min: number, max: number) => number;
|
|
72
|
+
/**
|
|
73
|
+
* Whether a cell counts as a number for data bars, colour scales, icon sets
|
|
74
|
+
* and the other numeric rules: its computed value is a number (Excel's rule —
|
|
75
|
+
* a typed `1` or a spilled `=SEQUENCE(3)` value qualifies without any number
|
|
76
|
+
* format), or it carries a number format (the legacy store's signal).
|
|
77
|
+
*/
|
|
78
|
+
export declare const isConditionalFormatNumberCell: (effectiveValue: Record<string, any> | null | undefined, cellFormat: CellFormat | null | undefined) => boolean;
|
|
79
|
+
/**
|
|
80
|
+
* The comparison bound of an above / below average rule: the mean, moved
|
|
81
|
+
* `stdDev` sample standard deviations (Excel's STDEV) above or below it for
|
|
82
|
+
* the "1/2/3 std dev above / below" options. Mirrors the engine's
|
|
83
|
+
* `average_bound` (rnc-store `derive.rs`).
|
|
84
|
+
*/
|
|
85
|
+
export declare const averageBound: (values: number[], above: boolean, stdDev?: number | null) => number;
|
|
86
|
+
/**
|
|
87
|
+
* Whether a CSS colour (`#rrggbb` / `rgb()`) is dark — relative luminance
|
|
88
|
+
* under 0.5. Unparseable colours count as light.
|
|
89
|
+
*/
|
|
90
|
+
export declare const isDarkCssColor: (color: string | null | undefined) => boolean;
|
|
91
|
+
/** {@link averageBound} from full-range statistics (sorted values or the engine's mean / std dev). */
|
|
92
|
+
export declare const averageBoundFromStats: (stats: CfRangeStats, above: boolean, stdDev?: number | null) => number | undefined;
|
|
7
93
|
//# sourceMappingURL=cf-overlays.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cf-overlays.d.ts","sourceRoot":"","sources":["../../../api/cf-overlays.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cf-overlays.d.ts","sourceRoot":"","sources":["../../../api/cf-overlays.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,106 +1,203 @@
|
|
|
1
1
|
// Helpers for IconSetRule and DataBarRule evaluation.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// Icon sets are painted as vector icons (`cf-icons.ts`); the glyphs below
|
|
4
|
+
// are the plain-text stand-ins menus (filter by icon, rule lists) show. Every
|
|
5
|
+
// family lists its icons in OOXML `iconId` order — index 0 is the icon of the
|
|
6
|
+
// LOWEST bucket; `reverse` on the rule flips the order. The number of icons
|
|
7
|
+
// encodes the family's bucket count (3, 4, or 5).
|
|
7
8
|
//
|
|
8
|
-
// Bucket selection:
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
9
|
+
// Bucket selection (Excel): thresholds are checked from the top bucket down;
|
|
10
|
+
// a value lands in the first bucket whose threshold it meets (`>=`, or `>`
|
|
11
|
+
// when the threshold's `gte` is false), else in bucket 0. Threshold types
|
|
12
|
+
// follow OOXML cfvo semantics: NUMBER is absolute, PERCENT is relative to
|
|
13
|
+
// the range's min..max, PERCENTILE is PERCENTILE.INC over the range values.
|
|
14
|
+
import { getExtendedValueNumber } from "@rowsncolumns/utils";
|
|
15
|
+
import { CF_ICON_SETS } from "./cf-icons";
|
|
13
16
|
export const ICON_SET_GLYPHS = {
|
|
14
|
-
// 3-icon families (
|
|
17
|
+
// 3-icon families (lowest → highest)
|
|
15
18
|
"3Arrows": ["▼", "▶", "▲"],
|
|
16
19
|
"3ArrowsGray": ["▽", "▷", "△"],
|
|
17
|
-
"3Flags": ["⚑", "
|
|
20
|
+
"3Flags": ["⚑", "⚑", "⚑"],
|
|
18
21
|
"3TrafficLights1": ["●", "●", "●"],
|
|
19
|
-
"3TrafficLights2": ["
|
|
22
|
+
"3TrafficLights2": ["●", "●", "●"],
|
|
20
23
|
"3Signs": ["◆", "▲", "●"],
|
|
21
|
-
"3Symbols": ["✖", "
|
|
24
|
+
"3Symbols": ["✖", "!", "✔"],
|
|
22
25
|
"3Symbols2": ["✗", "!", "✓"],
|
|
26
|
+
"3Stars": ["☆", "⯪", "★"],
|
|
27
|
+
"3Triangles": ["▼", "▬", "▲"],
|
|
23
28
|
// 4-icon families
|
|
24
29
|
"4Arrows": ["▼", "↘", "↗", "▲"],
|
|
25
30
|
"4ArrowsGray": ["▽", "↘", "↗", "△"],
|
|
26
31
|
"4RedToBlack": ["●", "●", "●", "●"],
|
|
27
|
-
"4Rating": ["
|
|
28
|
-
"4TrafficLights": ["
|
|
32
|
+
"4Rating": ["▂", "▃", "▅", "▇"],
|
|
33
|
+
"4TrafficLights": ["●", "●", "●", "●"],
|
|
29
34
|
// 5-icon families
|
|
30
35
|
"5Arrows": ["▼", "↘", "→", "↗", "▲"],
|
|
31
36
|
"5ArrowsGray": ["▽", "↘", "→", "↗", "△"],
|
|
32
37
|
"5Rating": ["▁", "▂", "▄", "▆", "▇"],
|
|
33
38
|
"5Quarters": ["○", "◔", "◑", "◕", "●"],
|
|
39
|
+
"5Boxes": ["□", "◰", "◧", "◩", "■"],
|
|
34
40
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"4ArrowsGray": ["#6b7280", "#6b7280", "#6b7280", "#6b7280"],
|
|
48
|
-
"4RedToBlack": ["#dc2626", "#f97316", "#525252", "#000000"],
|
|
49
|
-
"4Rating": ["#6b7280", "#6b7280", "#6b7280", "#6b7280"],
|
|
50
|
-
"4TrafficLights": ["#dc2626", "#f59e0b", "#84cc16", "#16a34a"],
|
|
51
|
-
"5Arrows": ["#dc2626", "#f59e0b", "#eab308", "#84cc16", "#16a34a"],
|
|
52
|
-
"5ArrowsGray": ["#6b7280", "#6b7280", "#6b7280", "#6b7280", "#6b7280"],
|
|
53
|
-
"5Rating": ["#6b7280", "#6b7280", "#6b7280", "#6b7280", "#6b7280"],
|
|
54
|
-
"5Quarters": ["#6b7280", "#6b7280", "#6b7280", "#6b7280", "#6b7280"],
|
|
41
|
+
const shapeColor = (shape) => {
|
|
42
|
+
switch (shape.kind) {
|
|
43
|
+
case "star":
|
|
44
|
+
return "#F5B800";
|
|
45
|
+
case "rating":
|
|
46
|
+
case "boxes":
|
|
47
|
+
return "#2F6EBA";
|
|
48
|
+
case "quarters":
|
|
49
|
+
return "#262626";
|
|
50
|
+
default:
|
|
51
|
+
return shape.color;
|
|
52
|
+
}
|
|
55
53
|
};
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
/** The colour each icon is painted in — what text stand-ins use. */
|
|
55
|
+
export const ICON_SET_COLORS = Object.fromEntries(Object.entries(CF_ICON_SETS).map(([family, shapes]) => [
|
|
56
|
+
family,
|
|
57
|
+
shapes.map(shapeColor),
|
|
58
|
+
]));
|
|
59
|
+
/** The percentiles / ranks a rule's thresholds resolve with. */
|
|
60
|
+
export const buildCfRuleStatsRequest = (rule) => {
|
|
61
|
+
const percentiles = new Set();
|
|
62
|
+
const addPoint = (point) => {
|
|
63
|
+
if (point?.type !== "PERCENTILE")
|
|
64
|
+
return;
|
|
65
|
+
const p = Number(point.value);
|
|
66
|
+
if (!Number.isFinite(p))
|
|
67
|
+
return;
|
|
68
|
+
percentiles.add(p);
|
|
69
|
+
// Colour scales read a 0..1 percentile as a fraction.
|
|
70
|
+
if (p <= 1)
|
|
71
|
+
percentiles.add(p * 100);
|
|
72
|
+
};
|
|
73
|
+
addPoint(rule.dataBarRule?.minpoint);
|
|
74
|
+
addPoint(rule.dataBarRule?.maxpoint);
|
|
75
|
+
rule.iconSetRule?.thresholds.forEach(addPoint);
|
|
76
|
+
addPoint(rule.gradientRule?.minpoint);
|
|
77
|
+
addPoint(rule.gradientRule?.midpoint);
|
|
78
|
+
addPoint(rule.gradientRule?.maxpoint);
|
|
79
|
+
const ranks = [];
|
|
80
|
+
if (rule.topBottomRule) {
|
|
81
|
+
ranks.push({
|
|
82
|
+
k: rule.topBottomRule.rank,
|
|
83
|
+
top: rule.topBottomRule.type === "TOP",
|
|
84
|
+
percent: !!rule.topBottomRule.isPercent,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return { percentiles: [...percentiles], ranks };
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Turn the engine's reply into {@link CfRangeStats} for the CF hook — what a
|
|
91
|
+
* windowed host returns from `getConditionalFormatRuleStats`.
|
|
92
|
+
*/
|
|
93
|
+
export const toCfRangeStats = (request, response) => {
|
|
94
|
+
if (!response)
|
|
95
|
+
return undefined;
|
|
96
|
+
const at = (list, i) => i >= 0 && list[i] != null ? list[i] : NaN;
|
|
97
|
+
return {
|
|
98
|
+
count: response.count,
|
|
99
|
+
min: response.min ?? NaN,
|
|
100
|
+
max: response.max ?? NaN,
|
|
101
|
+
mean: response.mean ?? undefined,
|
|
102
|
+
stdDev: response.stdDev ?? undefined,
|
|
103
|
+
percentile: (p) => at(response.percentiles, request.percentiles.indexOf(p)),
|
|
104
|
+
rankValue: (k, top, percent) => at(response.ranks, request.ranks.findIndex((r) => r.k === k && r.top === top && !!r.percent === !!percent)),
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
export const buildCfRangeStats = (values) => {
|
|
108
|
+
const sorted = values.slice().sort((a, b) => a - b);
|
|
109
|
+
return {
|
|
110
|
+
count: sorted.length,
|
|
111
|
+
min: sorted.length ? sorted[0] : NaN,
|
|
112
|
+
max: sorted.length ? sorted[sorted.length - 1] : NaN,
|
|
113
|
+
sorted,
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
/** Excel's PERCENTILE.INC over ascending values (`p` in 0..100). */
|
|
117
|
+
export const percentileInc = (sorted, p) => {
|
|
118
|
+
if (!sorted.length || !Number.isFinite(p))
|
|
119
|
+
return NaN;
|
|
120
|
+
const k = (Math.max(0, Math.min(100, p)) / 100) * (sorted.length - 1);
|
|
121
|
+
const lower = Math.floor(k);
|
|
122
|
+
const upper = Math.ceil(k);
|
|
123
|
+
if (lower === upper)
|
|
124
|
+
return sorted[lower];
|
|
125
|
+
return sorted[lower] + (sorted[upper] - sorted[lower]) * (k - lower);
|
|
126
|
+
};
|
|
127
|
+
const numericValue = (raw) => typeof raw === "number" ? raw : raw == null || raw === "" ? NaN : Number(raw);
|
|
128
|
+
/**
|
|
129
|
+
* Resolve a cfvo threshold against the rule's range statistics (OOXML cfvo
|
|
130
|
+
* semantics). `role` picks the AUTOMATIC bound (data bars only): the lower
|
|
131
|
+
* bound is `min(0, lowest)`, the upper `max(0, highest)`. Returns NaN when
|
|
132
|
+
* the threshold can't be resolved.
|
|
133
|
+
*/
|
|
134
|
+
export const resolveCfThreshold = (threshold, stats, options = {}) => {
|
|
135
|
+
const num = numericValue(threshold.value);
|
|
62
136
|
switch (threshold.type) {
|
|
63
137
|
case "MIN":
|
|
64
|
-
return
|
|
138
|
+
return stats.min;
|
|
65
139
|
case "MAX":
|
|
66
|
-
return
|
|
140
|
+
return stats.max;
|
|
141
|
+
case "AUTOMATIC":
|
|
142
|
+
return options.role === "max"
|
|
143
|
+
? Math.max(0, stats.max)
|
|
144
|
+
: Math.min(0, stats.min);
|
|
67
145
|
case "NUMBER":
|
|
68
146
|
return Number.isFinite(num) ? num : NaN;
|
|
69
|
-
case "PERCENT":
|
|
147
|
+
case "PERCENT":
|
|
70
148
|
if (!Number.isFinite(num))
|
|
71
149
|
return NaN;
|
|
72
|
-
|
|
73
|
-
return rangeMin + (span * num) / 100;
|
|
74
|
-
}
|
|
150
|
+
return stats.min + ((stats.max - stats.min) * num) / 100;
|
|
75
151
|
case "PERCENTILE":
|
|
76
|
-
// Approximate percentile by linear interpolation of min/max — the
|
|
77
|
-
// engine doesn't have access to the sorted value list here. For tight
|
|
78
|
-
// OOXML conformance the caller can pass a true percentile separately.
|
|
79
152
|
if (!Number.isFinite(num))
|
|
80
153
|
return NaN;
|
|
81
|
-
return
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
154
|
+
return stats.sorted
|
|
155
|
+
? percentileInc(stats.sorted, num)
|
|
156
|
+
: stats.percentile
|
|
157
|
+
? stats.percentile(num)
|
|
158
|
+
: stats.min + (stats.max - stats.min) * (num / 100);
|
|
159
|
+
case "FORMULA": {
|
|
160
|
+
if (Number.isFinite(num))
|
|
161
|
+
return num;
|
|
162
|
+
const text = String(threshold.value ?? "").trim();
|
|
163
|
+
if (!text)
|
|
164
|
+
return NaN;
|
|
165
|
+
const literal = Number(text.replace(/^=/, ""));
|
|
166
|
+
if (text.replace(/^=/, "") !== "" && Number.isFinite(literal)) {
|
|
167
|
+
return literal;
|
|
168
|
+
}
|
|
169
|
+
const resolved = options.resolveFormula?.(text);
|
|
170
|
+
return typeof resolved === "number" && Number.isFinite(resolved)
|
|
171
|
+
? resolved
|
|
172
|
+
: NaN;
|
|
173
|
+
}
|
|
87
174
|
default:
|
|
88
175
|
return NaN;
|
|
89
176
|
}
|
|
90
177
|
};
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
178
|
+
// Resolve a cfvo threshold value against a range's min/max numeric values.
|
|
179
|
+
// Returns NaN when the threshold can't be resolved (e.g. PERCENT against
|
|
180
|
+
// an empty range), which downstream callers should skip. Pass `sorted`
|
|
181
|
+
// values for an exact PERCENTILE.
|
|
182
|
+
export const resolveThreshold = (threshold, rangeMin, rangeMax, sorted) => resolveCfThreshold(threshold, {
|
|
183
|
+
count: sorted?.length ?? 0,
|
|
184
|
+
min: rangeMin,
|
|
185
|
+
max: rangeMax,
|
|
186
|
+
sorted,
|
|
187
|
+
});
|
|
188
|
+
// Pick the icon bucket index for a value. `thresholds[i]` is the lower bound
|
|
189
|
+
// of bucket `i + 1` (length = iconCount - 1); `strict[i]` makes it a `>`
|
|
190
|
+
// comparison. Checked from the top bucket down, like Excel; non-finite
|
|
191
|
+
// thresholds never match.
|
|
192
|
+
export const pickIconBucket = (value, thresholds, strict) => {
|
|
193
|
+
for (let i = thresholds.length - 1; i >= 0; i--) {
|
|
194
|
+
const t = thresholds[i];
|
|
96
195
|
if (!Number.isFinite(t))
|
|
97
|
-
|
|
98
|
-
if (value >= t)
|
|
99
|
-
|
|
100
|
-
else
|
|
101
|
-
break;
|
|
196
|
+
continue;
|
|
197
|
+
if (strict?.[i] ? value > t : value >= t)
|
|
198
|
+
return i + 1;
|
|
102
199
|
}
|
|
103
|
-
return
|
|
200
|
+
return 0;
|
|
104
201
|
};
|
|
105
202
|
// Compute a 0..1 fill fraction for a data-bar cell value.
|
|
106
203
|
// When `min >= max`, all cells in the range share the same value; return 1
|
|
@@ -116,3 +213,62 @@ export const computeDataBarFill = (value, min, max) => {
|
|
|
116
213
|
const clamped = Math.max(min, Math.min(max, value));
|
|
117
214
|
return (clamped - min) / (max - min);
|
|
118
215
|
};
|
|
216
|
+
/**
|
|
217
|
+
* Whether a cell counts as a number for data bars, colour scales, icon sets
|
|
218
|
+
* and the other numeric rules: its computed value is a number (Excel's rule —
|
|
219
|
+
* a typed `1` or a spilled `=SEQUENCE(3)` value qualifies without any number
|
|
220
|
+
* format), or it carries a number format (the legacy store's signal).
|
|
221
|
+
*/
|
|
222
|
+
export const isConditionalFormatNumberCell = (effectiveValue, cellFormat) => getExtendedValueNumber(effectiveValue) != null ||
|
|
223
|
+
!!cellFormat?.numberFormat?.type;
|
|
224
|
+
/**
|
|
225
|
+
* The comparison bound of an above / below average rule: the mean, moved
|
|
226
|
+
* `stdDev` sample standard deviations (Excel's STDEV) above or below it for
|
|
227
|
+
* the "1/2/3 std dev above / below" options. Mirrors the engine's
|
|
228
|
+
* `average_bound` (rnc-store `derive.rs`).
|
|
229
|
+
*/
|
|
230
|
+
export const averageBound = (values, above, stdDev) => {
|
|
231
|
+
const mean = values.reduce((sum, v) => sum + v, 0) / values.length;
|
|
232
|
+
if (!stdDev || stdDev <= 0 || values.length < 2)
|
|
233
|
+
return mean;
|
|
234
|
+
const variance = values.reduce((sum, v) => sum + (v - mean) ** 2, 0) / (values.length - 1);
|
|
235
|
+
const offset = stdDev * Math.sqrt(variance);
|
|
236
|
+
return above ? mean + offset : mean - offset;
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* Whether a CSS colour (`#rrggbb` / `rgb()`) is dark — relative luminance
|
|
240
|
+
* under 0.5. Unparseable colours count as light.
|
|
241
|
+
*/
|
|
242
|
+
export const isDarkCssColor = (color) => {
|
|
243
|
+
if (!color)
|
|
244
|
+
return false;
|
|
245
|
+
const hex = /^#?([0-9a-f]{6})/i.exec(color.trim());
|
|
246
|
+
const rgb = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i.exec(color.trim());
|
|
247
|
+
let channels;
|
|
248
|
+
if (hex) {
|
|
249
|
+
const n = parseInt(hex[1], 16);
|
|
250
|
+
channels = [(n >> 16) & 255, (n >> 8) & 255, n & 255];
|
|
251
|
+
}
|
|
252
|
+
else if (rgb) {
|
|
253
|
+
channels = [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])];
|
|
254
|
+
}
|
|
255
|
+
if (!channels)
|
|
256
|
+
return false;
|
|
257
|
+
const [r, g, b] = channels.map((c) => {
|
|
258
|
+
const v = c / 255;
|
|
259
|
+
return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
|
|
260
|
+
});
|
|
261
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b < 0.5;
|
|
262
|
+
};
|
|
263
|
+
/** {@link averageBound} from full-range statistics (sorted values or the engine's mean / std dev). */
|
|
264
|
+
export const averageBoundFromStats = (stats, above, stdDev) => {
|
|
265
|
+
if (stats.sorted) {
|
|
266
|
+
return stats.sorted.length
|
|
267
|
+
? averageBound(stats.sorted, above, stdDev)
|
|
268
|
+
: undefined;
|
|
269
|
+
}
|
|
270
|
+
if (stats.mean == null || !stats.count)
|
|
271
|
+
return undefined;
|
|
272
|
+
const offset = stdDev && stdDev > 0 ? stdDev * (stats.stdDev ?? 0) : 0;
|
|
273
|
+
return above ? stats.mean + offset : stats.mean - offset;
|
|
274
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ConditionalFormatRule } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Conditional-format precedence, as Excel defines it ("Manage conditional formatting rule
|
|
4
|
+
* precedence", support.microsoft.com): the rule listed FIRST has the highest precedence and wins a
|
|
5
|
+
* conflicting format; new rules go to the top of the list.
|
|
6
|
+
*
|
|
7
|
+
* `priority` carries that order (lower = higher precedence, as in xlsx `<cfRule priority>`). A rule
|
|
8
|
+
* without one ranks below every rule that has one; ties keep the stored order. The grid paints, the
|
|
9
|
+
* Rules Manager lists and the exporters number rules with this one ordering.
|
|
10
|
+
*/
|
|
11
|
+
export declare const sortConditionalFormatRules: <T extends Pick<ConditionalFormatRule, "priority">>(rules: ReadonlyArray<T>) => T[];
|
|
12
|
+
/**
|
|
13
|
+
* The `priority` that puts a new rule above every existing one (Excel adds new rules at the top of
|
|
14
|
+
* the list). Priorities may go to zero or below; exporters renumber from 1.
|
|
15
|
+
*/
|
|
16
|
+
export declare const getTopConditionalFormatPriority: (rules: ReadonlyArray<Pick<ConditionalFormatRule, "priority">>) => number;
|
|
17
|
+
/** A new rule with its `priority` set to the top of `rules`, unless it already carries one. */
|
|
18
|
+
export declare const withTopConditionalFormatPriority: <T extends Pick<ConditionalFormatRule, "priority">>(rule: T, rules: ReadonlyArray<Pick<ConditionalFormatRule, "priority">>) => T;
|
|
19
|
+
/**
|
|
20
|
+
* Move one rule up (`-1`) or down (`+1`) among `scope` (the rules the Rules Manager is showing —
|
|
21
|
+
* "Show formatting rules for" may hide some), returning the `priority` updates that realise the new
|
|
22
|
+
* order: every rule of the workbook renumbered 1..N in its new precedence order, keeping only the
|
|
23
|
+
* rules whose priority changes. Empty when the move is a no-op (first rule up, last rule down).
|
|
24
|
+
*/
|
|
25
|
+
export declare const planConditionalFormatMove: <T extends Pick<ConditionalFormatRule, "id" | "priority">>(rules: ReadonlyArray<T>, ruleId: T["id"], direction: -1 | 1, scope?: ReadonlyArray<Pick<T, "id">>) => Array<{
|
|
26
|
+
rule: T;
|
|
27
|
+
priority: number;
|
|
28
|
+
}>;
|
|
29
|
+
/** `priority` updates that make `ordered` the precedence order (1..N), changed rules only. */
|
|
30
|
+
export declare const planConditionalFormatOrder: <T extends Pick<ConditionalFormatRule, "priority">>(ordered: ReadonlyArray<T>) => Array<{
|
|
31
|
+
rule: T;
|
|
32
|
+
priority: number;
|
|
33
|
+
}>;
|
|
34
|
+
//# sourceMappingURL=cf-priority.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cf-priority.d.ts","sourceRoot":"","sources":["../../../api/cf-priority.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEtD;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GACrC,CAAC,SAAS,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,EAEjD,OAAO,aAAa,CAAC,CAAC,CAAC,KACtB,CAAC,EAWwB,CAAC;AAE7B;;;GAGG;AACH,eAAO,MAAM,+BAA+B,GAC1C,OAAO,aAAa,CAAC,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAC,KAC5D,MAQF,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,gCAAgC,GAC3C,CAAC,SAAS,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,EAEjD,MAAM,CAAC,EACP,OAAO,aAAa,CAAC,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAC,KAC5D,CAGgE,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GACpC,CAAC,SAAS,IAAI,CAAC,qBAAqB,EAAE,IAAI,GAAG,UAAU,CAAC,EAExD,OAAO,aAAa,CAAC,CAAC,CAAC,EACvB,QAAQ,CAAC,CAAC,IAAI,CAAC,EACf,WAAW,CAAC,CAAC,GAAG,CAAC,EACjB,QAAO,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAS,KAC1C,KAAK,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAerC,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,0BAA0B,GACrC,CAAC,SAAS,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,EAEjD,SAAS,aAAa,CAAC,CAAC,CAAC,KACxB,KAAK,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAGnC,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conditional-format precedence, as Excel defines it ("Manage conditional formatting rule
|
|
3
|
+
* precedence", support.microsoft.com): the rule listed FIRST has the highest precedence and wins a
|
|
4
|
+
* conflicting format; new rules go to the top of the list.
|
|
5
|
+
*
|
|
6
|
+
* `priority` carries that order (lower = higher precedence, as in xlsx `<cfRule priority>`). A rule
|
|
7
|
+
* without one ranks below every rule that has one; ties keep the stored order. The grid paints, the
|
|
8
|
+
* Rules Manager lists and the exporters number rules with this one ordering.
|
|
9
|
+
*/
|
|
10
|
+
export const sortConditionalFormatRules = (rules) => rules
|
|
11
|
+
.map((rule, index) => ({ rule, index }))
|
|
12
|
+
.sort((left, right) => {
|
|
13
|
+
const leftPriority = left.rule.priority ?? Number.POSITIVE_INFINITY;
|
|
14
|
+
const rightPriority = right.rule.priority ?? Number.POSITIVE_INFINITY;
|
|
15
|
+
if (leftPriority === rightPriority) {
|
|
16
|
+
return left.index - right.index;
|
|
17
|
+
}
|
|
18
|
+
return leftPriority - rightPriority;
|
|
19
|
+
})
|
|
20
|
+
.map(({ rule }) => rule);
|
|
21
|
+
/**
|
|
22
|
+
* The `priority` that puts a new rule above every existing one (Excel adds new rules at the top of
|
|
23
|
+
* the list). Priorities may go to zero or below; exporters renumber from 1.
|
|
24
|
+
*/
|
|
25
|
+
export const getTopConditionalFormatPriority = (rules) => {
|
|
26
|
+
let top = 1;
|
|
27
|
+
for (const rule of rules) {
|
|
28
|
+
if (typeof rule.priority === "number" && Number.isFinite(rule.priority)) {
|
|
29
|
+
top = Math.min(top, rule.priority);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return top - 1;
|
|
33
|
+
};
|
|
34
|
+
/** A new rule with its `priority` set to the top of `rules`, unless it already carries one. */
|
|
35
|
+
export const withTopConditionalFormatPriority = (rule, rules) => typeof rule.priority === "number"
|
|
36
|
+
? rule
|
|
37
|
+
: { ...rule, priority: getTopConditionalFormatPriority(rules) };
|
|
38
|
+
/**
|
|
39
|
+
* Move one rule up (`-1`) or down (`+1`) among `scope` (the rules the Rules Manager is showing —
|
|
40
|
+
* "Show formatting rules for" may hide some), returning the `priority` updates that realise the new
|
|
41
|
+
* order: every rule of the workbook renumbered 1..N in its new precedence order, keeping only the
|
|
42
|
+
* rules whose priority changes. Empty when the move is a no-op (first rule up, last rule down).
|
|
43
|
+
*/
|
|
44
|
+
export const planConditionalFormatMove = (rules, ruleId, direction, scope = rules) => {
|
|
45
|
+
const ordered = sortConditionalFormatRules(rules);
|
|
46
|
+
const scopeIds = new Set(scope.map((rule) => rule.id));
|
|
47
|
+
const visible = ordered.filter((rule) => scopeIds.has(rule.id));
|
|
48
|
+
const at = visible.findIndex((rule) => rule.id === ruleId);
|
|
49
|
+
const neighbour = visible[at + direction];
|
|
50
|
+
if (at === -1 || !neighbour) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
const from = ordered.indexOf(visible[at]);
|
|
54
|
+
const to = ordered.indexOf(neighbour);
|
|
55
|
+
const next = [...ordered];
|
|
56
|
+
next[from] = neighbour;
|
|
57
|
+
next[to] = visible[at];
|
|
58
|
+
return planConditionalFormatOrder(next);
|
|
59
|
+
};
|
|
60
|
+
/** `priority` updates that make `ordered` the precedence order (1..N), changed rules only. */
|
|
61
|
+
export const planConditionalFormatOrder = (ordered) => ordered.flatMap((rule, index) => rule.priority === index + 1 ? [] : [{ rule, priority: index + 1 }]);
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { SpreadsheetTheme } from "../components/canvas-grid/typings";
|
|
2
2
|
import type { GradientRule } from "../types";
|
|
3
|
-
|
|
3
|
+
import type { CfRangeStats } from "./cf-overlays";
|
|
4
|
+
/**
|
|
5
|
+
* `population` — the rule's full-range statistics when `values` is only the
|
|
6
|
+
* visible slice of a windowed rule; min / mid / max resolve over it instead
|
|
7
|
+
* of the slice.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getGradientColors: (values: (number | undefined)[][][], gradientRule: GradientRule, theme: SpreadsheetTheme, population?: CfRangeStats) => (string | undefined)[][][];
|
|
4
10
|
//# sourceMappingURL=heatmap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heatmap.d.ts","sourceRoot":"","sources":["../../../api/heatmap.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"heatmap.d.ts","sourceRoot":"","sources":["../../../api/heatmap.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,EAAE,EAClC,cAAc,YAAY,EAC1B,OAAO,gBAAgB,EACvB,aAAa,YAAY,+BAoE1B,CAAC"}
|
package/dist/esm/api/heatmap.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { hexToRgb, isNil, rgbToHex } from "@rowsncolumns/utils";
|
|
2
2
|
import { getStringifiedColor } from "../themes";
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* `population` — the rule's full-range statistics when `values` is only the
|
|
5
|
+
* visible slice of a windowed rule; min / mid / max resolve over it instead
|
|
6
|
+
* of the slice.
|
|
7
|
+
*/
|
|
8
|
+
export const getGradientColors = (values, gradientRule, theme, population) => {
|
|
4
9
|
const colors = [];
|
|
5
10
|
const { minpoint, midpoint, maxpoint } = gradientRule;
|
|
6
|
-
const [minValue, midValue, maxValue] = getMinMidMax(values, gradientRule);
|
|
11
|
+
const [minValue, midValue, maxValue] = getMinMidMax(population?.sorted ? [[population.sorted]] : values, gradientRule, population?.sorted ? undefined : population);
|
|
7
12
|
const range = maxValue - minValue || 1;
|
|
8
13
|
const minColor = getStringifiedColor(minpoint?.color, theme);
|
|
9
14
|
const midColor = getStringifiedColor(midpoint?.color, theme);
|
|
@@ -67,16 +72,20 @@ const interpolateColor = (color1, color2, ratio) => {
|
|
|
67
72
|
const interpolate = (value1, value2, ratio) => {
|
|
68
73
|
return value1 + (value2 - value1) * ratio;
|
|
69
74
|
};
|
|
70
|
-
const getMinMidMax = (values, { minpoint, midpoint, maxpoint }
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
const getMinMidMax = (values, { minpoint, midpoint, maxpoint },
|
|
76
|
+
// Engine statistics without the sorted values (windowed hosts).
|
|
77
|
+
stats) => {
|
|
78
|
+
const flattenedValues = stats
|
|
79
|
+
? []
|
|
80
|
+
: values
|
|
81
|
+
.flat(2)
|
|
82
|
+
.filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
83
|
+
if (stats ? !stats.count : flattenedValues.length === 0) {
|
|
75
84
|
return [0, 0, 0];
|
|
76
85
|
}
|
|
77
86
|
const sortedValues = [...flattenedValues].sort((a, b) => a - b);
|
|
78
|
-
const dataMin = sortedValues[0];
|
|
79
|
-
const dataMax = sortedValues[sortedValues.length - 1];
|
|
87
|
+
const dataMin = stats ? stats.min : sortedValues[0];
|
|
88
|
+
const dataMax = stats ? stats.max : sortedValues[sortedValues.length - 1];
|
|
80
89
|
const parseNumericInput = (value) => {
|
|
81
90
|
if (typeof value === "number") {
|
|
82
91
|
return Number.isFinite(value) ? value : undefined;
|
|
@@ -93,6 +102,12 @@ const getMinMidMax = (values, { minpoint, midpoint, maxpoint }) => {
|
|
|
93
102
|
return undefined;
|
|
94
103
|
};
|
|
95
104
|
const getPercentileValue = (percent) => {
|
|
105
|
+
if (stats) {
|
|
106
|
+
const value = stats.percentile?.(percent);
|
|
107
|
+
return value !== undefined && Number.isFinite(value)
|
|
108
|
+
? value
|
|
109
|
+
: dataMin + ((dataMax - dataMin) * percent) / 100;
|
|
110
|
+
}
|
|
96
111
|
if (!sortedValues.length) {
|
|
97
112
|
return dataMin;
|
|
98
113
|
}
|
|
@@ -8,7 +8,7 @@ import type { SheetRange, TableView } from "../types";
|
|
|
8
8
|
* @param isActiveCell
|
|
9
9
|
* @param isSelection
|
|
10
10
|
*/
|
|
11
|
-
export declare const getSelectionStrokeStyle: (formulaMode: boolean, isFill: boolean, isActiveCell: boolean, emptySelections: boolean) => "
|
|
11
|
+
export declare const getSelectionStrokeStyle: (formulaMode: boolean, isFill: boolean, isActiveCell: boolean, emptySelections: boolean) => "dashed" | "solid";
|
|
12
12
|
export type SelectionStrokeOptions = {
|
|
13
13
|
/** Border width of a range selection outside formula mode. Default `1`. */
|
|
14
14
|
selectionStrokeWidth?: number;
|
|
@@ -37,7 +37,7 @@ export declare const getSelectionStrokeWidth: (formulaMode: boolean, isFill: boo
|
|
|
37
37
|
* @param isFill
|
|
38
38
|
* @returns
|
|
39
39
|
*/
|
|
40
|
-
export declare const getSelectionFillOpacity: (formulaMode: boolean, isFill: boolean) =>
|
|
40
|
+
export declare const getSelectionFillOpacity: (formulaMode: boolean, isFill: boolean) => 1 | 0 | 0.2;
|
|
41
41
|
/**
|
|
42
42
|
* Get background color of selection
|
|
43
43
|
* @param formulaMode
|