@rowsncolumns/spreadsheet 10.5.17 → 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 (202) 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/atoms/goal-seek-dialog.atom.d.ts +8 -3
  21. package/dist/cjs/atoms/goal-seek-dialog.atom.d.ts.map +1 -1
  22. package/dist/cjs/atoms/index.d.ts +4 -0
  23. package/dist/cjs/atoms/index.d.ts.map +1 -1
  24. package/dist/cjs/atoms/index.js +4 -0
  25. package/dist/cjs/components/canvas-grid/index.d.ts.map +1 -1
  26. package/dist/cjs/components/canvas-grid/index.js +194 -51
  27. package/dist/cjs/components/canvas-grid/overflow.d.ts +37 -0
  28. package/dist/cjs/components/canvas-grid/overflow.d.ts.map +1 -0
  29. package/dist/cjs/components/canvas-grid/overflow.js +49 -0
  30. package/dist/cjs/components/canvas-grid/page-breaks.d.ts +15 -0
  31. package/dist/cjs/components/canvas-grid/page-breaks.d.ts.map +1 -0
  32. package/dist/cjs/components/canvas-grid/page-breaks.js +77 -0
  33. package/dist/cjs/components/canvas-grid/typings.d.ts +32 -3
  34. package/dist/cjs/components/canvas-grid/typings.d.ts.map +1 -1
  35. package/dist/cjs/components/cell/alignment.d.ts +58 -1
  36. package/dist/cjs/components/cell/alignment.d.ts.map +1 -1
  37. package/dist/cjs/components/cell/alignment.js +144 -1
  38. package/dist/cjs/components/cell/cell-background.d.ts +2 -0
  39. package/dist/cjs/components/cell/cell-background.d.ts.map +1 -1
  40. package/dist/cjs/components/cell/cell-background.js +5 -6
  41. package/dist/cjs/components/cell/cell-backgrounds.d.ts.map +1 -1
  42. package/dist/cjs/components/cell/cell-backgrounds.js +5 -1
  43. package/dist/cjs/components/cell/cell-text-runs.js +1 -1
  44. package/dist/cjs/components/cell/index.d.ts.map +1 -1
  45. package/dist/cjs/components/cell/index.js +378 -37
  46. package/dist/cjs/components/cell/number-format-layout.d.ts +35 -0
  47. package/dist/cjs/components/cell/number-format-layout.d.ts.map +1 -0
  48. package/dist/cjs/components/cell/number-format-layout.js +106 -0
  49. package/dist/cjs/components/cell/typings.d.ts +22 -0
  50. package/dist/cjs/components/cell/typings.d.ts.map +1 -1
  51. package/dist/cjs/components/cell-editor/index.js +2 -2
  52. package/dist/cjs/components/cell-filter/index.d.ts.map +1 -1
  53. package/dist/cjs/components/cell-filter/index.js +3 -3
  54. package/dist/cjs/components/cell-overlay/index.d.ts +20 -0
  55. package/dist/cjs/components/cell-overlay/index.d.ts.map +1 -1
  56. package/dist/cjs/components/cell-overlay/index.js +155 -28
  57. package/dist/cjs/components/cf-icon-preview/index.d.ts +16 -0
  58. package/dist/cjs/components/cf-icon-preview/index.d.ts.map +1 -0
  59. package/dist/cjs/components/cf-icon-preview/index.js +48 -0
  60. package/dist/cjs/components/context-menu/index.d.ts.map +1 -1
  61. package/dist/cjs/components/context-menu/index.js +11 -3
  62. package/dist/cjs/components/embeds/embed-component.d.ts.map +1 -1
  63. package/dist/cjs/components/embeds/embed-component.js +3 -2
  64. package/dist/cjs/components/goal-seek-dialog/index.d.ts +15 -5
  65. package/dist/cjs/components/goal-seek-dialog/index.d.ts.map +1 -1
  66. package/dist/cjs/components/goal-seek-dialog/index.js +145 -42
  67. package/dist/cjs/components/hidden-markers/index.d.ts.map +1 -1
  68. package/dist/cjs/components/hidden-markers/index.js +8 -7
  69. package/dist/cjs/components/hidden-markers/style.d.ts +7 -0
  70. package/dist/cjs/components/hidden-markers/style.d.ts.map +1 -1
  71. package/dist/cjs/components/hidden-markers/style.js +13 -2
  72. package/dist/cjs/components/protect-sheet-dialog/index.d.ts +67 -0
  73. package/dist/cjs/components/protect-sheet-dialog/index.d.ts.map +1 -0
  74. package/dist/cjs/components/protect-sheet-dialog/index.js +196 -0
  75. package/dist/cjs/components/toolbar/types.d.ts +1 -1
  76. package/dist/cjs/components/toolbar/types.d.ts.map +1 -1
  77. package/dist/cjs/config.d.ts +13 -1
  78. package/dist/cjs/config.d.ts.map +1 -1
  79. package/dist/cjs/config.js +15 -3
  80. package/dist/cjs/helpers.d.ts +10 -5
  81. package/dist/cjs/helpers.d.ts.map +1 -1
  82. package/dist/cjs/helpers.js +43 -31
  83. package/dist/cjs/hooks/use-border-styles.d.ts.map +1 -1
  84. package/dist/cjs/hooks/use-border-styles.js +5 -28
  85. package/dist/cjs/hooks/use-cell-renderer.d.ts +35 -3
  86. package/dist/cjs/hooks/use-cell-renderer.d.ts.map +1 -1
  87. package/dist/cjs/hooks/use-cell-renderer.js +85 -47
  88. package/dist/cjs/hooks/use-conditional-formatting.d.ts +13 -1
  89. package/dist/cjs/hooks/use-conditional-formatting.d.ts.map +1 -1
  90. package/dist/cjs/hooks/use-conditional-formatting.js +281 -230
  91. package/dist/cjs/index.d.ts +7 -0
  92. package/dist/cjs/index.d.ts.map +1 -1
  93. package/dist/cjs/index.js +13 -1
  94. package/dist/cjs/release-date.js +1 -1
  95. package/dist/cjs/themes.d.ts +8 -0
  96. package/dist/cjs/themes.d.ts.map +1 -1
  97. package/dist/cjs/themes.js +21 -3
  98. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  99. package/dist/cjs/types.d.ts +115 -5
  100. package/dist/cjs/types.d.ts.map +1 -1
  101. package/dist/esm/api/cf-data-bar.d.ts +73 -0
  102. package/dist/esm/api/cf-data-bar.d.ts.map +1 -0
  103. package/dist/esm/api/cf-data-bar.js +178 -0
  104. package/dist/esm/api/cf-icons.d.ts +73 -0
  105. package/dist/esm/api/cf-icons.d.ts.map +1 -0
  106. package/dist/esm/api/cf-icons.js +306 -0
  107. package/dist/esm/api/cf-overlays.d.ts +89 -3
  108. package/dist/esm/api/cf-overlays.d.ts.map +1 -1
  109. package/dist/esm/api/cf-overlays.js +223 -67
  110. package/dist/esm/api/cf-priority.d.ts +34 -0
  111. package/dist/esm/api/cf-priority.d.ts.map +1 -0
  112. package/dist/esm/api/cf-priority.js +61 -0
  113. package/dist/esm/api/heatmap.d.ts +7 -1
  114. package/dist/esm/api/heatmap.d.ts.map +1 -1
  115. package/dist/esm/api/heatmap.js +24 -9
  116. package/dist/esm/api/selections.d.ts +2 -2
  117. package/dist/esm/api/validation.d.ts +6 -0
  118. package/dist/esm/api/validation.d.ts.map +1 -1
  119. package/dist/esm/api/validation.js +6 -0
  120. package/dist/esm/atoms/goal-seek-dialog.atom.d.ts +8 -3
  121. package/dist/esm/atoms/goal-seek-dialog.atom.d.ts.map +1 -1
  122. package/dist/esm/atoms/index.d.ts +4 -0
  123. package/dist/esm/atoms/index.d.ts.map +1 -1
  124. package/dist/esm/atoms/index.js +4 -0
  125. package/dist/esm/components/canvas-grid/index.d.ts.map +1 -1
  126. package/dist/esm/components/canvas-grid/index.js +163 -47
  127. package/dist/esm/components/canvas-grid/overflow.d.ts +37 -0
  128. package/dist/esm/components/canvas-grid/overflow.d.ts.map +1 -0
  129. package/dist/esm/components/canvas-grid/overflow.js +39 -0
  130. package/dist/esm/components/canvas-grid/page-breaks.d.ts +15 -0
  131. package/dist/esm/components/canvas-grid/page-breaks.d.ts.map +1 -0
  132. package/dist/esm/components/canvas-grid/page-breaks.js +50 -0
  133. package/dist/esm/components/canvas-grid/typings.d.ts +32 -3
  134. package/dist/esm/components/canvas-grid/typings.d.ts.map +1 -1
  135. package/dist/esm/components/cell/alignment.d.ts +58 -1
  136. package/dist/esm/components/cell/alignment.d.ts.map +1 -1
  137. package/dist/esm/components/cell/alignment.js +110 -1
  138. package/dist/esm/components/cell/cell-background.d.ts +2 -0
  139. package/dist/esm/components/cell/cell-background.d.ts.map +1 -1
  140. package/dist/esm/components/cell/cell-background.js +4 -5
  141. package/dist/esm/components/cell/cell-backgrounds.d.ts.map +1 -1
  142. package/dist/esm/components/cell/cell-backgrounds.js +5 -1
  143. package/dist/esm/components/cell/cell-text-runs.js +2 -2
  144. package/dist/esm/components/cell/index.d.ts.map +1 -1
  145. package/dist/esm/components/cell/index.js +339 -39
  146. package/dist/esm/components/cell/number-format-layout.d.ts +35 -0
  147. package/dist/esm/components/cell/number-format-layout.d.ts.map +1 -0
  148. package/dist/esm/components/cell/number-format-layout.js +99 -0
  149. package/dist/esm/components/cell/typings.d.ts +22 -0
  150. package/dist/esm/components/cell/typings.d.ts.map +1 -1
  151. package/dist/esm/components/cell-editor/index.js +2 -2
  152. package/dist/esm/components/cell-filter/index.d.ts.map +1 -1
  153. package/dist/esm/components/cell-filter/index.js +4 -4
  154. package/dist/esm/components/cell-overlay/index.d.ts +20 -0
  155. package/dist/esm/components/cell-overlay/index.d.ts.map +1 -1
  156. package/dist/esm/components/cell-overlay/index.js +111 -25
  157. package/dist/esm/components/cf-icon-preview/index.d.ts +16 -0
  158. package/dist/esm/components/cf-icon-preview/index.d.ts.map +1 -0
  159. package/dist/esm/components/cf-icon-preview/index.js +41 -0
  160. package/dist/esm/components/context-menu/index.d.ts.map +1 -1
  161. package/dist/esm/components/context-menu/index.js +11 -3
  162. package/dist/esm/components/embeds/embed-component.d.ts.map +1 -1
  163. package/dist/esm/components/embeds/embed-component.js +4 -3
  164. package/dist/esm/components/goal-seek-dialog/index.d.ts +15 -5
  165. package/dist/esm/components/goal-seek-dialog/index.d.ts.map +1 -1
  166. package/dist/esm/components/goal-seek-dialog/index.js +126 -29
  167. package/dist/esm/components/hidden-markers/index.d.ts.map +1 -1
  168. package/dist/esm/components/hidden-markers/index.js +9 -8
  169. package/dist/esm/components/hidden-markers/style.d.ts +7 -0
  170. package/dist/esm/components/hidden-markers/style.d.ts.map +1 -1
  171. package/dist/esm/components/hidden-markers/style.js +8 -1
  172. package/dist/esm/components/protect-sheet-dialog/index.d.ts +67 -0
  173. package/dist/esm/components/protect-sheet-dialog/index.d.ts.map +1 -0
  174. package/dist/esm/components/protect-sheet-dialog/index.js +154 -0
  175. package/dist/esm/components/toolbar/types.d.ts +1 -1
  176. package/dist/esm/components/toolbar/types.d.ts.map +1 -1
  177. package/dist/esm/config.d.ts +13 -1
  178. package/dist/esm/config.d.ts.map +1 -1
  179. package/dist/esm/config.js +13 -1
  180. package/dist/esm/helpers.d.ts +10 -5
  181. package/dist/esm/helpers.d.ts.map +1 -1
  182. package/dist/esm/helpers.js +40 -28
  183. package/dist/esm/hooks/use-border-styles.d.ts.map +1 -1
  184. package/dist/esm/hooks/use-border-styles.js +5 -26
  185. package/dist/esm/hooks/use-cell-renderer.d.ts +35 -3
  186. package/dist/esm/hooks/use-cell-renderer.d.ts.map +1 -1
  187. package/dist/esm/hooks/use-cell-renderer.js +83 -42
  188. package/dist/esm/hooks/use-conditional-formatting.d.ts +13 -1
  189. package/dist/esm/hooks/use-conditional-formatting.d.ts.map +1 -1
  190. package/dist/esm/hooks/use-conditional-formatting.js +215 -120
  191. package/dist/esm/index.d.ts +7 -0
  192. package/dist/esm/index.d.ts.map +1 -1
  193. package/dist/esm/index.js +7 -0
  194. package/dist/esm/release-date.js +1 -1
  195. package/dist/esm/themes.d.ts +8 -0
  196. package/dist/esm/themes.d.ts.map +1 -1
  197. package/dist/esm/themes.js +20 -3
  198. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  199. package/dist/esm/types.d.ts +115 -5
  200. package/dist/esm/types.d.ts.map +1 -1
  201. package/dist/spreadsheet.min.css +1 -1
  202. package/package.json +4 -4
