@rowsncolumns/spreadsheet 10.6.0 → 10.6.4

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 (182) hide show
  1. package/dist/cjs/api/cf-data-bar.d.ts +73 -0
  2. package/dist/cjs/api/cf-data-bar.d.ts.map +1 -0
  3. package/dist/cjs/api/cf-data-bar.js +182 -0
  4. package/dist/cjs/api/cf-icons.d.ts +73 -0
  5. package/dist/cjs/api/cf-icons.d.ts.map +1 -0
  6. package/dist/cjs/api/cf-icons.js +322 -0
  7. package/dist/cjs/api/cf-overlays.d.ts +89 -3
  8. package/dist/cjs/api/cf-overlays.d.ts.map +1 -1
  9. package/dist/cjs/api/cf-overlays.js +256 -80
  10. package/dist/cjs/api/cf-priority.d.ts +34 -0
  11. package/dist/cjs/api/cf-priority.d.ts.map +1 -0
  12. package/dist/cjs/api/cf-priority.js +94 -0
  13. package/dist/cjs/api/heatmap.d.ts +7 -1
  14. package/dist/cjs/api/heatmap.d.ts.map +1 -1
  15. package/dist/cjs/api/heatmap.js +27 -11
  16. package/dist/cjs/api/selections.d.ts +2 -2
  17. package/dist/cjs/api/validation.d.ts +6 -0
  18. package/dist/cjs/api/validation.d.ts.map +1 -1
  19. package/dist/cjs/api/validation.js +10 -1
  20. package/dist/cjs/components/canvas-grid/index.d.ts.map +1 -1
  21. package/dist/cjs/components/canvas-grid/index.js +194 -51
  22. package/dist/cjs/components/canvas-grid/overflow.d.ts +37 -0
  23. package/dist/cjs/components/canvas-grid/overflow.d.ts.map +1 -0
  24. package/dist/cjs/components/canvas-grid/overflow.js +49 -0
  25. package/dist/cjs/components/canvas-grid/page-breaks.d.ts +15 -0
  26. package/dist/cjs/components/canvas-grid/page-breaks.d.ts.map +1 -0
  27. package/dist/cjs/components/canvas-grid/page-breaks.js +77 -0
  28. package/dist/cjs/components/canvas-grid/typings.d.ts +25 -0
  29. package/dist/cjs/components/canvas-grid/typings.d.ts.map +1 -1
  30. package/dist/cjs/components/cell/alignment.d.ts +58 -1
  31. package/dist/cjs/components/cell/alignment.d.ts.map +1 -1
  32. package/dist/cjs/components/cell/alignment.js +144 -1
  33. package/dist/cjs/components/cell/cell-background.d.ts +2 -0
  34. package/dist/cjs/components/cell/cell-background.d.ts.map +1 -1
  35. package/dist/cjs/components/cell/cell-background.js +5 -6
  36. package/dist/cjs/components/cell/cell-backgrounds.d.ts.map +1 -1
  37. package/dist/cjs/components/cell/cell-backgrounds.js +5 -1
  38. package/dist/cjs/components/cell/cell-text-runs.js +1 -1
  39. package/dist/cjs/components/cell/index.d.ts.map +1 -1
  40. package/dist/cjs/components/cell/index.js +378 -37
  41. package/dist/cjs/components/cell/number-format-layout.d.ts +35 -0
  42. package/dist/cjs/components/cell/number-format-layout.d.ts.map +1 -0
  43. package/dist/cjs/components/cell/number-format-layout.js +106 -0
  44. package/dist/cjs/components/cell/typings.d.ts +22 -0
  45. package/dist/cjs/components/cell/typings.d.ts.map +1 -1
  46. package/dist/cjs/components/cell-editor/index.js +2 -2
  47. package/dist/cjs/components/cell-filter/index.d.ts.map +1 -1
  48. package/dist/cjs/components/cell-filter/index.js +3 -3
  49. package/dist/cjs/components/cell-overlay/index.d.ts +20 -0
  50. package/dist/cjs/components/cell-overlay/index.d.ts.map +1 -1
  51. package/dist/cjs/components/cell-overlay/index.js +155 -28
  52. package/dist/cjs/components/cf-icon-preview/index.d.ts +16 -0
  53. package/dist/cjs/components/cf-icon-preview/index.d.ts.map +1 -0
  54. package/dist/cjs/components/cf-icon-preview/index.js +48 -0
  55. package/dist/cjs/components/embeds/embed-component.d.ts.map +1 -1
  56. package/dist/cjs/components/embeds/embed-component.js +3 -2
  57. package/dist/cjs/components/hidden-markers/index.d.ts.map +1 -1
  58. package/dist/cjs/components/hidden-markers/index.js +8 -7
  59. package/dist/cjs/components/hidden-markers/style.d.ts +7 -0
  60. package/dist/cjs/components/hidden-markers/style.d.ts.map +1 -1
  61. package/dist/cjs/components/hidden-markers/style.js +13 -2
  62. package/dist/cjs/components/protect-sheet-dialog/index.d.ts +67 -0
  63. package/dist/cjs/components/protect-sheet-dialog/index.d.ts.map +1 -0
  64. package/dist/cjs/components/protect-sheet-dialog/index.js +196 -0
  65. package/dist/cjs/components/toolbar/types.d.ts +1 -1
  66. package/dist/cjs/components/toolbar/types.d.ts.map +1 -1
  67. package/dist/cjs/config.d.ts +13 -1
  68. package/dist/cjs/config.d.ts.map +1 -1
  69. package/dist/cjs/config.js +15 -3
  70. package/dist/cjs/helpers.d.ts +10 -5
  71. package/dist/cjs/helpers.d.ts.map +1 -1
  72. package/dist/cjs/helpers.js +43 -31
  73. package/dist/cjs/hooks/use-border-styles.d.ts.map +1 -1
  74. package/dist/cjs/hooks/use-border-styles.js +5 -28
  75. package/dist/cjs/hooks/use-cell-renderer.d.ts +35 -3
  76. package/dist/cjs/hooks/use-cell-renderer.d.ts.map +1 -1
  77. package/dist/cjs/hooks/use-cell-renderer.js +85 -47
  78. package/dist/cjs/hooks/use-conditional-formatting.d.ts +13 -1
  79. package/dist/cjs/hooks/use-conditional-formatting.d.ts.map +1 -1
  80. package/dist/cjs/hooks/use-conditional-formatting.js +281 -230
  81. package/dist/cjs/index.d.ts +5 -0
  82. package/dist/cjs/index.d.ts.map +1 -1
  83. package/dist/cjs/index.js +5 -0
  84. package/dist/cjs/release-date.js +1 -1
  85. package/dist/cjs/themes.d.ts +8 -0
  86. package/dist/cjs/themes.d.ts.map +1 -1
  87. package/dist/cjs/themes.js +21 -3
  88. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  89. package/dist/cjs/types.d.ts +81 -4
  90. package/dist/cjs/types.d.ts.map +1 -1
  91. package/dist/esm/api/cf-data-bar.d.ts +73 -0
  92. package/dist/esm/api/cf-data-bar.d.ts.map +1 -0
  93. package/dist/esm/api/cf-data-bar.js +178 -0
  94. package/dist/esm/api/cf-icons.d.ts +73 -0
  95. package/dist/esm/api/cf-icons.d.ts.map +1 -0
  96. package/dist/esm/api/cf-icons.js +306 -0
  97. package/dist/esm/api/cf-overlays.d.ts +89 -3
  98. package/dist/esm/api/cf-overlays.d.ts.map +1 -1
  99. package/dist/esm/api/cf-overlays.js +223 -67
  100. package/dist/esm/api/cf-priority.d.ts +34 -0
  101. package/dist/esm/api/cf-priority.d.ts.map +1 -0
  102. package/dist/esm/api/cf-priority.js +61 -0
  103. package/dist/esm/api/heatmap.d.ts +7 -1
  104. package/dist/esm/api/heatmap.d.ts.map +1 -1
  105. package/dist/esm/api/heatmap.js +24 -9
  106. package/dist/esm/api/selections.d.ts +2 -2
  107. package/dist/esm/api/validation.d.ts +6 -0
  108. package/dist/esm/api/validation.d.ts.map +1 -1
  109. package/dist/esm/api/validation.js +6 -0
  110. package/dist/esm/components/canvas-grid/index.d.ts.map +1 -1
  111. package/dist/esm/components/canvas-grid/index.js +163 -47
  112. package/dist/esm/components/canvas-grid/overflow.d.ts +37 -0
  113. package/dist/esm/components/canvas-grid/overflow.d.ts.map +1 -0
  114. package/dist/esm/components/canvas-grid/overflow.js +39 -0
  115. package/dist/esm/components/canvas-grid/page-breaks.d.ts +15 -0
  116. package/dist/esm/components/canvas-grid/page-breaks.d.ts.map +1 -0
  117. package/dist/esm/components/canvas-grid/page-breaks.js +50 -0
  118. package/dist/esm/components/canvas-grid/typings.d.ts +25 -0
  119. package/dist/esm/components/canvas-grid/typings.d.ts.map +1 -1
  120. package/dist/esm/components/cell/alignment.d.ts +58 -1
  121. package/dist/esm/components/cell/alignment.d.ts.map +1 -1
  122. package/dist/esm/components/cell/alignment.js +110 -1
  123. package/dist/esm/components/cell/cell-background.d.ts +2 -0
  124. package/dist/esm/components/cell/cell-background.d.ts.map +1 -1
  125. package/dist/esm/components/cell/cell-background.js +4 -5
  126. package/dist/esm/components/cell/cell-backgrounds.d.ts.map +1 -1
  127. package/dist/esm/components/cell/cell-backgrounds.js +5 -1
  128. package/dist/esm/components/cell/cell-text-runs.js +2 -2
  129. package/dist/esm/components/cell/index.d.ts.map +1 -1
  130. package/dist/esm/components/cell/index.js +339 -39
  131. package/dist/esm/components/cell/number-format-layout.d.ts +35 -0
  132. package/dist/esm/components/cell/number-format-layout.d.ts.map +1 -0
  133. package/dist/esm/components/cell/number-format-layout.js +99 -0
  134. package/dist/esm/components/cell/typings.d.ts +22 -0
  135. package/dist/esm/components/cell/typings.d.ts.map +1 -1
  136. package/dist/esm/components/cell-editor/index.js +2 -2
  137. package/dist/esm/components/cell-filter/index.d.ts.map +1 -1
  138. package/dist/esm/components/cell-filter/index.js +4 -4
  139. package/dist/esm/components/cell-overlay/index.d.ts +20 -0
  140. package/dist/esm/components/cell-overlay/index.d.ts.map +1 -1
  141. package/dist/esm/components/cell-overlay/index.js +111 -25
  142. package/dist/esm/components/cf-icon-preview/index.d.ts +16 -0
  143. package/dist/esm/components/cf-icon-preview/index.d.ts.map +1 -0
  144. package/dist/esm/components/cf-icon-preview/index.js +41 -0
  145. package/dist/esm/components/embeds/embed-component.d.ts.map +1 -1
  146. package/dist/esm/components/embeds/embed-component.js +4 -3
  147. package/dist/esm/components/hidden-markers/index.d.ts.map +1 -1
  148. package/dist/esm/components/hidden-markers/index.js +9 -8
  149. package/dist/esm/components/hidden-markers/style.d.ts +7 -0
  150. package/dist/esm/components/hidden-markers/style.d.ts.map +1 -1
  151. package/dist/esm/components/hidden-markers/style.js +8 -1
  152. package/dist/esm/components/protect-sheet-dialog/index.d.ts +67 -0
  153. package/dist/esm/components/protect-sheet-dialog/index.d.ts.map +1 -0
  154. package/dist/esm/components/protect-sheet-dialog/index.js +154 -0
  155. package/dist/esm/components/toolbar/types.d.ts +1 -1
  156. package/dist/esm/components/toolbar/types.d.ts.map +1 -1
  157. package/dist/esm/config.d.ts +13 -1
  158. package/dist/esm/config.d.ts.map +1 -1
  159. package/dist/esm/config.js +13 -1
  160. package/dist/esm/helpers.d.ts +10 -5
  161. package/dist/esm/helpers.d.ts.map +1 -1
  162. package/dist/esm/helpers.js +40 -28
  163. package/dist/esm/hooks/use-border-styles.d.ts.map +1 -1
  164. package/dist/esm/hooks/use-border-styles.js +5 -26
  165. package/dist/esm/hooks/use-cell-renderer.d.ts +35 -3
  166. package/dist/esm/hooks/use-cell-renderer.d.ts.map +1 -1
  167. package/dist/esm/hooks/use-cell-renderer.js +83 -42
  168. package/dist/esm/hooks/use-conditional-formatting.d.ts +13 -1
  169. package/dist/esm/hooks/use-conditional-formatting.d.ts.map +1 -1
  170. package/dist/esm/hooks/use-conditional-formatting.js +215 -120
  171. package/dist/esm/index.d.ts +5 -0
  172. package/dist/esm/index.d.ts.map +1 -1
  173. package/dist/esm/index.js +5 -0
  174. package/dist/esm/release-date.js +1 -1
  175. package/dist/esm/themes.d.ts +8 -0
  176. package/dist/esm/themes.d.ts.map +1 -1
  177. package/dist/esm/themes.js +20 -3
  178. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  179. package/dist/esm/types.d.ts +81 -4
  180. package/dist/esm/types.d.ts.map +1 -1
  181. package/dist/spreadsheet.min.css +1 -1
  182. package/package.json +4 -4