@@ -23,6 +23,10 @@ export * from "./go-to-dialog.atom";
23
23
  export * from "./move-overwrite-confirm.atom";
24
24
  export * from "./evaluate-formula-dialog.atom";
25
25
  export * from "./remove-duplicates-dialog.atom";
26
+ export * from "./text-to-columns-dialog.atom";
27
+ export * from "./subtotal-dialog.atom";
28
+ export * from "./goal-seek-dialog.atom";
29
+ export * from "./advanced-filter-dialog.atom";
26
30
  export * from "./watch-window.atom";
27
31
  export * from "./insert-cells-dialog.atom";
28
32
  export * from "./insert-options.atom";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/canvas-grid/index.tsx"],"names":[],"mappings":"AAqDA,OAAO,KASN,MAAM,OAAO,CAAC;AAyNf,OAAO,KAAK,EAGV,QAAQ,EAWT,MAAM,aAAa,CAAC;AAoBrB,OAAO,KAAK,EACV,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EAEhB,MAAM,WAAW,CAAC;AA+jMnB,eAAO,MAAM,UAAU,EAA4C,CACjE,CAAC,SAAS,QAAQ,CAAC,GAAG,CAAC,EAEvB,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,GACvB,wBAAwB,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;CAAE,KAChE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/canvas-grid/index.tsx"],"names":[],"mappings":"AAsDA,OAAO,KASN,MAAM,OAAO,CAAC;AAgOf,OAAO,KAAK,EAGV,QAAQ,EAWT,MAAM,aAAa,CAAC;AAoBrB,OAAO,KAAK,EACV,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EAEhB,MAAM,WAAW,CAAC;AA6sMnB,eAAO,MAAM,UAAU,EAA4C,CACjE,CAAC,SAAS,QAAQ,CAAC,GAAG,CAAC,EAEvB,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,GACvB,wBAAwB,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;CAAE,KAChE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC"}
@@ -5,7 +5,7 @@ import { getBoundedCells, MouseButtonCodes } from "@rowsncolumns/grid";
5
5
  import { isCellWithinBounds } from "@rowsncolumns/grid";
6
6
  import { cellIdentifier, Grid as BaseGrid, isEqualCells, } from "@rowsncolumns/grid";
7
7
  import { cn, DropdownMenuContent, DropdownMenuPortal, Skeleton, tryParseRichText, } from "@rowsncolumns/ui";
8
- import { cellToAddress, getCellEffectiveFormat, getContrastColor, getFormulaLocale, getEffectiveDataValidationConditionType, isConditionalFormatFormulaRule, isDataValidationFormulaRule, isNil, isNilOrBlank, iterateCellsInRange, localizeCellInput, localizeFormula, localizeFunctionDescriptions, log, resolveDefaultHorizontalAlignment, ssfFormatColor, uuid, } from "@rowsncolumns/utils";
8
+ import { cellToAddress, getCellEffectiveFormat, getContrastColor, getFormulaLocale, getEffectiveDataValidationConditionType, isConditionalFormatFormulaRule, isDataValidationFormulaRule, isNil, isNilOrBlank, iterateCellsInRange, localizeCellInput, localizeFormula, localizeFunctionDescriptions, log, resolveDefaultHorizontalAlignment, ssfFormat, ssfFormatColor, uuid, } from "@rowsncolumns/utils";
9
9
  import { useStore } from "jotai";