@@ -1,14 +1,16 @@
1
1
  import { cellIdentifier } from "@rowsncolumns/grid";
2
- import { isConditionalFormatFormulaRule, iterateCellsInRange, } from "@rowsncolumns/utils";
2
+ import { addressToCell, isConditionalFormatFormulaRule, iterateCellsInRange, } from "@rowsncolumns/utils";
3
3
  import isNil from "lodash/isNil";
4
4
  import { useCallback, useMemo, useRef } from "react";
5
- import { computeDataBarFill, ICON_SET_COLORS, ICON_SET_GLYPHS, pickIconBucket, resolveThreshold, } from "../api/cf-overlays";
5
+ import { computeDataBarGeometry } from "../api/cf-data-bar";
6
6
  import { isEngineEvaluatedAggregateRule } from "../api/cf-engine";
7
+ import { averageBound, averageBoundFromStats, buildCfRangeStats, ICON_SET_COLORS, ICON_SET_GLYPHS, pickIconBucket, resolveCfThreshold, } from "../api/cf-overlays";
8
+ import { sortConditionalFormatRules } from "../api/cf-priority";
7
9
  import { windowConditionalFormatRules } from "../api/cf-window";
8
10
  import { getGradientColors } from "../api/heatmap";
9
11
  import { checkBooleanRule, shouldUsePreviousValue } from "../api/validation";