10
10
  import merge from "lodash/merge";
11
11
  import throttle from "lodash/throttle";
@@ -14,6 +14,7 @@ import { getBandedCells } from "../../api/banded-ranges";
14
14
  import { clearRangeForInsertedBand, formatsForInsertOption, insertedBandHasValues, } from "../../api/insert-options";
15
15
  import { keepsCalculatedColumnTag, } from "../../api/calculated-column-fill";
16
16
  import { keepsTableAutoExpansionTag, } from "../../api/table-auto-expansion";
17
+ import { isConditionalFormatNumberCell, isDarkCssColor, } from "../../api/cf-overlays";
17
18
  import { CF_INITIAL_WINDOW, cfWindowForViewport, isSameCfWindow, } from "../../api/cf-window";
18
19
  import { generateSelectionsFromFormula } from "../../api/selections";
19
20
  import { SpreadsheetApi } from "../../api/spreadsheet-api";
@@ -21,7 +22,7 @@ import { findActiveTableWithinCell } from "../../api/table";
21
22
  import { getDataValidationTooltipContent } from "../../api/validation-tooltip";
22
23
  import { resolveGoToSpecial } from "../../api/go-to-special";
23
24
  import { checkExcelValidationValue, isFormulaEntry, } from "../../api/excel-validation-kinds";
24
- import { checkBooleanRule, decideValidationCommit, isCellLockedUnderProtection, isProtectedCell, isProtectedSheet, showValidationDropdownArrow, } from "../../api/validation";
25
+ import { checkBooleanRule, decideValidationCommit, isCellFormulaHiddenUnderProtection, isCellLockedUnderProtection, isProtectedCell, isProtectedSheet, } from "../../api/validation";
25
26
  import { useFormulaModeValue, useIsEvaluateFormulaDialogMounted, useIsGoToDialogMounted, useIsMoveOverwriteConfirmMounted, useIsPasteSpecialDialogMounted, useOpenEvaluateFormulaDialog, useOpenGoToDialog, useOpenMoveOverwriteConfirm, useOpenPasteSpecialDialog, useSetNoteEditorCell, useSetPinnedTooltip, useFillOptionsState, useInsertOptionsState, useTableAutoExpansionState, useCalculatedColumnFillState, useOpenFillSeriesDialog, useShowPasteMenu, useShowValidationAlert, } from "../../atoms";
26
27
  import { useActiveEditor } from "../../atoms/active-editor.atom";
27
28
  import { useAddWatch, useIsWatchWindowMounted, useSetWatchWindowContext, } from "../../atoms/watch-window.atom";
@@ -32,12 +33,14 @@ import { useFormulaSelections } from "../../atoms/formula-selections.atom";
32
33
  import { useQuickEditState } from "../../atoms/magic-fill-state.atom";
33
34
  import { useOnHideFormulaHelp, useOnShowFormulaHelp, useShowFormulaHelpValue, } from "../../atoms/show-formula-help.atom";
34
35
  import { useSetSpreadsheetApi } from "../../atoms/spreadsheet-api.atom";
35
- import { ARROW_DOWN_WIDTH, CALCULATED_ICON_WIDTH, CELL_HORIZONTAL_ALIGNMENT, CF_ICON_SPACING, CF_ICON_WIDTH, CHIP_COLOR, CHIP_SPACING, COLUMN_HEADER_HEIGHT, DEFAULT_ACTIVE_CELL, DEFAULT_ARRAY, DEFAULT_CELL_BACKGROUND_COLOR, DEFAULT_CELL_COLOR, DEFAULT_CELL_SPACING, DEFAULT_COLUMN_COUNT, DEFAULT_COLUMN_WIDTH, DEFAULT_FONT_SIZE_PT, DEFAULT_HEADER_ACTIVE_BG, DEFAULT_HEADER_ACTIVE_TABLE_BG, DEFAULT_HEADER_BG, DEFAULT_HEADER_BORDER_COLOR, DEFAULT_HEADER_COLOR, DEFAULT_HEADER_SELECTED_BG, DEFAULT_HEADER_SELECTED_TABLE_BG, DEFAULT_HEADER_TABLE_BG, DEFAULT_ROW_COUNT, DEFAULT_ROW_HEIGHT, DEFAULT_SCROLL_POSITION, defaultSpreadsheetTheme, EXPAND_COLLAPSE_ICON_WIDTH, FILTER_ICON_WIDTH, GRIDLINE_COLOR, HEADER_TEXT_FORMAT, INDENT_SPACING, MAX_COLUMN_COUNT, MAX_ROW_COUNT, MIN_COLUMN_WIDTH, ROW_HEADER_WIDTH, SCROLLBAR_SIZE, SELECTION_BG, SELECTION_BORDER, } from "../../config";
36
+ import { ARROW_DOWN_WIDTH, CALCULATED_ICON_WIDTH, CELL_HORIZONTAL_ALIGNMENT, CF_ICON_SPACING, CF_ICON_WIDTH, CHIP_COLOR, CHIP_SPACING, COLUMN_HEADER_HEIGHT, DEFAULT_ACTIVE_CELL, DEFAULT_ARRAY, DEFAULT_CELL_BACKGROUND_COLOR, DEFAULT_CELL_COLOR, DEFAULT_CELL_SPACING, DEFAULT_COLUMN_COUNT, DEFAULT_COLUMN_WIDTH, DEFAULT_FONT_SIZE_PT, DEFAULT_HEADER_ACTIVE_BG, DEFAULT_HEADER_ACTIVE_TABLE_BG, DEFAULT_HEADER_BG, DEFAULT_HEADER_BORDER_COLOR, DEFAULT_HEADER_COLOR, DEFAULT_HEADER_SELECTED_BG, DEFAULT_HEADER_SELECTED_TABLE_BG, DEFAULT_HEADER_TABLE_BG, DEFAULT_ROW_COUNT, DEFAULT_ROW_HEIGHT, DEFAULT_SCROLL_POSITION, defaultSpreadsheetTheme, EXPAND_COLLAPSE_ICON_WIDTH, FILTER_ICON_WIDTH, GRIDLINE_COLOR, HEADER_TEXT_FORMAT, FILTER_BUTTON_GLYPH_COLOR, INDENT_SPACING, MAX_COLUMN_COUNT, MAX_ROW_COUNT, MIN_COLUMN_WIDTH, ROW_HEADER_WIDTH, SCROLLBAR_SIZE, SELECTION_BG, SELECTION_BORDER, } from "../../config";
36
37
  import { definedProps, getCellEffectiveValue, getCellFormattedValue, getCellUserEnteredValue, getDefaultColumnHeader, getDefaultRowHeader, getExtendedValueBool, getExtendedValueError, getExtendedValueFormula, getExtendedValueNumber, getExtendedValueString, getTableHeaderCells, isFirefox, isStyleReference, isTouchDevice, toEditorRangeValuesAsync, } from "../../helpers";
37
38
  import { useBorderStyles } from "../../hooks/use-border-styles";
38
39
  import { useCallbackRef } from "../../hooks/use-callback-ref";
39
40
  import { useCellPopover } from "../../hooks/use-cell-popover";
40
41
  import { useCellRenderer } from "../../hooks/use-cell-renderer";
42
+ import { blocksOverflow, walkOverflowColumns } from "./overflow";
43
+ import { getPageBreakBorderStyles } from "./page-breaks";
41
44
  import { useChartSourceRanges } from "../../hooks/use-chart-source-ranges";
42
45
  import { useConditionalFormatting } from "../../hooks/use-conditional-formatting";
43
46
  import { DefaultContextMenuWrapper, useContextMenu, } from "../../hooks/use-context-menu";
@@ -127,7 +130,7 @@ function isDetachedEditor(editor) {
127
130
  return element != null && !element.isConnected;
128
131
  }
129
132
  function CanvasGridComponent(props, forwardedRef) {
130
- const { licenseKey, sheetId, sheetType, ChartSheetView: ChartSheetViewComponent = ChartSheetView, instanceId, activeCell = DEFAULT_ACTIVE_CELL, selections = DEFAULT_ARRAY, frozenColumnCount = 0, frozenRowCount = 0, rowCount = DEFAULT_ROW_COUNT, columnCount = DEFAULT_COLUMN_COUNT, autoFocus, basicFilter, tables, namedRanges, bandedRanges = DEFAULT_ARRAY, tableBorderColor = "#008000", filterIconColor = "#008000", conditionalFormats, showFilterIcon = true, showCalculatedColumnIcon = true, showHeaders = true, defaultColumnWidth = DEFAULT_COLUMN_WIDTH, defaultRowHeight = DEFAULT_ROW_HEIGHT, lineHeightMode = "fontMetrics", columnHeaderHeight = COLUMN_HEADER_HEIGHT, rowHeaderWidth = ROW_HEADER_WIDTH, gridLineColor = GRIDLINE_COLOR, cellBackgroundColor = DEFAULT_CELL_BACKGROUND_COLOR, cellColor = DEFAULT_CELL_COLOR, headerBorderColor = DEFAULT_HEADER_BORDER_COLOR, headerBackgroundColor = DEFAULT_HEADER_BG, headerColor = DEFAULT_HEADER_COLOR, headerActiveBackgroundColor = DEFAULT_HEADER_ACTIVE_BG, headerSelectedBackgroundColor = DEFAULT_HEADER_SELECTED_BG, headerSelectedColor = "white", headerTableBackgroundColor = DEFAULT_HEADER_TABLE_BG, headerTableActiveBackgroundColor = DEFAULT_HEADER_ACTIVE_TABLE_BG, headerTableSelectedBackgroundColor = DEFAULT_HEADER_SELECTED_TABLE_BG, frozenShadowColor = headerBorderColor, frozenShadowThickness = 1, selectionBackgroundColor = SELECTION_BG, selectionBorderColor = SELECTION_BORDER, selectionStrokeWidth, showActiveCellBorderInSelection, selectionDragBorderColor = SELECTION_BORDER, chartSelectedColor, chipBackgroundColor = CHIP_COLOR, merges = DEFAULT_ARRAY, borderStyles, protectedRanges, isWorkbookProtected: isWorkbookProtectedProp = false, getSheetProtection, pivotTables, charts, onUpdateChart, onChangeZOrder, embeds, slicers, rowMetadata = DEFAULT_ARRAY, columnMetadata = DEFAULT_ARRAY, scale = 1, zoomSpeed = 1, overscanCount = 3, enableEditOnEnterKey: enableEditOnEnterKeyProp, shouldHandleKeyDown, enableTextOverflow = true, showGridLines: _showGridLines, showFormulas = false, protectFormulas = false, showFrozenSeparator = true, HeaderCell = DefaultHeaderCell, Cell = DefaultCell, SelectionTitleComponent = SelectionTitle, CellEditor = DefaultCellEditor, CellTooltip, ContextMenu = DefaultContextMenu, ContextMenuWrapper = DefaultContextMenuWrapper, FilterBox = DefaultFilterBox, HeaderMoveDragComponent = DefaultHeaderMoveDragComponent, SuggestionsDropdown, stickyEditor = true, scrollSnap = false, scrollThrottleTimeout, preventBrowserDefaultScroll, mouseMoveThrottleTimeout = 60, tooltipIntentInterval = 60, selectionPolicy, users, userId, renderCollaboratorCursor, functionDescriptions, showHeaderMenuButton = true, scrollbarSize = SCROLLBAR_SIZE, theme = defaultSpreadsheetTheme, showNotes = true, showComments = true, locale, formulaLocale: formulaLocaleProp, agentSuggestions, onReviewSuggestion, onShowFormulas, getDataRowCount, getDataRegion, getChartComponent, getEmbedComponent, getSlicerComponent, onChange, onChangeBatch, onExpandCollapse, onPivotDrillDown, onDelete, onChangeEditorValue, onFill, onRequestCalculate, onChangeActiveCell, onChangeActiveSheet, onChangeSelections, getSheetName, getSheetId, getCellData, getNote: getNoteProp, getTextFormatRuns, getDataValidation, getEffectiveFormat, getFormattedValue: getFormattedValueProp, getTooltipContent, errorResolutionComponent, getEffectiveValue: getEffectiveValueProp, getSparklineGroup, getUserEnteredExtendedValue, getEffectiveExtendedValue, getSheetRowCount, getSheetColumnCount, getCellPopoverContent, onScroll, onViewPortChange, windowConditionalFormats = false, engineConditionalFormatResults = false, onResize, onAutoResize, onHideColumn, onHideRow, onShowColumn, onShowRow, onGroupRows, onUngroupRows, onCollapseRowGroup, onExpandRowGroup, onGroupColumns, onUngroupColumns, onCollapseColumnGroup, onExpandColumnGroup, onSetOutlineDepth, onDeleteRow, onDeleteColumn, onInsertRow, onInsertColumn, onChangeAutoExpandTables, onChangeAutoCalculatedColumns, onInsertCellsShiftDown, onInsertCellsShiftRight, onDeleteCellsShiftLeft, onDeleteCellsShiftUp, onClearContents, onMoveColumns, onMoveRows, onSelectNextSheet, onSelectPreviousSheet, onCreateNewSheet, onKeyDown, onChangeFormatting, onRepeatFormatting, onClearFormatting, onRequestEditProtectedRange, onMoveChart, onResizeChart, onDeleteChart, onCutChart, onCopyChart, onMoveEmbed, onResizeEmbed, onDeleteEmbed, onRequestEditEmbed, onMoveSlicer, onResizeSlicer, onDeleteSlicer, onRequestEditSlicer, onFillRange, disableFillRightShortcut, keymap, onCalculateNow, onRequestGoTo, onMoveSelection, onInsertCutCells, onInsertTime, onInsertDate, onInsertDateTime, onInsertAutoSum, onUndo, onRedo, batchHistory, onPaste, onCopy, onCut, onSortColumn, onSortTable, onFilterTable, onFilterPivot, onResizeTable, onUndoTableAutoExpansion, onUndoCalculatedColumn, onOverwriteCalculatedColumn, onRequestEditTable, onRequestEditPivotTable, onRequestDeletePivotTable, onRequestCreatePivotChart, onRemoveTable, onCreateTable, onRequestCreateTable, onInsertTableColumn, onDeleteTableColumn, onInsertTableRow, onDeleteTableRow, onUpdateTable, onRequestResizeTable, onRequestInsertSlicer, onCreateBasicFilter, onRequestDefineNamedRange, onRequestFormatCells, onRequestConditionalFormat, onRequestDataValidation, onRequestInsertComment, onRequestInsertLink, onFreezeColumn, onFreezeRow, onUpdateNote, onProtectRange, onUnProtectRange, onSortRange, onRequestSearch, onRequestReplace, onRequestResize, getRowHeaderText = getDefaultRowHeader, getColumnHeaderText = getDefaultColumnHeader, getAdditionalCellSpacing, tokenizer: defaultTokenizer = defaultFormulaTokenizer, onChangeScale, onRemoveLink, onSelectLink, onSplitTextToColumns, onRemoveDuplicates, onGoalSeek, onSubtotal, onAdvancedFilter, onRequestExpand, cellExpandPredicate, StructuredResult = DefaultStructuredResult, getMentions, getStructuredProperties: getStructuredPropertiesProp, getFunctionParameterSuggestions, shouldFetchFunctionParameters, MentionTagComponent, MentionDropdownItemComponent, showSelectionResizeHandles = true, enableMagicFill, enableQuickEdit = true, MagicFillComponent, MagicFillContent, QuickEdit, PasteMenu, SuggestionAction, HiddenRowMarkers, HiddenColumnMarkers, enableResizerOverflow, className, defaultFontSizePoint = DEFAULT_FONT_SIZE_PT, defaultCellFormat, readonly, isComparing = false, getCellDiff, enableDataBoundaryNavigation, footerHeight, footerComponent, arrowComponents,
133
+ const { licenseKey, sheetId, sheetType, ChartSheetView: ChartSheetViewComponent = ChartSheetView, instanceId, activeCell = DEFAULT_ACTIVE_CELL, selections = DEFAULT_ARRAY, frozenColumnCount = 0, frozenRowCount = 0, rowCount = DEFAULT_ROW_COUNT, columnCount = DEFAULT_COLUMN_COUNT, autoFocus, basicFilter, tables, namedRanges, bandedRanges = DEFAULT_ARRAY, tableBorderColor = "#008000", filterIconColor = FILTER_BUTTON_GLYPH_COLOR, conditionalFormats, showFilterIcon = true, showCalculatedColumnIcon = true, showHeaders = true, defaultColumnWidth = DEFAULT_COLUMN_WIDTH, defaultRowHeight = DEFAULT_ROW_HEIGHT, lineHeightMode = "fontMetrics", columnHeaderHeight = COLUMN_HEADER_HEIGHT, rowHeaderWidth = ROW_HEADER_WIDTH, gridLineColor = GRIDLINE_COLOR, cellBackgroundColor = DEFAULT_CELL_BACKGROUND_COLOR, cellColor = DEFAULT_CELL_COLOR, headerBorderColor = DEFAULT_HEADER_BORDER_COLOR, headerBackgroundColor = DEFAULT_HEADER_BG, headerColor = DEFAULT_HEADER_COLOR, headerActiveBackgroundColor = DEFAULT_HEADER_ACTIVE_BG, headerSelectedBackgroundColor = DEFAULT_HEADER_SELECTED_BG, headerSelectedColor = "white", headerTableBackgroundColor = DEFAULT_HEADER_TABLE_BG, headerTableActiveBackgroundColor = DEFAULT_HEADER_ACTIVE_TABLE_BG, headerTableSelectedBackgroundColor = DEFAULT_HEADER_SELECTED_TABLE_BG, frozenShadowColor = headerBorderColor, frozenShadowThickness = 1, selectionBackgroundColor = SELECTION_BG, selectionBorderColor = SELECTION_BORDER, selectionStrokeWidth, showActiveCellBorderInSelection, selectionDragBorderColor = SELECTION_BORDER, chartSelectedColor, chipBackgroundColor = CHIP_COLOR, merges = DEFAULT_ARRAY, borderStyles, protectedRanges, isWorkbookProtected: isWorkbookProtectedProp = false, getSheetProtection, pivotTables, charts, onUpdateChart, onChangeZOrder, embeds, slicers, rowMetadata = DEFAULT_ARRAY, columnMetadata = DEFAULT_ARRAY, scale = 1, zoomSpeed = 1, overscanCount = 3, enableEditOnEnterKey: enableEditOnEnterKeyProp, shouldHandleKeyDown, enableTextOverflow = true, showGridLines: _showGridLines, showZeros, pageBreaks, showFormulas = false, protectFormulas = false, showFrozenSeparator = true, HeaderCell = DefaultHeaderCell, Cell = DefaultCell, SelectionTitleComponent = SelectionTitle, CellEditor = DefaultCellEditor, CellTooltip, ContextMenu = DefaultContextMenu, ContextMenuWrapper = DefaultContextMenuWrapper, FilterBox = DefaultFilterBox, HeaderMoveDragComponent = DefaultHeaderMoveDragComponent, SuggestionsDropdown, stickyEditor = true, scrollSnap = false, scrollThrottleTimeout, preventBrowserDefaultScroll, mouseMoveThrottleTimeout = 60, tooltipIntentInterval = 60, selectionPolicy, users, userId, renderCollaboratorCursor, functionDescriptions, showHeaderMenuButton = true, scrollbarSize = SCROLLBAR_SIZE, theme = defaultSpreadsheetTheme, showNotes = true, showComments = true, locale, formulaLocale: formulaLocaleProp, agentSuggestions, onReviewSuggestion, onShowFormulas, getDataRowCount, getDataRegion, getChartComponent, getEmbedComponent, getSlicerComponent, onChange, onChangeBatch, onExpandCollapse, onPivotDrillDown, onDelete, onChangeEditorValue, onFill, onRequestCalculate, onChangeActiveCell, onChangeActiveSheet, onChangeSelections, getSheetName, getSheetId, getCellData, getNote: getNoteProp, getTextFormatRuns, getDataValidation, getEffectiveFormat, getFormattedValue: getFormattedValueProp, getTooltipContent, errorResolutionComponent, getEffectiveValue: getEffectiveValueProp, getSparklineGroup, getUserEnteredExtendedValue, getEffectiveExtendedValue, getSheetRowCount, getSheetColumnCount, getCellPopoverContent, onScroll, onViewPortChange, windowConditionalFormats = false, engineConditionalFormatResults = false, getConditionalFormatRuleStats, onResize, onAutoResize, onHideColumn, onHideRow, onShowColumn, onShowRow, onGroupRows, onUngroupRows, onCollapseRowGroup, onExpandRowGroup, onGroupColumns, onUngroupColumns, onCollapseColumnGroup, onExpandColumnGroup, onSetOutlineDepth, onDeleteRow, onDeleteColumn, onInsertRow, onInsertColumn, onChangeAutoExpandTables, onChangeAutoCalculatedColumns, onInsertCellsShiftDown, onInsertCellsShiftRight, onDeleteCellsShiftLeft, onDeleteCellsShiftUp, onClearContents, onMoveColumns, onMoveRows, onSelectNextSheet, onSelectPreviousSheet, onCreateNewSheet, onKeyDown, onChangeFormatting, onRepeatFormatting, onClearFormatting, onRequestEditProtectedRange, onMoveChart, onResizeChart, onDeleteChart, onCutChart, onCopyChart, onMoveEmbed, onResizeEmbed, onDeleteEmbed, onRequestEditEmbed, onMoveSlicer, onResizeSlicer, onDeleteSlicer, onRequestEditSlicer, onFillRange, disableFillRightShortcut, keymap, onCalculateNow, onRequestGoTo, onMoveSelection, onInsertCutCells, onInsertTime, onInsertDate, onInsertDateTime, onInsertAutoSum, onUndo, onRedo, batchHistory, onPaste, onCopy, onCut, onSortColumn, onSortTable, onFilterTable, onFilterPivot, onResizeTable, onUndoTableAutoExpansion, onUndoCalculatedColumn, onOverwriteCalculatedColumn, onRequestEditTable, onRequestEditPivotTable, onRequestDeletePivotTable, onRequestCreatePivotChart, onRemoveTable, onCreateTable, onRequestCreateTable, onInsertTableColumn, onDeleteTableColumn, onInsertTableRow, onDeleteTableRow, onUpdateTable, onRequestResizeTable, onRequestInsertSlicer, onCreateBasicFilter, onRequestDefineNamedRange, onRequestFormatCells, onRequestConditionalFormat, onRequestDataValidation, onRequestInsertComment, onRequestInsertLink, onFreezeColumn, onFreezeRow, onUpdateNote, onProtectRange, onUnProtectRange, onSortRange, onRequestSearch, onRequestReplace, onRequestResize, getRowHeaderText = getDefaultRowHeader, getColumnHeaderText = getDefaultColumnHeader, getAdditionalCellSpacing, tokenizer: defaultTokenizer = defaultFormulaTokenizer, onChangeScale, onRemoveLink, onSelectLink, onSplitTextToColumns, onRemoveDuplicates, onGoalSeek, onSubtotal, onAdvancedFilter, onRequestExpand, cellExpandPredicate, StructuredResult = DefaultStructuredResult, getMentions, getStructuredProperties: getStructuredPropertiesProp, getFunctionParameterSuggestions, shouldFetchFunctionParameters, MentionTagComponent, MentionDropdownItemComponent, showSelectionResizeHandles = true, enableMagicFill, enableQuickEdit = true, MagicFillComponent, MagicFillContent, QuickEdit, PasteMenu, SuggestionAction, HiddenRowMarkers, HiddenColumnMarkers, enableResizerOverflow, className, defaultFontSizePoint = DEFAULT_FONT_SIZE_PT, defaultCellFormat, readonly, isComparing = false, getCellDiff, enableDataBoundaryNavigation, footerHeight, footerComponent, arrowComponents,
131
134
  // Host-driven filter props. `hostHiddenRowRanges`
132
135
  // supplies compact [start, end] hidden-row tuples; `getFilterValues` supplies a
133
136
  // column's distinct values. Both let a million-row filter render without scanning
@@ -978,10 +981,7 @@ function CanvasGridComponent(props, forwardedRef) {
978
981
  /**
979
982
  * Check if a cell data is a number
980
983
  */
981
- const isNumberValue = useCallback((sheetId, rowIndex, columnIndex) => {
982
- const cellFormat = getCellFormat?.(sheetId, rowIndex, columnIndex);
983
- return !!cellFormat?.numberFormat?.type;
984
- }, [getCellFormat]);
984
+ const isNumberValue = useCallback((sheetId, rowIndex, columnIndex) => isConditionalFormatNumberCell(getEffectiveValue(sheetId, rowIndex, columnIndex), getCellFormat?.(sheetId, rowIndex, columnIndex)), [getCellFormat, getEffectiveValue]);
985
985
  /**
986
986
  * Get value entered by the user in a cell
987
987
  * If its a formula cell, formulaValue is used
@@ -1098,6 +1098,7 @@ function CanvasGridComponent(props, forwardedRef) {
1098
1098
  getConditionalFormatResult: engineConditionalFormatResults
1099
1099
  ? getFormulaValidationValue
1100
1100
  : undefined,
1101
+ getConditionalFormatRuleStats,
1101
1102
  });
1102
1103
  /**
1103
1104
  * Get conditional format of a cell
@@ -1105,6 +1106,28 @@ function CanvasGridComponent(props, forwardedRef) {
1105
1106
  const getConditionalCellFormat = useCallback((sheetId, rowIndex, columnIndex) => {
1106
1107
  return conditionalFormatByCell.get(cellIdentifier(rowIndex, columnIndex));
1107
1108
  }, [conditionalFormatByCell]);
1109
+ /**
1110
+ * The text a cell paints: a true conditional format's number format
1111
+ * (Format Cells ▸ Number in the rule) re-formats a numeric value, as in
1112
+ * Excel; otherwise the cell's own formatted value.
1113
+ */
1114
+ const getDisplayFormattedValue = useCallback((sheetId, rowIndex, columnIndex) => {
1115
+ const pattern = conditionalFormatByCell.get(cellIdentifier(rowIndex, columnIndex))?.numberFormat?.pattern;
1116
+ if (pattern && !(showFormulas && !protectFormulas)) {
1117
+ const numberValue = getExtendedValueNumber(getEffectiveValue(sheetId, rowIndex, columnIndex));
1118
+ if (typeof numberValue === "number") {
1119
+ return ssfFormat(pattern, numberValue, locale);
1120
+ }
1121
+ }
1122
+ return getFormattedValue(sheetId, rowIndex, columnIndex);
1123
+ }, [
1124
+ conditionalFormatByCell,
1125
+ getEffectiveValue,
1126
+ getFormattedValue,
1127
+ locale,
1128
+ protectFormulas,
1129
+ showFormulas,
1130
+ ]);
1108
1131
  /**
1109
1132
  * Get conditional format of a cell
1110
1133
  */
@@ -1163,14 +1186,17 @@ function CanvasGridComponent(props, forwardedRef) {
1163
1186
  const { textFormat: _textFormat, ...rest } = defaultCellFormat;
1164
1187
  return Object.keys(rest).length ? rest : undefined;
1165
1188
  }, [defaultCellFormat]);
1189
+ const isDarkGrid = useMemo(() => isDarkCssColor(getStringifiedColor(cellBackgroundColor, theme)), [cellBackgroundColor, theme]);
1166
1190
  const getEffectiveCellFormat = useCallback((sheetId, rowIndex, columnIndex) => {
1167
1191
  const cellFormat = getCellFormat(sheetId, rowIndex, columnIndex);
1168
1192
  const isHyperlink = Boolean(getHyperlink(sheetId, rowIndex, columnIndex));
1169
1193
  const conditionalCellFormat = getConditionalCellFormat(sheetId, rowIndex, columnIndex);
1170
1194
  const bandedCellFormat = getBandedCellFormat(sheetId, rowIndex, columnIndex);
1171
- // Conditional format cell color for
1172
- // light and dark themes
1173
- const conditionalFormatColor = conditionalCellFormat?.backgroundColor &&
1195
+ // A fill-only rule keeps the cell's font colour (Excel). Only a dark
1196
+ // grid swaps to a contrasting text colour, so the default light text
1197
+ // stays readable on the rule's (usually light) fill.
1198
+ const conditionalFormatColor = isDarkGrid &&
1199
+ conditionalCellFormat?.backgroundColor &&
1174
1200
  !conditionalCellFormat?.textFormat?.color
1175
1201
  ? getContrastColor(getStringifiedColor(conditionalCellFormat.backgroundColor, theme), getStringifiedColor({ theme: 1 }, theme), getStringifiedColor({ theme: 1, tint: 1 }, theme))
1176
1202
  : undefined;
@@ -1253,6 +1279,7 @@ function CanvasGridComponent(props, forwardedRef) {
1253
1279
  cellColor,
1254
1280
  defaultCellTextFormat,
1255
1281
  defaultCellFormatRest,
1282
+ isDarkGrid,
1256
1283
  ]);
1257
1284
  /**
1258
1285
  * Get horizontal alignment of editor
@@ -1614,37 +1641,24 @@ function CanvasGridComponent(props, forwardedRef) {
1614
1641
  * Can a cell overflow to adjoining cell
1615
1642
  */
1616
1643
  const canOverflowToNextCell = useCallback(({ rowIndex, columnIndex }) => {
1617
- if (isRowHeader(columnIndex) || isColumnHeader(rowIndex)) {
1618
- return false;
1619
- }
1620
- if (isTableHeader(rowIndex, columnIndex)) {
1621
- return false;
1622
- }
1623
- if (isBandedCell(rowIndex, columnIndex)) {
1624
- return false;
1625
- }
1626
- if (getDataValidationRule(sheetId, rowIndex, columnIndex)) {
1627
- return false;
1628
- }
1629
- const [expandable] = getCellGroupingInfo(sheetId, rowIndex, columnIndex);
1630
- if (expandable) {
1631
- return false;
1632
- }
1633
- const formattedValue = getFormattedValue?.(sheetId, rowIndex, columnIndex);
1634
- return (getNote(sheetId, rowIndex, columnIndex) === undefined &&
1635
- isNilOrBlank(formattedValue) &&
1636
- getCellImageUrl(sheetId, rowIndex, columnIndex) === undefined);
1644
+ // Only content stops the spill (Excel): a value, a formula result
1645
+ // (`=""` included), an image. Data validation, notes, tables and
1646
+ // banding are not content.
1647
+ return !blocksOverflow({
1648
+ isHeader: isRowHeader(columnIndex) || isColumnHeader(rowIndex),
1649
+ isExpandable: getCellGroupingInfo(sheetId, rowIndex, columnIndex)[0],
1650
+ formattedValue: getFormattedValue?.(sheetId, rowIndex, columnIndex),
1651
+ effectiveValue: getEffectiveValue(sheetId, rowIndex, columnIndex),
1652
+ hasImage: getCellImageUrl(sheetId, rowIndex, columnIndex) !== undefined,
1653
+ });
1637
1654
  }, [
1638
1655
  sheetId,
1639
1656
  getFormattedValue,
1657
+ getEffectiveValue,
1640
1658
  getCellGroupingInfo,
1641
1659
  getCellImageUrl,
1642
- getNote,
1643
- getDataValidationRule,
1644
1660
  isRowHeader,
1645
1661
  isColumnHeader,
1646
- isTableHeader,
1647
- isBandedCell,
1648
1662
  ]);
1649
1663
  /**
1650
1664
  * If a cell is hidden,
@@ -1863,18 +1877,19 @@ function CanvasGridComponent(props, forwardedRef) {
1863
1877
  if (axis === "x") {
1864
1878
  return 0;
1865
1879
  }
1866
- /* Data validation arrow */
1867
- const dataValidation = getDataValidationRule(sheetId, rowIndex, columnIndex);
1868
1880
  const additionalCellSpacing = getAdditionalCellSpacing?.(sheetId, rowIndex, columnIndex) ?? 0;
1869
- const showArrow = showValidationDropdownArrow(dataValidation) ||
1870
- isTableTotalsCell(rowIndex, columnIndex);
1881
+ // A data-validation list's dropdown paints beside the active cell, so
1882
+ // only the table totals arrow takes room inside the cell.
1883
+ const showArrow = isTableTotalsCell(rowIndex, columnIndex);
1871
1884
  const showChip = getCellMetaType(sheetId, rowIndex, columnIndex) === "people";
1872
1885
  const [expandable] = getCellGroupingInfo(sheetId, rowIndex, columnIndex);
1873
1886
  const iconSpacing = DEFAULT_CELL_SPACING;
1874
1887
  const expandableSpacing = expandable
1875
1888
  ? (EXPAND_COLLAPSE_ICON_WIDTH + iconSpacing) * scale
1876
1889
  : 0;
1877
- const indentSpacing = (getCellIndent(sheetId, rowIndex, columnIndex) ?? 0) * INDENT_SPACING;
1890
+ const indentSpacing = (getCellIndent(sheetId, rowIndex, columnIndex) ?? 0) *
1891
+ INDENT_SPACING *
1892
+ scale;
1878
1893
  // Cell has dropdown icon
1879
1894
  const arrowSpacing = showArrow
1880
1895
  ? (ARROW_DOWN_WIDTH + iconSpacing) * scale
@@ -1907,7 +1922,6 @@ function CanvasGridComponent(props, forwardedRef) {
1907
1922
  additionalCellSpacing);
1908
1923
  }, [
1909
1924
  isTableFilterVisible,
1910
- getDataValidationRule,
1911
1925
  getCellMetaType,
1912
1926
  getCellIndent,
1913
1927
  showCalculatedColumnIcon,
@@ -1937,7 +1951,7 @@ function CanvasGridComponent(props, forwardedRef) {
1937
1951
  isHiddenColumn,
1938
1952
  getTextFormat,
1939
1953
  getTextFormatRuns,
1940
- getTextValue: getFormattedValue,
1954
+ getTextValue: getDisplayFormattedValue,
1941
1955
  getSpacing: getCellSpacing,
1942
1956
  getActualCellWidth,
1943
1957
  shouldWrapCell,
@@ -3615,11 +3629,58 @@ function CanvasGridComponent(props, forwardedRef) {
3615
3629
  }
3616
3630
  onKeyDownEditable(e);
3617
3631
  }, [onKeyDownEditable]);
3632
+ /**
3633
+ * Center Across Selection: a `centerContinuous` cell centres its text over
3634
+ * the empty neighbours on either side that carry the same alignment
3635
+ * (Format Cells ▸ Alignment ▸ Horizontal).
3636
+ */
3637
+ const getCenterAcrossSelectionSpan = useCallback((sheetId, rowIndex, columnIndex) => {
3638
+ const canSpan = (index) => getEffectiveCellFormat(sheetId, rowIndex, index)
3639
+ ?.horizontalAlignment === "centerContinuous" &&
3640
+ canOverflowToNextCell({ rowIndex, columnIndex: index });
3641
+ const scaledWidth = (index) => columnWidth(index) * scale;
3642
+ const left = walkOverflowColumns({
3643
+ start: columnIndex,
3644
+ step: -1,
3645
+ need: Infinity,
3646
+ canOverflow: canSpan,
3647
+ columnWidth: scaledWidth,
3648
+ });
3649
+ const right = walkOverflowColumns({
3650
+ start: columnIndex,
3651
+ step: 1,
3652
+ need: Infinity,
3653
+ canOverflow: canSpan,
3654
+ columnWidth: scaledWidth,
3655
+ });
3656
+ if (!left.columns.length && !right.columns.length)
3657
+ return undefined;
3658
+ const spans = [];
3659
+ for (const index of [...left.columns, ...right.columns]) {
3660
+ spans.push([
3661
+ index,
3662
+ getColumnOffset(index),
3663
+ scaledWidth(index),
3664
+ getEffectiveCellFormat(sheetId, rowIndex, index)?.backgroundColor,
3665
+ ]);
3666
+ }
3667
+ return [
3668
+ scaledWidth(columnIndex) + left.width + right.width,
3669
+ spans,
3670
+ left.width,
3671
+ ];
3672
+ }, [
3673
+ canOverflowToNextCell,
3674
+ columnWidth,
3675
+ getColumnOffset,
3676
+ getEffectiveCellFormat,
3677
+ scale,
3678
+ ]);
3618
3679
  /**
3619
3680
  * Get maximum text width
3620
3681
  * before it overflows into next cell
3621
3682
  */
3622
- const getMaximumOverflowTextWidth = useCallback((formattedValue, sheetId, rowIndex, columnIndex, canOverflowToNextCell, textFormat, shouldWrapOverride, direction = Direction.Right) => {
3683
+ const getMaximumOverflowTextWidth = useCallback((formattedValue, sheetId, rowIndex, columnIndex, canOverflowToNextCell, textFormat, shouldWrapOverride, direction = Direction.Right, centered = false) => {
3623
3684
  // A format override makes the sizer measure the whole text
3624
3685
  // uniformly, ignoring per-segment rich-text runs. For cells that
3625
3686
  // carry runs (e.g. imported xlsx titles with mixed font sizes),
@@ -3634,6 +3695,41 @@ function CanvasGridComponent(props, forwardedRef) {
3634
3695
  if (textWidth < colWidth) {
3635
3696
  return [textWidth, DEFAULT_ARRAY];
3636
3697
  }
3698
+ if (centered) {
3699
+ // Centred text spills half its excess each way (Excel); a blocked
3700
+ // side clips while the text stays centred on its own cell.
3701
+ const need = (textWidth - colWidth) / 2;
3702
+ const scaledWidth = (index) => columnWidth(index) * scale;
3703
+ const canOverflow = (index) => canOverflowToNextCell({ rowIndex, columnIndex: index });
3704
+ const left = walkOverflowColumns({
3705
+ start: columnIndex,
3706
+ step: -1,
3707
+ need,
3708
+ canOverflow,
3709
+ columnWidth: scaledWidth,
3710
+ });
3711
+ const right = walkOverflowColumns({
3712
+ start: columnIndex,
3713
+ step: 1,
3714
+ need,
3715
+ canOverflow,
3716
+ columnWidth: scaledWidth,
3717
+ });
3718
+ const spans = [];
3719
+ for (const index of [...left.columns, ...right.columns]) {
3720
+ spans.push([
3721
+ index,
3722
+ getColumnOffset(index),
3723
+ scaledWidth(index),
3724
+ getEffectiveCellFormat(sheetId, rowIndex, index)?.backgroundColor,
3725
+ ]);
3726
+ }
3727
+ return [
3728
+ colWidth + Math.min(left.width, need) + Math.min(right.width, need),
3729
+ spans,
3730
+ Math.min(left.width, need),
3731
+ ];
3732
+ }
3637
3733
  let start = columnIndex;
3638
3734
  const columnSpans = [];
3639
3735
  const isMovingRight = direction === Direction.Right;
@@ -3672,7 +3768,9 @@ function CanvasGridComponent(props, forwardedRef) {
3672
3768
  isTableTotalsCell,
3673
3769
  onTotalsArrowClick: handleTotalsArrowClick,
3674
3770
  formulaLocale,
3771
+ locale,
3675
3772
  showGridLines,
3773
+ showZeros,
3676
3774
  scale,
3677
3775
  enableTextOverflow,
3678
3776
  isRowHeader,
@@ -3710,7 +3808,7 @@ function CanvasGridComponent(props, forwardedRef) {
3710
3808
  getComment,
3711
3809
  getEffectiveValue,
3712
3810
  getSparklineGroup,
3713
- getFormattedValue,
3811
+ getFormattedValue: getDisplayFormattedValue,
3714
3812
  getCellImageUrl,
3715
3813
  getEffectiveCellFormat,
3716
3814
  getCellBounds,
@@ -3718,6 +3816,8 @@ function CanvasGridComponent(props, forwardedRef) {
3718
3816
  getRowHeaderText,
3719
3817
  getColumnHeaderText,
3720
3818
  getMaximumOverflowTextWidth,
3819
+ getCenterAcrossSelectionSpan,
3820
+ activeCell,
3721
3821
  getTextDimension,
3722
3822
  getCellGroupingInfo,
3723
3823
  getTextFormatRuns,
@@ -3906,9 +4006,16 @@ function CanvasGridComponent(props, forwardedRef) {
3906
4006
  quickEditValues,
3907
4007
  });
3908
4008
  // A selected chart's source outlines draw on top of the other range borders.
3909
- const gridBorderStyles = useMemo(() => chartSourceBorderStyles.length
3910
- ? [...finalBorderStyles, ...chartSourceBorderStyles]
3911
- : finalBorderStyles, [finalBorderStyles, chartSourceBorderStyles]);
4009
+ // Page breaks (when the host shows them) dash across the sheet, Excel's
4010
+ // Normal-view page-break lines.
4011
+ const pageBreakBorderStyles = useMemo(() => getPageBreakBorderStyles(pageBreaks, rowCount, columnCount), [pageBreaks, rowCount, columnCount]);
4012
+ const gridBorderStyles = useMemo(() => chartSourceBorderStyles.length || pageBreakBorderStyles.length
4013
+ ? [
4014
+ ...pageBreakBorderStyles,
4015
+ ...finalBorderStyles,
4016
+ ...chartSourceBorderStyles,
4017
+ ]
4018
+ : finalBorderStyles, [finalBorderStyles, chartSourceBorderStyles, pageBreakBorderStyles]);
3912
4019
  // Hidden column markers
3913
4020
  const [hiddenColumnMarkers, frozenHiddenColumnMarkers, hiddenRowMarkers, frozenHiddenRowMarkers,] = useHiddenDimensionMarkers({
3914
4021
  sheetId,
@@ -4217,6 +4324,13 @@ function CanvasGridComponent(props, forwardedRef) {
4217
4324
  return;
4218
4325
  }
4219
4326
  const { rowIndex, columnIndex } = activeCell;
4327
+ // Excel's Format Cells ▸ Protection ▸ Hidden: while the sheet is protected, a hidden
4328
+ // cell's contents never show in the formula bar ("Protect a worksheet").
4329
+ if (isCellFormulaHiddenUnderProtection(getSheetProtection?.(sheetId), getCellData?.(sheetId, rowIndex, columnIndex)?.protection)) {
4330
+ setFormulabarEditorValue("");
4331
+ setFormulaBarTextFormatRuns(undefined);
4332
+ return;
4333
+ }
4220
4334
  const value = getUserEnteredStringValue(sheetId, rowIndex, columnIndex);
4221
4335
  const textFormatRuns = getTextFormatRuns?.(sheetId, rowIndex, columnIndex);
4222
4336
  // Update formula bar input (in the grid's formula locale, like the cell editor)
@@ -4227,6 +4341,8 @@ function CanvasGridComponent(props, forwardedRef) {
4227
4341
  formulaMode,
4228
4342
  sheetId,
4229
4343
  editingCellCoordinate,
4344
+ getSheetProtection,
4345
+ getCellData,
4230
4346
  getUserEnteredStringValue,
4231
4347
  formulaLocale,
4232
4348
  setFormulabarEditorValue,
@@ -0,0 +1,37 @@
1
+ import type { ExtendedValue } from "@rowsncolumns/common-types";
2
+ /** What the grid knows about the cell text wants to spill into. */
3
+ export type OverflowNeighbour = {
4
+ formattedValue?: string | null;
5
+ effectiveValue?: ExtendedValue | null;
6
+ hasImage?: boolean;
7
+ /** An outline expand / collapse button paints in the cell. */
8
+ isExpandable?: boolean;
9
+ /** Row / column header cells. */
10
+ isHeader?: boolean;
11
+ /**
12
+ * Present for the matrix test's sake: none of these block overflow in
13
+ * Excel, so the decision below never reads them.
14
+ */
15
+ hasDataValidation?: boolean;
16
+ hasNote?: boolean;
17
+ isTableCell?: boolean;
18
+ isBanded?: boolean;
19
+ };
20
+ /** Does this cell stop text spilling from its neighbour? */
21
+ export declare const blocksOverflow: (cell: OverflowNeighbour) => boolean;
22
+ /**
23
+ * Columns text claims walking from `start` by `step` (±1) until `need`
24
+ * pixels are covered or a blocking cell stops it.
25
+ */
26
+ export declare const walkOverflowColumns: ({ start, step, need, canOverflow, columnWidth, maxSteps, }: {
27
+ start: number;
28
+ step: 1 | -1;
29
+ need: number;
30
+ canOverflow: (columnIndex: number) => boolean;
31
+ columnWidth: (columnIndex: number) => number;
32
+ maxSteps?: number;
33
+ }) => {
34
+ columns: number[];
35
+ width: number;
36
+ };
37
+ //# sourceMappingURL=overflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overflow.d.ts","sourceRoot":"","sources":["../../../../components/canvas-grid/overflow.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGhE,mEAAmE;AACnE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,cAAc,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAaF,4DAA4D;AAC5D,eAAO,MAAM,cAAc,GAAI,MAAM,iBAAiB,KAAG,OAK1B,CAAC;AAEhC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,4DAOjC;IACD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;IAC9C,WAAW,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,KAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAWrC,CAAC"}
@@ -0,0 +1,39 @@
1
+ // Text overflow into neighbouring cells, the way Excel decides it.
2
+ //
3
+ // Excel lets text spill over a neighbour only while that neighbour is empty:
4
+ // a cell holding anything — a formula returning "" included — stops it.
5
+ // Formatting, data validation, notes, table membership and banding never
6
+ // do; they are not content.
7
+ import { isNilOrBlank } from "@rowsncolumns/utils";
8
+ const hasValue = (value) => !!value &&
9
+ (value.nv != null ||
10
+ value.numberValue != null ||
11
+ value.sv != null ||
12
+ value.stringValue != null ||
13
+ value.bv != null ||
14
+ value.boolValue != null ||
15
+ value.ev != null ||
16
+ value.errorValue != null);
17
+ /** Does this cell stop text spilling from its neighbour? */
18
+ export const blocksOverflow = (cell) => !!cell.isHeader ||
19
+ !!cell.isExpandable ||
20
+ !!cell.hasImage ||
21
+ !isNilOrBlank(cell.formattedValue) ||
22
+ hasValue(cell.effectiveValue);
23
+ /**
24
+ * Columns text claims walking from `start` by `step` (±1) until `need`
25
+ * pixels are covered or a blocking cell stops it.
26
+ */
27
+ export const walkOverflowColumns = ({ start, step, need, canOverflow, columnWidth, maxSteps = 512, }) => {
28
+ const columns = [];
29
+ let width = 0;
30
+ let column = start;
31
+ for (let i = 0; i < maxSteps && width < need; i++) {
32
+ column += step;
33
+ if (column < 0 || !canOverflow(column))
34
+ break;
35
+ columns.push(column);
36
+ width += columnWidth(column);
37
+ }
38
+ return { columns, width };
39
+ };
@@ -0,0 +1,15 @@
1
+ import type { AreaStyle } from "@rowsncolumns/grid";
2
+ export type SheetPageBreaks = {
3
+ /** 1-based rows AFTER which a page break falls (`<rowBreaks><brk id>`). */
4
+ rowBreaks?: number[] | null;
5
+ /** 1-based columns after which a page break falls. */
6
+ columnBreaks?: number[] | null;
7
+ };
8
+ export declare const PAGE_BREAK_COLOR = "#7F7F7F";
9
+ /**
10
+ * Range styles that paint the page-break dashes. Grid rows and columns are
11
+ * 1-based like the break ids, so a break after row N is the bottom edge of
12
+ * grid row N.
13
+ */
14
+ export declare const getPageBreakBorderStyles: (pageBreaks: SheetPageBreaks | null | undefined, rowCount: number, columnCount: number) => AreaStyle[];
15
+ //# sourceMappingURL=page-breaks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-breaks.d.ts","sourceRoot":"","sources":["../../../../components/canvas-grid/page-breaks.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,MAAM,eAAe,GAAG;IAC5B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC5B,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAE1C;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GACnC,YAAY,eAAe,GAAG,IAAI,GAAG,SAAS,EAC9C,UAAU,MAAM,EAChB,aAAa,MAAM,KAClB,SAAS,EAyCX,CAAC"}
@@ -0,0 +1,50 @@
1
+ export const PAGE_BREAK_COLOR = "#7F7F7F";
2
+ /**
3
+ * Range styles that paint the page-break dashes. Grid rows and columns are
4
+ * 1-based like the break ids, so a break after row N is the bottom edge of
5
+ * grid row N.
6
+ */
7
+ export const getPageBreakBorderStyles = (pageBreaks, rowCount, columnCount) => {
8
+ const styles = [];
9
+ for (const row of pageBreaks?.rowBreaks ?? []) {
10
+ if (row < 1 || row >= rowCount)
11
+ continue;
12
+ styles.push({
13
+ index: `page-break-row-${row}`,
14
+ type: "border",
15
+ range: {
16
+ startRowIndex: row,
17
+ endRowIndex: row,
18
+ startColumnIndex: 1,
19
+ endColumnIndex: columnCount - 1,
20
+ },
21
+ style: {
22
+ strokeWidth: 0,
23
+ strokeBottomWidth: 1,
24
+ strokeBottomColor: PAGE_BREAK_COLOR,
25
+ strokeStyle: "dashed",
26
+ },
27
+ });
28
+ }
29
+ for (const column of pageBreaks?.columnBreaks ?? []) {
30
+ if (column < 1 || column >= columnCount)
31
+ continue;
32
+ styles.push({
33
+ index: `page-break-column-${column}`,
34
+ type: "border",
35
+ range: {
36
+ startRowIndex: 1,
37
+ endRowIndex: rowCount - 1,
38
+ startColumnIndex: column,
39
+ endColumnIndex: column,
40
+ },
41
+ style: {
42
+ strokeWidth: 0,
43
+ strokeRightWidth: 1,
44
+ strokeRightColor: PAGE_BREAK_COLOR,
45
+ strokeStyle: "dashed",
46
+ },
47
+ });
48
+ }
49
+ return styles;
50
+ };