10
- import { getStringifiedColor } from "../themes";
11
12
  import { DEFAULT_COLUMN_COUNT, DEFAULT_ROW_COUNT } from "../config";
13
+ import { getStringifiedColor } from "../themes";
12
14
  /**
13
15
  * Merge a lower-priority rule's format under an already-applied one, per
14
16
  * property (Excel's stacking): every property the higher-priority format
@@ -39,7 +41,26 @@ const definedEntries = (obj) => {
39
41
  }
40
42
  return out;
41
43
  };
42
- export const useConditionalFormatting = ({ sheetId, theme, conditionalFormats, locale, getValidationValue, isNumberValue, getSheetRowCount, getSheetColumnCount, window: evaluationWindow, getConditionalFormatResult, }) => {
44
+ /** The k-th value a top/bottom-N rule ranks against, from full-range statistics. */
45
+ const fullRangeRankValue = (stats, rule) => {
46
+ const top = rule.type === "TOP";
47
+ if (stats.sorted) {
48
+ const n = stats.sorted.length;
49
+ if (!n)
50
+ return undefined;
51
+ const k = Math.min(n, Math.max(1, rule.isPercent ? Math.ceil((rule.rank / 100) * n) : rule.rank));
52
+ return top ? stats.sorted[n - k] : stats.sorted[k - 1];
53
+ }
54
+ const value = stats.rankValue?.(rule.rank, top, !!rule.isPercent);
55
+ return value !== undefined && Number.isFinite(value) ? value : undefined;
56
+ };
57
+ export const useConditionalFormatting = ({ sheetId, theme, conditionalFormats, locale, getValidationValue, isNumberValue, getSheetRowCount, getSheetColumnCount, window: evaluationWindow, getConditionalFormatResult, getConditionalFormatRuleStats, }) => {
58
+ // Whole-range statistics of windowed rules, keyed by rule id. An entry is
59
+ // reused while the rule object and the data getters are unchanged —
60
+ // scrolling (a new window) re-runs the memo below without re-scanning the
61
+ // full range, and any edit (new getter identity) or rule change
62
+ // invalidates it.
63
+ const fullRangeStatsCache = useRef(new Map());
43
64
  const previousEffectiveValueMap = useRef(undefined);
44
65
  // Lazy initialization
45
66
  const getPreviousValueMap = useCallback(() => {
@@ -73,17 +94,8 @@ export const useConditionalFormatting = ({ sheetId, theme, conditionalFormats, l
73
94
  if (!conditionalFormats) {
74
95
  return formattingByCell;
75
96
  }
76
- const sortedRules = conditionalFormats
77
- .map((rule, index) => ({ rule, index }))
78
- .sort((left, right) => {
79
- const leftPriority = left.rule.priority ?? Number.POSITIVE_INFINITY;
80
- const rightPriority = right.rule.priority ?? Number.POSITIVE_INFINITY;
81
- if (leftPriority === rightPriority) {
82
- return left.index - right.index;
83
- }
84
- return leftPriority - rightPriority;
85
- })
86
- .map(({ rule }) => rule);
97
+ // Excel precedence: the first rule (lowest `priority`) is evaluated first and wins conflicts.
98
+ const sortedRules = sortConditionalFormatRules(conditionalFormats);
87
99
  const rules = evaluationWindow
88
100
  ? windowConditionalFormatRules({
89
101
  rules: sortedRules,
@@ -131,6 +143,66 @@ export const useConditionalFormatting = ({ sheetId, theme, conditionalFormats, l
131
143
  }
132
144
  }
133
145
  };
146
+ // Every numeric covered cell of a rule on this sheet, across all of its
147
+ // (clamped) ranges — the population Excel resolves cfvo thresholds over.
148
+ const collectRuleNumbers = (rule) => {
149
+ const cells = [];
150
+ for (const range of rule.ranges) {
151
+ if (range?.sheetId !== sheetId)
152
+ continue;
153
+ for (const [rowIndex, columnIndex] of iterateCellsInRange(clampRange(range))) {
154
+ const v = getValidationValue(sheetId, rowIndex, columnIndex, rule);
155
+ if (!isNil(v) &&
156
+ typeof v !== "boolean" &&
157
+ isNumberValue(sheetId, rowIndex, columnIndex) &&
158
+ Number.isFinite(Number(v))) {
159
+ cells.push({ rowIndex, columnIndex, value: Number(v) });
160
+ }
161
+ }
162
+ }
163
+ return cells;
164
+ };
165
+ // FORMULA cfvo thresholds: a constant or a single same-sheet cell
166
+ // reference (`=$B$1`) — the forms Excel's rule dialog produces.
167
+ const resolveFormula = (formula) => {
168
+ const match = /^=?\s*\$?([A-Z]{1,3})\$?(\d+)\s*$/i.exec(formula);
169
+ if (!match)
170
+ return undefined;
171
+ const cell = addressToCell(`${match[1]}${match[2]}`);
172
+ if (!cell)
173
+ return undefined;
174
+ const value = getValidationValue(sheetId, cell.rowIndex, cell.columnIndex);
175
+ const num = typeof value === "boolean" ? NaN : Number(value);
176
+ return isNil(value) || value === "" || !Number.isFinite(num)
177
+ ? undefined
178
+ : num;
179
+ };
180
+ const originalRuleById = new Map(sortedRules.map((rule) => [rule.id, rule]));
181
+ // Statistics over the rule's FULL range when the window cut it (Excel
182
+ // resolves thresholds over every covered cell, not the visible slice);
183
+ // `undefined` for a rule evaluated whole, whose loaded values are exact.
184
+ const fullRangeStats = (rule) => {
185
+ const original = originalRuleById.get(rule.id);
186
+ if (!original || original === rule)
187
+ return undefined;
188
+ const cache = fullRangeStatsCache.current;
189
+ const hit = cache.get(rule.id);
190
+ if (hit &&
191
+ hit.rule === original &&
192
+ hit.getValidationValue === getValidationValue &&
193
+ hit.isNumberValue === isNumberValue) {
194
+ return hit.stats;
195
+ }
196
+ const stats = getConditionalFormatRuleStats?.(sheetId, original) ??
197
+ buildCfRangeStats(collectRuleNumbers(original).map((cell) => cell.value));
198
+ cache.set(rule.id, {
199
+ rule: original,
200
+ getValidationValue,
201
+ isNumberValue,
202
+ stats,
203
+ });
204
+ return stats;
205
+ };
134
206
  // There can be conditions applied
135
207
  // to the same range
136
208
  // So to get previous value, we have to save it
@@ -171,10 +243,13 @@ export const useConditionalFormatting = ({ sheetId, theme, conditionalFormats, l
171
243
  numericValues.push(Number(value));
172
244
  }
173
245
  }
174
- if (numericValues.length) {
175
- averageValue =
176
- numericValues.reduce((sum, entry) => sum + entry, 0) /
177
- numericValues.length;
246
+ const above = conditionType === "NUMBER_ABOVE_AVERAGE";
247
+ const fullStats = fullRangeStats(rule);
248
+ if (fullStats) {
249
+ averageValue = averageBoundFromStats(fullStats, above, booleanRule.stdDev);
250
+ }
251
+ else if (numericValues.length) {
252
+ averageValue = averageBound(numericValues, above, booleanRule.stdDev);
178
253
  }
179
254
  }
180
255
  // Formula path vs sync path: see `isConditionalFormatFormulaRule`
@@ -195,10 +270,15 @@ export const useConditionalFormatting = ({ sheetId, theme, conditionalFormats, l
195
270
  isNumberValue(sheetId, rowIndex, columnIndex)) {
196
271
  const numericValue = Number(effectiveValue);
197
272
  if (Number.isFinite(numericValue)) {
273
+ const inclusive = booleanRule.equalAverage === true;
198
274
  satisfies =
199
275
  conditionType === "NUMBER_ABOVE_AVERAGE"
200
- ? numericValue > averageValue
201
- : numericValue < averageValue;
276
+ ? inclusive
277
+ ? numericValue >= averageValue
278
+ : numericValue > averageValue
279
+ : inclusive
280
+ ? numericValue <= averageValue
281
+ : numericValue < averageValue;
202
282
  }
203
283
  }
204
284
  }
@@ -257,7 +337,7 @@ export const useConditionalFormatting = ({ sheetId, theme, conditionalFormats, l
257
337
  }
258
338
  values.push(rangeValues);
259
339
  }
260
- const colors = getGradientColors(values, gradientRule, theme);
340
+ const colors = getGradientColors(values, gradientRule, theme, fullRangeStats(rule));
261
341
  let rangeIndex = 0;
262
342
  // Apply colors
263
343
  for (const range of ranges) {
@@ -322,7 +402,11 @@ export const useConditionalFormatting = ({ sheetId, theme, conditionalFormats, l
322
402
  const sorted = [...numericCells].sort((a, b) => topBottomRule.type === "TOP"
323
403
  ? b.value - a.value
324
404
  : a.value - b.value);
325
- const thresholdValue = sorted[Math.min(desiredRank - 1, sorted.length - 1)]?.value;
405
+ // A windowed rule ranks against its full range.
406
+ const fullStats = fullRangeStats(rule);
407
+ const thresholdValue = fullStats
408
+ ? fullRangeRankValue(fullStats, topBottomRule)
409
+ : sorted[Math.min(desiredRank - 1, sorted.length - 1)]?.value;
326
410
  if (thresholdValue === undefined) {
327
411
  continue;
328
412
  }
@@ -391,127 +475,137 @@ export const useConditionalFormatting = ({ sheetId, theme, conditionalFormats, l
391
475
  }
392
476
  }
393
477
  else if (iconSetRule) {
394
- const glyphs = ICON_SET_GLYPHS[iconSetRule.iconSet];
395
- if (!glyphs) {
478
+ const iconCount = ICON_SET_GLYPHS[iconSetRule.iconSet]?.length;
479
+ if (!iconCount) {
396
480
  conditionIndex++;
397
481
  continue;
398
482
  }
399
- const orderedGlyphs = iconSetRule.reverse
400
- ? [...glyphs].reverse()
401
- : glyphs;
402
- const orderedColors = iconSetRule.reverse
403
- ? [...ICON_SET_COLORS[iconSetRule.iconSet]].reverse()
404
- : ICON_SET_COLORS[iconSetRule.iconSet];
405
- for (const range of ranges) {
406
- if (range.sheetId !== sheetId)
407
- continue;
408
- const clampedRange = clampRange(range);
409
- // Aggregate range min/max for PERCENT/PERCENTILE threshold resolution.
410
- let rangeMin = Infinity;
411
- let rangeMax = -Infinity;
412
- const cellValues = [];
413
- for (const [rowIndex, columnIndex] of iterateCellsInRange(clampedRange)) {
414
- const v = getValidationValue(sheetId, rowIndex, columnIndex, rule);
415
- if (!isNil(v) &&
416
- isNumberValue(sheetId, rowIndex, columnIndex) &&
417
- Number.isFinite(Number(v))) {
418
- const num = Number(v);
419
- cellValues.push({ rowIndex, columnIndex, value: num });
420
- if (num < rangeMin)
421
- rangeMin = num;
422
- if (num > rangeMax)
423
- rangeMax = num;
424
- }
483
+ // Thresholds resolve over the rule's whole applies-to range.
484
+ const cellValues = collectRuleNumbers(rule);
485
+ if (cellValues.length === 0) {
486
+ conditionIndex++;
487
+ continue;
488
+ }
489
+ const stats = fullRangeStats(rule) ??
490
+ buildCfRangeStats(cellValues.map((cell) => cell.value));
491
+ const thresholds = iconSetRule.thresholds
492
+ .slice(0, iconCount - 1)
493
+ .map((t) => resolveCfThreshold(t, stats, { resolveFormula }));
494
+ const strict = iconSetRule.thresholds
495
+ .slice(0, iconCount - 1)
496
+ .map((t) => t.gte === false);
497
+ const hideValue = iconSetRule.showValue === false;
498
+ // The icon a bucket shows: the custom mix when set, else the
499
+ // family's icon (reversed when asked).
500
+ const bucketIcon = (bucket) => {
501
+ const custom = iconSetRule.icons?.[bucket];
502
+ if (custom) {
503
+ return custom.iconSet === "NoIcons"
504
+ ? undefined
505
+ : { iconSet: custom.iconSet, iconId: custom.iconId };
425
506
  }
426
- if (cellValues.length === 0)
507
+ return {
508
+ iconSet: iconSetRule.iconSet,
509
+ iconId: iconSetRule.reverse ? iconCount - 1 - bucket : bucket,
510
+ };
511
+ };
512
+ for (const cell of cellValues) {
513
+ const cellId = cellIdentifier(cell.rowIndex, cell.columnIndex);
514
+ if (stopCells.has(cellId))
427
515
  continue;
428
- const sortedThresholds = iconSetRule.thresholds
429
- .map((t) => resolveThreshold(t, rangeMin, rangeMax))
430
- .filter((n) => Number.isFinite(n))
431
- .sort((a, b) => a - b);
432
- for (const cell of cellValues) {
433
- const bucket = pickIconBucket(cell.value, sortedThresholds);
434
- const cellId = cellIdentifier(cell.rowIndex, cell.columnIndex);
435
- if (stopCells.has(cellId))
436
- continue;
437
- const glyphIndex = Math.min(bucket, orderedGlyphs.length - 1);
438
- const glyph = orderedGlyphs[glyphIndex];
439
- const color = orderedColors[Math.min(bucket, orderedColors.length - 1)];
516
+ const icon = bucketIcon(pickIconBucket(cell.value, thresholds, strict));
517
+ if (icon) {
440
518
  layerFormat(cellId, {
441
- // iconSet + iconId are needed by the icon column filter to
442
- // match cells against a specific (iconSet, iconId) target.
443
- // They're harmless to renderers that only read `glyph`.
519
+ // iconSet + iconId drive the painter and the icon column
520
+ // filter; `glyph` / `color` are the text stand-ins.
444
521
  conditionalIcon: {
445
- glyph,
446
- color,
447
- iconSet: iconSetRule.iconSet,
448
- iconId: glyphIndex,
522
+ glyph: ICON_SET_GLYPHS[icon.iconSet]?.[icon.iconId] ?? "",
523
+ color: ICON_SET_COLORS[icon.iconSet]?.[icon.iconId],
524
+ iconSet: icon.iconSet,
525
+ iconId: icon.iconId,
526
+ ...(hideValue ? { hideValue } : {}),
449
527
  },
450
528
  });
451
- if (rule.stopIfTrue)
452
- stopCells.add(cellId);
453
529
  }
530
+ if (rule.stopIfTrue)
531
+ stopCells.add(cellId);
454
532
  }
455
533
  }
456
534
  else if (dataBarRule) {
535
+ // Excel resolves a data bar's bounds over the rule's whole applies-to
536
+ // range (every area of a multi-area rule together).
537
+ const cellValues = collectRuleNumbers(rule);
538
+ if (cellValues.length === 0) {
539
+ conditionIndex++;
540
+ continue;
541
+ }
542
+ const stats = fullRangeStats(rule) ??
543
+ buildCfRangeStats(cellValues.map((cell) => cell.value));
544
+ const resolvedMin = resolveCfThreshold(dataBarRule.minpoint, stats, {
545
+ role: "min",
546
+ resolveFormula,
547
+ });
548
+ const resolvedMax = resolveCfThreshold(dataBarRule.maxpoint, stats, {
549
+ role: "max",
550
+ resolveFormula,
551
+ });
552
+ const min = Number.isFinite(resolvedMin) ? resolvedMin : stats.min;
553
+ const max = Number.isFinite(resolvedMax) ? resolvedMax : stats.max;
457
554
  const barColor = getStringifiedColor(dataBarRule.color, theme);
458
555
  const negativeColor = dataBarRule.negativeColor
459
556
  ? getStringifiedColor(dataBarRule.negativeColor, theme)
460
- : undefined;
557
+ : barColor;
461
558
  const borderColor = dataBarRule.borderColor
462
559
  ? getStringifiedColor(dataBarRule.borderColor, theme)
463
560
  : undefined;
561
+ const negativeBorderColor = dataBarRule.negativeBorderColor
562
+ ? getStringifiedColor(dataBarRule.negativeBorderColor, theme)
563
+ : borderColor;
564
+ const axisColor = dataBarRule.axisColor
565
+ ? getStringifiedColor(dataBarRule.axisColor, theme)
566
+ : undefined;
464
567
  const direction = dataBarRule.direction === "rightToLeft"
465
568
  ? "rightToLeft"
466
569
  : "leftToRight";
467
- for (const range of ranges) {
468
- if (range.sheetId !== sheetId)
570
+ const hideValue = dataBarRule.showValue === false;
571
+ for (const cell of cellValues) {
572
+ const cellId = cellIdentifier(cell.rowIndex, cell.columnIndex);
573
+ if (stopCells.has(cellId))
469
574
  continue;
470
- const clampedRange = clampRange(range);
471
- let rangeMin = Infinity;
472
- let rangeMax = -Infinity;
473
- const cellValues = [];
474
- for (const [rowIndex, columnIndex] of iterateCellsInRange(clampedRange)) {
475
- const v = getValidationValue(sheetId, rowIndex, columnIndex, rule);
476
- if (!isNil(v) &&
477
- isNumberValue(sheetId, rowIndex, columnIndex) &&
478
- Number.isFinite(Number(v))) {
479
- const num = Number(v);
480
- cellValues.push({ rowIndex, columnIndex, value: num });
481
- if (num < rangeMin)
482
- rangeMin = num;
483
- if (num > rangeMax)
484
- rangeMax = num;
485
- }
486
- }
487
- if (cellValues.length === 0)
575
+ const geometry = computeDataBarGeometry({
576
+ value: cell.value,
577
+ min,
578
+ max,
579
+ axisPosition: dataBarRule.axisPosition,
580
+ minLength: dataBarRule.minLength,
581
+ maxLength: dataBarRule.maxLength,
582
+ direction,
583
+ });
584
+ if (!geometry)
488
585
  continue;
489
- const min = resolveThreshold(dataBarRule.minpoint, rangeMin, rangeMax);
490
- const max = resolveThreshold(dataBarRule.maxpoint, rangeMin, rangeMax);
491
- const resolvedMin = Number.isFinite(min) ? min : rangeMin;
492
- const resolvedMax = Number.isFinite(max) ? max : rangeMax;
493
- for (const cell of cellValues) {
494
- const cellId = cellIdentifier(cell.rowIndex, cell.columnIndex);
495
- if (stopCells.has(cellId))
496
- continue;
497
- const isNegative = cell.value < 0 && negativeColor !== undefined;
498
- const fill = computeDataBarFill(isNegative ? -cell.value : cell.value, isNegative ? 0 : Math.max(0, resolvedMin), isNegative
499
- ? Math.abs(resolvedMin)
500
- : Math.max(resolvedMin, resolvedMax));
501
- layerFormat(cellId, {
502
- conditionalDataBar: {
503
- color: isNegative
504
- ? negativeColor
505
- : barColor,
506
- fillFraction: fill,
507
- negative: isNegative,
508
- borderColor,
509
- direction,
510
- },
511
- });
512
- if (rule.stopIfTrue)
513
- stopCells.add(cellId);
514
- }
586
+ layerFormat(cellId, {
587
+ conditionalDataBar: {
588
+ color: geometry.negative ? negativeColor : barColor,
589
+ fillFraction: geometry.barEnd - geometry.barStart,
590
+ negative: geometry.negative,
591
+ borderColor: geometry.negative
592
+ ? negativeBorderColor
593
+ : borderColor,
594
+ direction,
595
+ barStart: geometry.barStart,
596
+ barEnd: geometry.barEnd,
597
+ gradient: dataBarRule.gradient !== false,
598
+ ...(geometry.axisPosition !== undefined
599
+ ? {
600
+ axisPosition: geometry.axisPosition,
601
+ axisColor: axisColor ?? "#000000",
602
+ }
603
+ : {}),
604
+ ...(hideValue ? { hideValue } : {}),
605
+ },
606
+ });
607
+ if (rule.stopIfTrue)
608
+ stopCells.add(cellId);
515
609
  }
516
610
  }
517
611
  conditionIndex++;
@@ -530,5 +624,6 @@ export const useConditionalFormatting = ({ sheetId, theme, conditionalFormats, l
530
624
  getSheetColumnCount,
531
625
  evaluationWindow,
532
626
  getConditionalFormatResult,
627
+ getConditionalFormatRuleStats,
533
628
  ]);
534
629
  };
@@ -1,6 +1,8 @@
1
1
  export * from "./components/canvas-grid";
2
2
  export * from "./components/canvas-grid/typings";
3
3
  export * from "./components/canvas-grid/helpers";
4
+ export * from "./components/canvas-grid/page-breaks";
5
+ export * from "./components/cf-icon-preview";
4
6
  export * from "./providers/spreadsheet-provider";
5
7
  export * from "./components/sheet-switcher";
6
8
  export * from "./components/sheet-switcher/new-sheet-button";
@@ -20,6 +22,7 @@ export * from "./api/move-overwrite";
20
22
  export * from "./components/evaluate-formula-dialog";
21
23
  export * from "./components/watch-window";
22
24
  export * from "./components/calculation-options-dialog";
25
+ export * from "./components/protect-sheet-dialog";
23
26
  export { resolveGoToReference, type GoToResolverContext } from "./api/go-to";
24
27
  export * from "./api/go-to-special";
25
28
  export * from "./api/excel-validation-kinds";
@@ -67,7 +70,9 @@ export * from "./api/table";
67
70
  export * from "./api/heatmap";
68
71
  export * from "./api/banded-ranges";
69
72
  export * from "./api/cf-overlays";
73
+ export * from "./api/cf-icons";
70
74
  export * from "./api/cf-engine";
75
+ export * from "./api/cf-priority";
71
76
  export * from "./api/fill-patterns";
72
77
  export type { AvailableIcon } from "./components/filter-box";
73
78
  export * from "./hooks";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../index.tsx"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,sCAAsC,CAAC;AACrD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AAEjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8CAA8C,CAAC;AAC7D,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,0CAA0C,CAAC;AACzD,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,cAAc,mCAAmC,CAAC;AAClD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,qCAAqC,CAAC;AACpD,cAAc,sBAAsB,CAAC;AACrC,cAAc,sCAAsC,CAAC;AACrD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yCAAyC,CAAC;AACxD,cAAc,mCAAmC,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC7E,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mBAAmB,CAAC;AAClC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uCAAuC,CAAC;AACtD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,0CAA0C,CAAC;AACzD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mCAAmC,CAAC;AAClD,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oCAAoC,CAAC;AAEnD,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,cAAc,SAAS,CAAC;AACxB,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,8CAA8C,CAAC;AAC7D,cAAc,mDAAmD,CAAC;AAClE,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,EAC9B,4BAA4B,EAC5B,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,oBAAoB,GACrB,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACxE,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,6BAA6B,CAAC;AAC5C,YAAY,EACV,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,KAAK,sBAAsB,EAC3B,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AACrC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,mCAAmC,CAAC;AAGlD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oCAAoC,CAAC;AAGnD,cAAc,8BAA8B,CAAC;AAG7C,cAAc,mCAAmC,CAAC;AAGlD,cAAc,mCAAmC,CAAC;AAGlD,cAAc,mCAAmC,CAAC;AAGlD,cAAc,0CAA0C,CAAC;AAGzD,cAAc,6BAA6B,CAAC;AAG5C,cAAc,8BAA8B,CAAC;AAG7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AAGrD,cAAc,sBAAsB,CAAC"}
package/dist/esm/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from "./components/canvas-grid";
2
2
  export * from "./components/canvas-grid/typings";
3
3
  export * from "./components/canvas-grid/helpers";
4
+ export * from "./components/canvas-grid/page-breaks";
5
+ export * from "./components/cf-icon-preview";
4
6
  export * from "./providers/spreadsheet-provider";
5
7
  export * from "./components/sheet-switcher";
6
8
  export * from "./components/sheet-switcher/new-sheet-button";
@@ -19,6 +21,7 @@ export * from "./api/move-overwrite";
19
21
  export * from "./components/evaluate-formula-dialog";
20
22
  export * from "./components/watch-window";
21
23
  export * from "./components/calculation-options-dialog";
24
+ export * from "./components/protect-sheet-dialog";
22
25
  export { resolveGoToReference } from "./api/go-to";
23
26
  export * from "./api/go-to-special";
24
27
  export * from "./api/excel-validation-kinds";
@@ -66,7 +69,9 @@ export * from "./api/table";
66
69
  export * from "./api/heatmap";
67
70
  export * from "./api/banded-ranges";
68
71
  export * from "./api/cf-overlays";
72
+ export * from "./api/cf-icons";
69
73
  export * from "./api/cf-engine";
74
+ export * from "./api/cf-priority";
70
75
  export * from "./api/fill-patterns";
71
76
  export * from "./hooks";
72
77
  export * from "./components/cell/typings";
@@ -1,3 +1,3 @@
1
1
  export const releaseDate =
2
2
  // @ts-ignore
3
- new Date("2026-10-30") ?? new Date("2025-06-18");
3
+ new Date("2026-11-02") ?? new Date("2025-06-18");
@@ -5,6 +5,14 @@ export declare const STANDARD_COLORS: string[];
5
5
  export declare const colorKeys: Map<ColorIndex, ThemeColors>;
6
6
  export type ColorIndex = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
7
7
  export declare const getThemeColorFromIndex: (theme: SpreadsheetTheme, index: ColorIndex, tint?: number | null) => string | undefined;
8
+ /**
9
+ * A DrawingML theme-font token (`+mn-lt`, `+mj-ea`, …: ECMA-376 Part 1, §20.1.4.1.16 `latin`
10
+ * typeface) as the family it names in `theme`: `+mn-*` is the minor (body) font,
11
+ * `+mj-*` the major (heading) font, which falls back to the body font when the theme has none.
12
+ * Any other family is returned as it is. Shapes, text boxes and rich runs keep the token (so it
13
+ * round-trips); this is what they paint with.
14
+ */
15
+ export declare const resolveThemeFontFamily: <T extends string | null | undefined>(family: T, theme: Pick<SpreadsheetTheme, "primaryFontFamily" | "headingFontFamily"> | undefined) => T | string;
8
16
  type StringifiedColorValue<T extends Color | string | undefined | null> = T extends undefined ? undefined : string;
9
17
  export declare const getStringifiedColor: <T extends Color | undefined | null>(color: T, theme: SpreadsheetTheme) => StringifiedColorValue<T>;
10
18
  export declare const createColorShades: (color: string, tints: number[]) => string[];
@@ -1 +1 @@
1
- {"version":3,"file":"themes.d.ts","sourceRoot":"","sources":["../../themes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACZ,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAQrC,eAAO,MAAM,eAAe,EAAE,gBAAgB,EAyM7C,CAAC;AAEF,eAAO,MAAM,eAAe,UAW3B,CAAC;AAEF,eAAO,MAAM,SAAS,8BAYpB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;AAGpE,eAAO,MAAM,sBAAsB,GACjC,OAAO,gBAAgB,EACvB,OAAO,UAAU,EACjB,OAAO,MAAM,GAAG,IAAI,uBAQrB,CAAC;AAEF,KAAK,qBAAqB,CAAC,CAAC,SAAS,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,IACpE,CAAC,SAAS,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAC3C,eAAO,MAAM,mBAAmB,GAAI,CAAC,SAAS,KAAK,GAAG,SAAS,GAAG,IAAI,EACpE,OAAO,CAAC,EACR,OAAO,gBAAgB,KACtB,qBAAqB,CAAC,CAAC,CASzB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,EAAE,OAAO,MAAM,EAAE,KACL,MAAM,EAChE,CAAC;AAEF,eAAO,MAAM,mBAAmB,YAY/B,CAAC"}
1
+ {"version":3,"file":"themes.d.ts","sourceRoot":"","sources":["../../themes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACZ,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAQrC,eAAO,MAAM,eAAe,EAAE,gBAAgB,EAyM7C,CAAC;AAEF,eAAO,MAAM,eAAe,UAW3B,CAAC;AAEF,eAAO,MAAM,SAAS,8BAYpB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;AAGpE,eAAO,MAAM,sBAAsB,GACjC,OAAO,gBAAgB,EACvB,OAAO,UAAU,EACjB,OAAO,MAAM,GAAG,IAAI,uBAQrB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAI,CAAC,SAAS,MAAM,GAAG,IAAI,GAAG,SAAS,EACxE,QAAQ,CAAC,EACT,OAAO,IAAI,CAAC,gBAAgB,EAAE,mBAAmB,GAAG,mBAAmB,CAAC,GAAG,SAAS,KACnF,CAAC,GAAG,MAON,CAAC;AAEF,KAAK,qBAAqB,CAAC,CAAC,SAAS,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,IACpE,CAAC,SAAS,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAC3C,eAAO,MAAM,mBAAmB,GAAI,CAAC,SAAS,KAAK,GAAG,SAAS,GAAG,IAAI,EACpE,OAAO,CAAC,EACR,OAAO,gBAAgB,KACtB,qBAAqB,CAAC,CAAC,CASzB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,EAAE,OAAO,MAAM,EAAE,KACR,MAAM,EAC7D,CAAC;AAEF,eAAO,MAAM,mBAAmB,YAY/B,CAAC"}
@@ -1,4 +1,4 @@
1
- import { isNil, lightenColor } from "@rowsncolumns/utils";
1
+ import { applyTint, isNil } from "@rowsncolumns/utils";
2
2
  const commonDarkColors = {
3
3
  background1: "rgb(17, 17, 17)",
4
4
  text1: "#FFFFFF",
@@ -238,9 +238,26 @@ export const getThemeColorFromIndex = (theme, index, tint) => {
238
238
  return color;
239
239
  }
240
240
  else {
241
- return lightenColor(tint, color);
241
+ return applyTint(tint, color);
242
242
  }
243
243
  };
244
+ /**
245
+ * A DrawingML theme-font token (`+mn-lt`, `+mj-ea`, …: ECMA-376 Part 1, §20.1.4.1.16 `latin`
246
+ * typeface) as the family it names in `theme`: `+mn-*` is the minor (body) font,
247
+ * `+mj-*` the major (heading) font, which falls back to the body font when the theme has none.
248
+ * Any other family is returned as it is. Shapes, text boxes and rich runs keep the token (so it
249
+ * round-trips); this is what they paint with.
250
+ */
251
+ export const resolveThemeFontFamily = (family, theme) => {
252
+ if (!family || !theme || family.charAt(0) !== "+")
253
+ return family;
254
+ const match = /^\+(mn|mj)-(lt|ea|cs)$/i.exec(family.trim());
255
+ if (!match)
256
+ return family;
257
+ return match[1].toLowerCase() === "mj"
258
+ ? theme.headingFontFamily || theme.primaryFontFamily
259
+ : theme.primaryFontFamily;
260
+ };
244
261
  export const getStringifiedColor = (color, theme) => {
245
262
  if (isNil(color) || typeof color === "string") {
246
263
  return color;
@@ -248,7 +265,7 @@ export const getStringifiedColor = (color, theme) => {
248
265
  return getThemeColorFromIndex(theme, color.theme, color.tint);
249
266
  };
250
267
  export const createColorShades = (color, tints) => {
251
- return tints.map((tint) => lightenColor(tint, color));
268
+ return tints.map((tint) => applyTint(tint, color));
252
269
  };
253
270
  export const colorTintsToDisplay = [
254
271
  [-0.05, -0.15, -0.25, -0.35, -0.5],