@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
@@ -6,6 +6,8 @@ var grid_1 = require("@rowsncolumns/grid");
6
6
  var utils_1 = require("@rowsncolumns/utils");
7
7
  var react_1 = tslib_1.__importStar(require("react"));
8
8
  var react_konva_1 = require("react-konva");
9
+ var cf_data_bar_1 = require("../../api/cf-data-bar");
10
+ var cf_icons_1 = require("../../api/cf-icons");
9
11
  var config_1 = require("../../config");
10
12
  var helpers_1 = require("../../helpers");
11
13
  var themes_1 = require("../../themes");
@@ -16,19 +18,18 @@ var cell_error_1 = require("../cell-error");
16
18
  var cell_expand_1 = require("../cell-expand");
17
19
  var cell_filter_1 = require("../cell-filter");
18
20
  var cell_group_1 = require("../cell-group");
21
+ var alignment_1 = require("./alignment");
19
22
  var cell_text_runs_1 = require("./cell-text-runs");
23
+ var helpers_2 = require("./helpers");
20
24
  var line_height_1 = require("./line-height");
25
+ var number_format_layout_1 = require("./number-format-layout");
21
26
  var rich_text_1 = require("./rich-text");
22
- var alignment_1 = require("./alignment");
23
- var helpers_2 = require("./helpers");
24
27
  var LOADING_VALUE = "Loading...";
25
28
  // CSS-equivalent scale for sup/sub baseline offset (matches browser default).
26
29
  var BASELINE_OFFSET_FONT_SCALE = 0.58;
27
- // Vertical inset of data-bar rect from cell edges (top/bottom).
28
- var CF_DATABAR_INSET_Y = 2;
29
30
  exports.Cell = (0, react_1.memo)(function (props) {
30
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
31
- var x = props.x, y = props.y, width = props.width, height = props.height, value = props.value, _p = props.padding, padding = _p === void 0 ? grid_1.CELL_TEXT_PADDING : _p, _q = props.scale, scale = _q === void 0 ? 1 : _q, _r = props.lineHeight, lineHeight = _r === void 0 ? 1.2 : _r, _s = props.lineHeightMode, lineHeightMode = _s === void 0 ? "fontMetrics" : _s, imageUrl = props.imageUrl, cellFormat = props.cellFormat, chipBackgroundColor = props.chipBackgroundColor, defaultColor = props.defaultColor, defaultBackgroundColor = props.defaultBackgroundColor, sheetId = props.sheetId, rowIndex = props.rowIndex, columnIndex = props.columnIndex, onRequestEdit = props.onRequestEdit, onArrowClick = props.onArrowClick, isChecked = props.isChecked, isInvalid = props.isInvalid, isError = props.isError, showCheckbox = props.showCheckbox, showArrow = props.showArrow, showFilter = props.showFilter, showChip = props.showChip, showNote = props.showNote, showComment = props.showComment, isFilterActive = props.isFilterActive, filterIconColor = props.filterIconColor, onFilterClick = props.onFilterClick, onCheckboxClick = props.onCheckboxClick, enableOverflow = props.enableOverflow, cellWidth = props.cellWidth, _textWidth = props.textWidth, theme = props.theme, showCalculatedColumnIcon = props.showCalculatedColumnIcon, isCalculatedColumn = props.isCalculatedColumn, expandable = props.expandable, expanded = props.expanded, columnSpans = props.columnSpans, overflowRight = props.overflowRight, showGridLines = props.showGridLines, structuredValue = props.structuredValue, sparklineGroupAxis = props.sparklineGroupAxis, defaultFontSizePoint = props.defaultFontSizePoint, sortOrder = props.sortOrder, textFormatRuns = props.textFormatRuns, StructuredResult = props.StructuredResult, _t = props.readonly, readonly = _t === void 0 ? false : _t, onExpandCollapse = props.onExpandCollapse, getDefaultHorizontalAlignment = props.getDefaultHorizontalAlignment;
31
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
32
+ var x = props.x, y = props.y, width = props.width, height = props.height, value = props.value, _m = props.padding, padding = _m === void 0 ? grid_1.CELL_TEXT_PADDING : _m, _o = props.scale, scale = _o === void 0 ? 1 : _o, _p = props.lineHeight, lineHeight = _p === void 0 ? 1.2 : _p, _q = props.lineHeightMode, lineHeightMode = _q === void 0 ? "fontMetrics" : _q, imageUrl = props.imageUrl, cellFormat = props.cellFormat, chipBackgroundColor = props.chipBackgroundColor, defaultColor = props.defaultColor, defaultBackgroundColor = props.defaultBackgroundColor, sheetId = props.sheetId, rowIndex = props.rowIndex, columnIndex = props.columnIndex, onRequestEdit = props.onRequestEdit, onArrowClick = props.onArrowClick, isChecked = props.isChecked, isInvalid = props.isInvalid, isError = props.isError, showCheckbox = props.showCheckbox, showArrow = props.showArrow, showFilter = props.showFilter, showChip = props.showChip, showNote = props.showNote, showComment = props.showComment, isFilterActive = props.isFilterActive, filterIconColor = props.filterIconColor, onFilterClick = props.onFilterClick, onCheckboxClick = props.onCheckboxClick, enableOverflow = props.enableOverflow, cellWidth = props.cellWidth, _textWidth = props.textWidth, theme = props.theme, showCalculatedColumnIcon = props.showCalculatedColumnIcon, isCalculatedColumn = props.isCalculatedColumn, expandable = props.expandable, expanded = props.expanded, columnSpans = props.columnSpans, overflowRight = props.overflowRight, overflowLeft = props.overflowLeft, _r = props.centerOnSpan, centerOnSpan = _r === void 0 ? false : _r, _s = props.arrowOutside, arrowOutside = _s === void 0 ? false : _s, showGridLines = props.showGridLines, structuredValue = props.structuredValue, sparklineGroupAxis = props.sparklineGroupAxis, defaultFontSizePoint = props.defaultFontSizePoint, sortOrder = props.sortOrder, textFormatRuns = props.textFormatRuns, numberFormatLayout = props.numberFormatLayout, StructuredResult = props.StructuredResult, _t = props.readonly, readonly = _t === void 0 ? false : _t, onExpandCollapse = props.onExpandCollapse, getDefaultHorizontalAlignment = props.getDefaultHorizontalAlignment;
32
33
  var _u = cellFormat !== null && cellFormat !== void 0 ? cellFormat : {}, textFormat = _u.textFormat, wrapStrategy = _u.wrapStrategy;
33
34
  // openpyxl's `relativeIndent` is an additive delta on top of `indent`.
34
35
  var indent = ((_a = cellFormat === null || cellFormat === void 0 ? void 0 : cellFormat.indent) !== null && _a !== void 0 ? _a : 0) + ((_b = cellFormat === null || cellFormat === void 0 ? void 0 : cellFormat.relativeIndent) !== null && _b !== void 0 ? _b : 0);
@@ -38,24 +39,37 @@ exports.Cell = (0, react_1.memo)(function (props) {
38
39
  // we cross-package-duplicate the sentinel so apps/spreadsheet doesn't
39
40
  // depend on spreadsheet-state.
40
41
  var isLoading = value === LOADING_VALUE;
42
+ // Format Cells → Alignment → Text direction: a right-to-left reading
43
+ // order starts General-aligned text at the right edge.
44
+ var readingOrder = cellFormat === null || cellFormat === void 0 ? void 0 : cellFormat.readingOrder;
41
45
  var horizontalAlignment = isLoading
42
46
  ? "center"
43
- : (_e = cellFormat === null || cellFormat === void 0 ? void 0 : cellFormat.horizontalAlignment) !== null && _e !== void 0 ? _e : (getDefaultHorizontalAlignment(sheetId, rowIndex, columnIndex) ||
47
+ : (_e = cellFormat === null || cellFormat === void 0 ? void 0 : cellFormat.horizontalAlignment) !== null && _e !== void 0 ? _e : ((0, alignment_1.resolveReadingOrderAlignment)(readingOrder, getDefaultHorizontalAlignment(sheetId, rowIndex, columnIndex)) ||
44
48
  config_1.CELL_HORIZONTAL_ALIGNMENT);
45
- var verticalAlignment = (cellFormat === null || cellFormat === void 0 ? void 0 : cellFormat.verticalAlignment) || config_1.CELL_VERTICAL_ALIGNMENT;
49
+ // Excel's vertical justify / distributed paint as top / middle for one
50
+ // line and spread wrapped lines over the cell height (below).
51
+ var cellVerticalAlignment = (cellFormat === null || cellFormat === void 0 ? void 0 : cellFormat.verticalAlignment) || config_1.CELL_VERTICAL_ALIGNMENT;
52
+ var verticalAlignment = (0, alignment_1.resolveCanvasVerticalAlign)(cellVerticalAlignment);
53
+ var isVerticalSpread = (0, alignment_1.verticalAlignmentImpliesWrap)(cellVerticalAlignment);
46
54
  // Excel-only modes (justify / distributed / fill / centerContinuous)
47
55
  // collapse onto what the canvas text node can paint.
48
56
  var canvasTextAlign = (0, alignment_1.resolveCanvasTextAlign)(horizontalAlignment);
49
57
  var isFillAlignment = horizontalAlignment === "fill";
50
58
  // Text format
51
- var _v = textFormat !== null && textFormat !== void 0 ? textFormat : {}, colorObject = _v.color, bold = _v.bold, italic = _v.italic, strikethrough = _v.strikethrough, underline = _v.underline, baselineOffset = _v.baselineOffset;
59
+ var _v = textFormat !== null && textFormat !== void 0 ? textFormat : {}, colorObject = _v.color, bold = _v.bold, italic = _v.italic, strikethrough = _v.strikethrough, underline = _v.underline, underlineStyle = _v.underlineStyle, baselineOffset = _v.baselineOffset;
52
60
  var fontSizePt = (_f = textFormat === null || textFormat === void 0 ? void 0 : textFormat.fontSize) !== null && _f !== void 0 ? _f : defaultFontSizePoint;
53
61
  // Fall back to the theme's body font so the painter agrees with the
54
62
  // sizer (AutoSizerCanvas measures with theme.primaryFontFamily).
55
- var fontFamily = (_g = textFormat === null || textFormat === void 0 ? void 0 : textFormat.fontFamily) !== null && _g !== void 0 ? _g : theme === null || theme === void 0 ? void 0 : theme.primaryFontFamily;
63
+ var fontFamily = (_g = (0, themes_1.resolveThemeFontFamily)(textFormat === null || textFormat === void 0 ? void 0 : textFormat.fontFamily, theme)) !== null && _g !== void 0 ? _g : theme === null || theme === void 0 ? void 0 : theme.primaryFontFamily;
56
64
  var color = (0, themes_1.getStringifiedColor)(colorObject, theme);
57
- // Text decoration
58
- var textDecoration = "".concat(underline ? "underline" : "", " ").concat(strikethrough ? "line-through" : "");
65
+ // Text decoration. Konva draws only a single underline; the double and
66
+ // accounting underlines (Format Cells → Font → Underline) are stroked by
67
+ // `underlineSceneFunc` below, where the text is one unrotated line.
68
+ var hasStyledUnderline = !!underline && !!underlineStyle && underlineStyle !== "single";
69
+ var textDecorationFor = function (konvaUnderline) {
70
+ return "".concat(konvaUnderline ? "underline" : "", " ").concat(strikethrough ? "line-through" : "");
71
+ };
72
+ var textDecoration = textDecorationFor(!!underline);
59
73
  /* Because of 1px + 0.5px (gridline width + spacing )*/
60
74
  var borderWidth = 1;
61
75
  var cellSpacingY = borderWidth;
@@ -75,9 +89,14 @@ exports.Cell = (0, react_1.memo)(function (props) {
75
89
  var e_1, _a;
76
90
  try {
77
91
  for (var columnSpans_1 = tslib_1.__values(columnSpans), columnSpans_1_1 = columnSpans_1.next(); !columnSpans_1_1.done; columnSpans_1_1 = columnSpans_1.next()) {
78
- var _b = tslib_1.__read(columnSpans_1_1.value, 4), _1 = _b[0], columnOffset = _b[1], columnWidth = _b[2], cellBackground = _b[3];
92
+ var _b = tslib_1.__read(columnSpans_1_1.value, 4), spanColumnIndex = _b[0], columnOffset = _b[1], columnWidth = _b[2], cellBackground = _b[3];
79
93
  context.beginPath();
80
- var x_1 = columnOffset - shape.x() + (overflowRight ? columnWidth : 0) + 0.5;
94
+ // A column left of the cell hides the gridline on its right edge,
95
+ // one to the right the gridline on its left edge.
96
+ var x_1 = columnOffset -
97
+ shape.x() +
98
+ (spanColumnIndex < columnIndex ? columnWidth : 0) +
99
+ 0.5;
81
100
  var strokeColor = cellBackground
82
101
  ? (0, themes_1.getStringifiedColor)(cellBackground, theme)
83
102
  : defaultBackgroundColor;
@@ -96,7 +115,7 @@ exports.Cell = (0, react_1.memo)(function (props) {
96
115
  }
97
116
  finally { if (e_1) throw e_1.error; }
98
117
  }
99
- }, [defaultBackgroundColor, columnSpans, theme, overflowRight, scale]);
118
+ }, [defaultBackgroundColor, columnSpans, theme, columnIndex, scale]);
100
119
  // Show error tag
101
120
  var showError = isError || isInvalid;
102
121
  // Calculated
@@ -104,13 +123,26 @@ exports.Cell = (0, react_1.memo)(function (props) {
104
123
  // Alignment
105
124
  var isRightAligned = horizontalAlignment === "right";
106
125
  // Spacing
107
- var indentSpacing = indent ? indent * config_1.INDENT_SPACING : 0;
126
+ var indentSpacing = indent ? indent * config_1.INDENT_SPACING * scale : 0;
108
127
  var iconSpacing = config_1.DEFAULT_CELL_SPACING;
109
128
  var showExpand = false;
110
129
  var leftSpacing = (0, helpers_2.getLeftSpacing)(isCalculatedCell, expandable, isRightAligned ? showExpand : false, iconSpacing, scale);
111
- var rightSpacing = (0, helpers_2.getRightSpacing)(showFilter, showArrow, isRightAligned ? false : showExpand, iconSpacing, scale);
130
+ var rightSpacing = (0, helpers_2.getRightSpacing)(showFilter, showArrow && !arrowOutside, isRightAligned ? false : showExpand, iconSpacing, scale);
112
131
  // final cell width
113
132
  var finalCellWidth = cellWidth !== null && cellWidth !== void 0 ? cellWidth : 0;
133
+ // Centred overflow: the spill area is `[x - overflowLeft, x - overflowLeft
134
+ // + cellWidth]`. Centred text stays centred on its own cell (a blocked
135
+ // side clips it); Center Across Selection centres on the whole span.
136
+ var centredSpill = enableOverflow && overflowLeft !== undefined
137
+ ? (function () {
138
+ var spanLeft = x - overflowLeft;
139
+ if (centerOnSpan) {
140
+ return { spanLeft: spanLeft, boxLeft: spanLeft, boxWidth: finalCellWidth };
141
+ }
142
+ var reach = Math.max(overflowLeft, finalCellWidth - width - overflowLeft);
143
+ return { spanLeft: spanLeft, boxLeft: x - reach, boxWidth: width + 2 * reach };
144
+ })()
145
+ : undefined;
114
146
  // text
115
147
  var textWidth = _textWidth + indentSpacing;
116
148
  // Reserve room for the CF icon on the left side of the cell. Only adds
@@ -122,7 +154,11 @@ exports.Cell = (0, react_1.memo)(function (props) {
122
154
  // doesn't render past the cell's right edge when an iconSet is present.
123
155
  var finalTextWidth = (overflowRight
124
156
  ? Math.max(textWidth, width)
125
- : (enableOverflow ? finalCellWidth : width) -
157
+ : (centredSpill
158
+ ? centredSpill.boxWidth
159
+ : enableOverflow
160
+ ? finalCellWidth
161
+ : width) -
126
162
  rightSpacing -
127
163
  leftSpacing -
128
164
  indentSpacing) - cfIconReserve;
@@ -131,8 +167,10 @@ exports.Cell = (0, react_1.memo)(function (props) {
131
167
  ? textWidth > width
132
168
  ? x - (textWidth - width)
133
169
  : x
134
- : x +
135
- (isRightAligned ? -indentSpacing - Math.floor((padding * scale) / 2) : 0);
170
+ : centredSpill
171
+ ? centredSpill.boxLeft
172
+ : x +
173
+ (isRightAligned ? -indentSpacing - Math.floor((padding * scale) / 2) : 0);
136
174
  // Text left padding
137
175
  var textLeftPadding = textX +
138
176
  leftSpacing +
@@ -146,7 +184,9 @@ exports.Cell = (0, react_1.memo)(function (props) {
146
184
  ? enableOverflow
147
185
  ? textX + (textWidth - finalCellWidth)
148
186
  : textX
149
- : textX;
187
+ : centredSpill
188
+ ? centredSpill.spanLeft
189
+ : textX;
150
190
  var overflowWidth = finalCellWidth;
151
191
  // Clip
152
192
  var clipX = (enableOverflow ? overflowX : x) +
@@ -173,7 +213,9 @@ exports.Cell = (0, react_1.memo)(function (props) {
173
213
  : fontSize;
174
214
  // Wrap — disabled in stacked, shrink, or rotated modes. Justify /
175
215
  // distributed alignment wraps implicitly, as in Excel.
176
- var wrapRequested = wrapStrategy === "wrap" || (0, alignment_1.alignmentImpliesWrap)(horizontalAlignment);
216
+ var wrapRequested = wrapStrategy === "wrap" ||
217
+ (0, alignment_1.alignmentImpliesWrap)(horizontalAlignment) ||
218
+ isVerticalSpread;
177
219
  var textWrapStrategy = isStackedVertical || shrinkEnabled || hasNumericRotation
178
220
  ? "none"
179
221
  : wrapRequested
@@ -193,7 +235,7 @@ exports.Cell = (0, react_1.memo)(function (props) {
193
235
  // the same numbers (#1141). Konva's `lineHeight` is a multiple of the
194
236
  // font size.
195
237
  var textLineMetrics = (0, line_height_1.getLineMetrics)({ fontFamily: fontFamily, fontSize: effectiveFontSize, bold: bold, italic: italic }, lineHeightMode, lineHeight, scale);
196
- var textLineHeight = effectiveFontSize > 0
238
+ var baseTextLineHeight = effectiveFontSize > 0
197
239
  ? textLineMetrics.advance / effectiveFontSize
198
240
  : lineHeight;
199
241
  // The sizer fitted the row to Konva's text block exactly — one advance
@@ -201,6 +243,16 @@ exports.Cell = (0, react_1.memo)(function (props) {
201
243
  // by the padding on both sides, its padding box is the cell, and every
202
244
  // fitted line shows (#1182, #1199).
203
245
  var textNode = (0, grid_1.getTextNodeBounds)(y + cellSpacingY, height, padding);
246
+ // Vertical justify / distributed: spread the wrapped lines over the
247
+ // cell's inner height. The line count is estimated from the natural
248
+ // width against the wrap width (and any hard line breaks).
249
+ var wrapWidth = Math.max(1, finalTextWidth - 2 * padding);
250
+ var estimatedLineCount = shouldWrap
251
+ ? Math.max((displayValue !== null && displayValue !== void 0 ? displayValue : "").split("\n").length, Math.ceil(_textWidth / wrapWidth))
252
+ : 1;
253
+ var textLineHeight = isVerticalSpread
254
+ ? (0, alignment_1.getVerticalSpreadLineHeight)(estimatedLineCount, textNode.height - 2 * padding, effectiveFontSize, baseTextLineHeight)
255
+ : baseTextLineHeight;
204
256
  // For rotated text, anchor the rotation pivot to an alignment-aware
205
257
  // corner of the cell so the text stays inside instead of sliding off
206
258
  // (Konva otherwise rotates around the Text's top-left at x/y).
@@ -223,16 +275,36 @@ exports.Cell = (0, react_1.memo)(function (props) {
223
275
  })
224
276
  : undefined;
225
277
  var rotationDegrees = (_h = rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.rotation) !== null && _h !== void 0 ? _h : (0, alignment_1.getKonvaRotationDegrees)(textRotation);
226
- // CF data-bar geometry. Painted behind the text Group so the cell value
227
- // remains readable on top of the bar. We inset 2px vertically so the bar
228
- // doesn't touch the borders.
229
- var dataBarHeight = Math.max(0, height - 2 * CF_DATABAR_INSET_Y * scale);
230
- var dataBarMaxWidth = Math.max(0, width - 2);
231
- var dataBarFill = conditionalDataBar
232
- ? Math.max(0, Math.min(1, conditionalDataBar.fillFraction))
233
- : 0;
234
- var dataBarWidth = dataBarMaxWidth * dataBarFill;
235
- var dataBarFromRight = (conditionalDataBar === null || conditionalDataBar === void 0 ? void 0 : conditionalDataBar.direction) === "rightToLeft";
278
+ // CF data bar — painted behind the text Group so the cell value stays
279
+ // readable on top of the bar (`paintDataBar` owns the geometry).
280
+ var dataBarSceneFunc = (0, react_1.useCallback)(function (context, shape) {
281
+ var _a, _b;
282
+ if (!conditionalDataBar)
283
+ return;
284
+ var barStart = (_a = conditionalDataBar.barStart) !== null && _a !== void 0 ? _a : (conditionalDataBar.direction === "rightToLeft"
285
+ ? 1 - conditionalDataBar.fillFraction
286
+ : 0);
287
+ var barEnd = (_b = conditionalDataBar.barEnd) !== null && _b !== void 0 ? _b : barStart + Math.max(0, Math.min(1, conditionalDataBar.fillFraction));
288
+ (0, cf_data_bar_1.paintDataBar)(context, { width: shape.width(), height: shape.height(), scale: scale }, tslib_1.__assign(tslib_1.__assign({}, conditionalDataBar), { barStart: barStart, barEnd: barEnd }));
289
+ }, [conditionalDataBar, scale]);
290
+ // CF icon — Excel's vector icon at the cell's left edge, aligned with the
291
+ // cell's vertical alignment.
292
+ var cfIconShape = conditionalIcon
293
+ ? (0, cf_icons_1.getCfIcon)(conditionalIcon.iconSet, conditionalIcon.iconId)
294
+ : undefined;
295
+ var cfIconSceneFunc = (0, react_1.useCallback)(function (context, shape) {
296
+ if (!cfIconShape)
297
+ return;
298
+ var size = Math.min(config_1.CF_ICON_WIDTH * scale, shape.height() - 2 * scale);
299
+ if (size <= 0)
300
+ return;
301
+ var iconY = verticalAlignment === "top"
302
+ ? scale
303
+ : verticalAlignment === "middle"
304
+ ? (shape.height() - size) / 2
305
+ : shape.height() - size - 2 * scale;
306
+ (0, cf_icons_1.paintCfIcon)(context, cfIconShape, 2 * scale, iconY, size);
307
+ }, [cfIconShape, scale, verticalAlignment]);
236
308
  // Use the segment-based renderer only when per-segment formatting
237
309
  // exists AND none of the unsupported display modes are active.
238
310
  // Rotation, stacked-vertical, shrink-to-fit, and chips stay on the
@@ -249,10 +321,277 @@ exports.Cell = (0, react_1.memo)(function (props) {
249
321
  !isStackedVertical &&
250
322
  !hasNumericRotation &&
251
323
  (0, rich_text_1.hasRenderableRuns)(textFormatRuns !== null && textFormatRuns !== void 0 ? textFormatRuns : undefined);
324
+ // Double / accounting underlines on a single unrotated line (the default
325
+ // Text path); wrapped, rotated or rich-text cells keep Konva's single line.
326
+ var paintStyledUnderline = hasStyledUnderline &&
327
+ !useRichTextRunPath &&
328
+ !showChip &&
329
+ !shouldWrap &&
330
+ !isStackedVertical &&
331
+ !hasNumericRotation;
332
+ var textDirection = readingOrder === "rtl" ? "rtl" : readingOrder === "ltr" ? "ltr" : "inherit";
333
+ var underlineSceneFunc = (0, react_1.useCallback)(function (context) {
334
+ var e_2, _a;
335
+ if (!paintStyledUnderline || !underlineStyle)
336
+ return;
337
+ var advance = textLineMetrics.advance;
338
+ var innerLeft = textLeftPadding + padding;
339
+ var innerWidth = Math.max(0, finalTextWidth - 2 * padding);
340
+ var glyphWidth = Math.min(_textWidth, innerWidth);
341
+ var textStart = canvasTextAlign === "right"
342
+ ? innerLeft + innerWidth - glyphWidth
343
+ : canvasTextAlign === "center"
344
+ ? innerLeft + (innerWidth - glyphWidth) / 2
345
+ : innerLeft;
346
+ var innerTop = textNode.y + padding;
347
+ var innerHeight = textNode.height - 2 * padding;
348
+ var lineTop = effectiveVerticalAlignment === "top"
349
+ ? innerTop
350
+ : effectiveVerticalAlignment === "middle"
351
+ ? innerTop + (innerHeight - advance) / 2
352
+ : innerTop + innerHeight - advance;
353
+ var strokes = (0, alignment_1.getUnderlineStrokes)({
354
+ style: underlineStyle,
355
+ textX: textStart,
356
+ textWidth: glyphWidth,
357
+ cellX: x,
358
+ cellWidth: width,
359
+ baselineY: lineTop + advance / 2 + effectiveFontSize * 0.35,
360
+ fontSize: effectiveFontSize,
361
+ scale: scale,
362
+ });
363
+ context.beginPath();
364
+ try {
365
+ for (var strokes_1 = tslib_1.__values(strokes), strokes_1_1 = strokes_1.next(); !strokes_1_1.done; strokes_1_1 = strokes_1.next()) {
366
+ var _b = strokes_1_1.value, x1 = _b.x1, x2 = _b.x2, strokeY = _b.y;
367
+ var yy = Math.round(strokeY) + 0.5;
368
+ context.moveTo(x1, yy);
369
+ context.lineTo(x2, yy);
370
+ }
371
+ }
372
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
373
+ finally {
374
+ try {
375
+ if (strokes_1_1 && !strokes_1_1.done && (_a = strokes_1.return)) _a.call(strokes_1);
376
+ }
377
+ finally { if (e_2) throw e_2.error; }
378
+ }
379
+ context.setAttr("strokeStyle", color !== null && color !== void 0 ? color : defaultColor);
380
+ context.setAttr("lineWidth", Math.max(1, scale));
381
+ context.stroke();
382
+ }, [
383
+ paintStyledUnderline,
384
+ underlineStyle,
385
+ textLineMetrics.advance,
386
+ textLeftPadding,
387
+ padding,
388
+ finalTextWidth,
389
+ _textWidth,
390
+ canvasTextAlign,
391
+ textNode.y,
392
+ textNode.height,
393
+ effectiveVerticalAlignment,
394
+ x,
395
+ width,
396
+ effectiveFontSize,
397
+ scale,
398
+ color,
399
+ defaultColor,
400
+ ]);
401
+ // Excel's `*x` fill and `_x` / `?` reserves (accounting `$` left, number
402
+ // right): one unrotated, unwrapped line whose parts are placed with
403
+ // measured glyph widths. Every other display mode keeps the plain string.
404
+ var paintNumberFormatLayout = !!numberFormatLayout &&
405
+ !useRichTextRunPath &&
406
+ !showChip &&
407
+ !shouldWrap &&
408
+ !isStackedVertical &&
409
+ !hasNumericRotation &&
410
+ !shrinkEnabled &&
411
+ !isFillAlignment &&
412
+ !enableOverflow &&
413
+ textDirection !== "rtl";
414
+ var numberFormatSceneFunc = (0, react_1.useCallback)(function (context, shape) {
415
+ var e_3, _a, e_4, _b;
416
+ var _c, _d, _e, _f, _g;
417
+ if (!numberFormatLayout)
418
+ return;
419
+ var ctx = context;
420
+ ctx.setAttr("font", "".concat(textStyle, " normal ").concat(effectiveFontSize, "px ").concat(fontFamily !== null && fontFamily !== void 0 ? fontFamily : "sans-serif"));
421
+ ctx.setAttr("textBaseline", "alphabetic");
422
+ ctx.setAttr("textAlign", "left");
423
+ ctx.setAttr("fillStyle", color !== null && color !== void 0 ? color : defaultColor);
424
+ var innerWidth = Math.max(0, shape.width() - 2 * padding);
425
+ var measure = function (text) { return ctx.measureText(text).width; };
426
+ var layout = (_c = (0, number_format_layout_1.layoutNumberFormatParts)({
427
+ parts: numberFormatLayout,
428
+ measure: measure,
429
+ availableWidth: innerWidth,
430
+ align: canvasTextAlign,
431
+ })) !== null && _c !== void 0 ? _c : {
432
+ // The fixed parts alone overflow the cell: paint the plain string
433
+ // aligned the way the text node would (the group clips it).
434
+ runs: [
435
+ {
436
+ text: value !== null && value !== void 0 ? value : "",
437
+ x: canvasTextAlign === "right"
438
+ ? innerWidth - measure(value !== null && value !== void 0 ? value : "")
439
+ : canvasTextAlign === "center"
440
+ ? (innerWidth - measure(value !== null && value !== void 0 ? value : "")) / 2
441
+ : 0,
442
+ width: measure(value !== null && value !== void 0 ? value : ""),
443
+ },
444
+ ],
445
+ start: 0,
446
+ end: innerWidth,
447
+ };
448
+ // Konva's text baseline: the line box is `lineHeight × fontSize` tall,
449
+ // aligned in the node, glyphs centred on it by the font's M box.
450
+ var lineHeightPx = textLineHeight * effectiveFontSize;
451
+ var metrics = ctx.measureText("M");
452
+ var ascent = (_e = (_d = metrics.fontBoundingBoxAscent) !== null && _d !== void 0 ? _d : metrics.actualBoundingBoxAscent) !== null && _e !== void 0 ? _e : 0;
453
+ var descent = (_g = (_f = metrics.fontBoundingBoxDescent) !== null && _f !== void 0 ? _f : metrics.actualBoundingBoxDescent) !== null && _g !== void 0 ? _g : 0;
454
+ var alignY = effectiveVerticalAlignment === "top"
455
+ ? 0
456
+ : effectiveVerticalAlignment === "middle"
457
+ ? (shape.height() - lineHeightPx - 2 * padding) / 2
458
+ : shape.height() - lineHeightPx - 2 * padding;
459
+ var baselineY = padding + alignY + (ascent - descent) / 2 + lineHeightPx / 2;
460
+ try {
461
+ for (var _h = tslib_1.__values(layout.runs), _j = _h.next(); !_j.done; _j = _h.next()) {
462
+ var run = _j.value;
463
+ ctx.fillText(run.text, padding + run.x, baselineY);
464
+ }
465
+ }
466
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
467
+ finally {
468
+ try {
469
+ if (_j && !_j.done && (_a = _h.return)) _a.call(_h);
470
+ }
471
+ finally { if (e_3) throw e_3.error; }
472
+ }
473
+ if (!underline && !strikethrough)
474
+ return;
475
+ context.beginPath();
476
+ var textStart = padding + layout.start;
477
+ var textWidthPx = layout.end - layout.start;
478
+ if (underline) {
479
+ try {
480
+ for (var _k = tslib_1.__values((0, alignment_1.getUnderlineStrokes)({
481
+ style: underlineStyle !== null && underlineStyle !== void 0 ? underlineStyle : "single",
482
+ textX: textStart,
483
+ textWidth: textWidthPx,
484
+ cellX: x - shape.x(),
485
+ cellWidth: width,
486
+ baselineY: baselineY,
487
+ fontSize: effectiveFontSize,
488
+ scale: scale,
489
+ })), _l = _k.next(); !_l.done; _l = _k.next()) {
490
+ var _m = _l.value, x1 = _m.x1, x2 = _m.x2, strokeY = _m.y;
491
+ var yy = Math.round(strokeY) + 0.5;
492
+ context.moveTo(x1, yy);
493
+ context.lineTo(x2, yy);
494
+ }
495
+ }
496
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
497
+ finally {
498
+ try {
499
+ if (_l && !_l.done && (_b = _k.return)) _b.call(_k);
500
+ }
501
+ finally { if (e_4) throw e_4.error; }
502
+ }
503
+ }
504
+ if (strikethrough) {
505
+ var yy = Math.round(baselineY - effectiveFontSize * 0.3) + 0.5;
506
+ context.moveTo(textStart, yy);
507
+ context.lineTo(textStart + textWidthPx, yy);
508
+ }
509
+ ctx.setAttr("strokeStyle", color !== null && color !== void 0 ? color : defaultColor);
510
+ ctx.setAttr("lineWidth", Math.max(1, scale));
511
+ context.stroke();
512
+ }, [
513
+ numberFormatLayout,
514
+ textStyle,
515
+ effectiveFontSize,
516
+ fontFamily,
517
+ color,
518
+ defaultColor,
519
+ padding,
520
+ canvasTextAlign,
521
+ value,
522
+ textLineHeight,
523
+ effectiveVerticalAlignment,
524
+ underline,
525
+ strikethrough,
526
+ underlineStyle,
527
+ x,
528
+ width,
529
+ scale,
530
+ ]);
531
+ // Excel's horizontal `distributed`: wrapped lines spread edge to edge
532
+ // (the last one too), a lone word centred, the indent kept on both sides.
533
+ var paintDistributed = horizontalAlignment === "distributed" &&
534
+ !useRichTextRunPath &&
535
+ !showChip &&
536
+ !isStackedVertical &&
537
+ !hasNumericRotation &&
538
+ !shrinkEnabled;
539
+ var distributedSceneFunc = (0, react_1.useCallback)(function (context, shape) {
540
+ var _a, _b, _c, _d;
541
+ var ctx = context;
542
+ ctx.setAttr("font", "".concat(textStyle, " normal ").concat(effectiveFontSize, "px ").concat(fontFamily !== null && fontFamily !== void 0 ? fontFamily : "sans-serif"));
543
+ ctx.setAttr("textBaseline", "alphabetic");
544
+ ctx.setAttr("textAlign", "left");
545
+ ctx.setAttr("fillStyle", color !== null && color !== void 0 ? color : defaultColor);
546
+ var innerWidth = Math.max(0, shape.width() - 2 * padding - indentSpacing);
547
+ var lines = (0, alignment_1.layoutDistributedLines)(displayValue !== null && displayValue !== void 0 ? displayValue : "", innerWidth, function (text) { return ctx.measureText(text).width; });
548
+ var lineHeightPx = textLineHeight * effectiveFontSize;
549
+ var metrics = ctx.measureText("M");
550
+ var ascent = (_b = (_a = metrics.fontBoundingBoxAscent) !== null && _a !== void 0 ? _a : metrics.actualBoundingBoxAscent) !== null && _b !== void 0 ? _b : 0;
551
+ var descent = (_d = (_c = metrics.fontBoundingBoxDescent) !== null && _c !== void 0 ? _c : metrics.actualBoundingBoxDescent) !== null && _d !== void 0 ? _d : 0;
552
+ var blockHeight = lines.length * lineHeightPx;
553
+ var alignY = effectiveVerticalAlignment === "top"
554
+ ? 0
555
+ : effectiveVerticalAlignment === "middle"
556
+ ? (shape.height() - blockHeight - 2 * padding) / 2
557
+ : shape.height() - blockHeight - 2 * padding;
558
+ lines.forEach(function (words, lineIndex) {
559
+ var e_5, _a;
560
+ var baselineY = padding +
561
+ alignY +
562
+ lineIndex * lineHeightPx +
563
+ (ascent - descent) / 2 +
564
+ lineHeightPx / 2;
565
+ try {
566
+ for (var words_1 = tslib_1.__values(words), words_1_1 = words_1.next(); !words_1_1.done; words_1_1 = words_1.next()) {
567
+ var word = words_1_1.value;
568
+ ctx.fillText(word.text, padding + word.x, baselineY);
569
+ }
570
+ }
571
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
572
+ finally {
573
+ try {
574
+ if (words_1_1 && !words_1_1.done && (_a = words_1.return)) _a.call(words_1);
575
+ }
576
+ finally { if (e_5) throw e_5.error; }
577
+ }
578
+ });
579
+ }, [
580
+ textStyle,
581
+ effectiveFontSize,
582
+ fontFamily,
583
+ color,
584
+ defaultColor,
585
+ padding,
586
+ indentSpacing,
587
+ displayValue,
588
+ textLineHeight,
589
+ effectiveVerticalAlignment,
590
+ ]);
252
591
  return (react_1.default.createElement(react_1.default.Fragment, null,
253
592
  enableOverflow && showGridLines ? (react_1.default.createElement(react_konva_1.Shape, { x: x, y: y, width: width, height: height, sceneFunc: overflowFillFunc, listening: false })) : null,
254
- conditionalDataBar && dataBarWidth > 0 ? (react_1.default.createElement(react_konva_1.Rect, { x: dataBarFromRight ? x + width - 1 - dataBarWidth : x + 1, y: y + CF_DATABAR_INSET_Y * scale, width: dataBarWidth, height: dataBarHeight, fill: conditionalDataBar.color, stroke: conditionalDataBar.borderColor, strokeWidth: conditionalDataBar.borderColor ? 1 : 0, listening: false, perfectDrawEnabled: false })) : null,
255
- conditionalIcon ? (react_1.default.createElement(react_konva_1.Text, { x: x + 2, y: y, width: config_1.CF_ICON_WIDTH * scale, height: height, text: conditionalIcon.glyph, fill: (_k = (_j = conditionalIcon.color) !== null && _j !== void 0 ? _j : color) !== null && _k !== void 0 ? _k : defaultColor, verticalAlign: "middle", align: "center", fontSize: fontSize, listening: false, perfectDrawEnabled: false })) : null,
593
+ conditionalDataBar ? (react_1.default.createElement(react_konva_1.Shape, { x: x, y: y, width: width, height: height, sceneFunc: dataBarSceneFunc, listening: false, perfectDrawEnabled: false })) : null,
594
+ conditionalIcon && cfIconShape ? (react_1.default.createElement(react_konva_1.Shape, { x: x, y: y, width: width, height: height, sceneFunc: cfIconSceneFunc, listening: false, perfectDrawEnabled: false })) : null,
256
595
  showCheckbox ? (react_1.default.createElement(cell_checkbox_1.CellCheckbox, { x: x, y: y, scale: scale, width: width, height: height, checked: isChecked, onChange: onCheckboxClick, rowIndex: props.rowIndex, columnIndex: props.columnIndex, verticalAlignment: verticalAlignment, horizontalAlignment: horizontalAlignment })) : showText ? (react_1.default.createElement(react_konva_1.Group, { clipY: y + borderWidth, clipHeight: height, clipX: clipX, clipWidth: clipWidth }, showChip ? (react_1.default.createElement(react_konva_1.Label, { width: width - config_1.CHIP_SPACING * scale, height: config_1.CHIP_HEIGHT * scale, x: textLeftPadding, y: (0, helpers_1.getChipVerticalPosition)(y, height, scale, verticalAlignment), offsetX: -config_1.CHIP_SPACING * scale, offsetY: -config_1.CHIP_SPACING * scale },
257
596
  react_1.default.createElement(react_konva_1.Tag, { height: config_1.CHIP_HEIGHT * scale, fill: chipBackgroundColor, cornerRadius: config_1.CHIP_RADIUS * scale, perfectDrawEnabled: false, hitStrokeWidth: 0 }),
258
597
  react_1.default.createElement(react_konva_1.Text, { text: displayValue, fill: color !== null && color !== void 0 ? color : defaultColor, verticalAlign: effectiveVerticalAlignment, align: canvasTextAlign, fontFamily: fontFamily, fontStyle: textStyle, fontSize: fontSize, textDecoration: textDecoration, padding: padding, lineHeight: 1, offsetY: -1, perfectDrawEnabled: false, wrap: "none" }))) : useRichTextRunPath ? (
@@ -272,8 +611,10 @@ exports.Cell = (0, react_1.memo)(function (props) {
272
611
  // sup/sub font scale itself (exactly once). Shrink-to-
273
612
  // fit never reaches this path, so `baseFontSize` equals
274
613
  // `effectiveFontSize` for every other cell.
275
- baseFontSize: baseFontSize, baseBold: !!bold, baseItalic: !!italic, baseUnderline: !!underline, baseStrikethrough: !!strikethrough, baseBaselineOffset: baselineOffset !== null && baselineOffset !== void 0 ? baselineOffset : undefined, horizontalAlign: canvasTextAlign, verticalAlign: effectiveVerticalAlignment, lineHeight: lineHeight, lineHeightMode: lineHeightMode, scale: scale, wrap: shouldWrap, theme: theme })) : (react_1.default.createElement(react_konva_1.Text, { x: (_l = rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.x) !== null && _l !== void 0 ? _l : textLeftPadding, y: (_m = rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.y) !== null && _m !== void 0 ? _m : textNode.y, offsetX: rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.offsetX, offsetY: rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.offsetY, height: rotatedLayout ? approxTextHeight : textNode.height, width: (_o = rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.width) !== null && _o !== void 0 ? _o : finalTextWidth, text: displayValue, fill: color !== null && color !== void 0 ? color : defaultColor, verticalAlign: rotatedLayout ? "top" : effectiveVerticalAlignment, align: rotatedLayout ? "left" : canvasTextAlign, fontFamily: fontFamily, fontStyle: textStyle, fontSize: effectiveFontSize, textDecoration: textDecoration, padding: padding, wrap: textWrapStrategy, lineHeight: textLineHeight, rotation: rotationDegrees, hitStrokeWidth: 0, perfectDrawEnabled: false })))) : imageUrl ? (react_1.default.createElement(grid_1.Image, { x: x, y: y, spacing: 1, width: width, height: height, url: imageUrl, perfectDrawEnabled: false, horizontalAlignment: canvasTextAlign === "justify" ? "left" : canvasTextAlign, verticalAlignment: verticalAlignment })) : null,
276
- showFilter ? (react_1.default.createElement(cell_filter_1.CellFilter, { scale: scale, isActive: isFilterActive, onClick: readonly ? undefined : onFilterClick, rowIndex: props.rowIndex, columnIndex: props.columnIndex, x: x, y: y, height: height, width: width, filterIconColor: filterIconColor, verticalAlignment: verticalAlignment, backgroundColor: defaultBackgroundColor, sortOrder: sortOrder })) : showArrow && !readonly ? (react_1.default.createElement(cell_arrow_1.CellArrow, { scale: scale, onClick: onArrowClick !== null && onArrowClick !== void 0 ? onArrowClick : onRequestEdit, rowIndex: rowIndex, columnIndex: columnIndex, x: x, y: y, height: height, width: width, verticalAlignment: verticalAlignment })) : null,
614
+ baseFontSize: baseFontSize, baseBold: !!bold, baseItalic: !!italic, baseUnderline: !!underline, baseStrikethrough: !!strikethrough, baseBaselineOffset: baselineOffset !== null && baselineOffset !== void 0 ? baselineOffset : undefined, horizontalAlign: canvasTextAlign, verticalAlign: effectiveVerticalAlignment, lineHeight: lineHeight, lineHeightMode: lineHeightMode, scale: scale, wrap: shouldWrap, theme: theme })) : paintDistributed ? (react_1.default.createElement(react_konva_1.Shape, { x: textLeftPadding, y: textNode.y, width: finalTextWidth, height: textNode.height, sceneFunc: distributedSceneFunc, listening: false, perfectDrawEnabled: false })) : paintNumberFormatLayout ? (react_1.default.createElement(react_konva_1.Shape, { x: textLeftPadding, y: textNode.y, width: finalTextWidth, height: textNode.height, sceneFunc: numberFormatSceneFunc, listening: false, perfectDrawEnabled: false })) : (react_1.default.createElement(react_1.default.Fragment, null,
615
+ react_1.default.createElement(react_konva_1.Text, { x: (_j = rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.x) !== null && _j !== void 0 ? _j : textLeftPadding, y: (_k = rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.y) !== null && _k !== void 0 ? _k : textNode.y, offsetX: rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.offsetX, offsetY: rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.offsetY, height: rotatedLayout ? approxTextHeight : textNode.height, width: (_l = rotatedLayout === null || rotatedLayout === void 0 ? void 0 : rotatedLayout.width) !== null && _l !== void 0 ? _l : finalTextWidth, text: displayValue, fill: color !== null && color !== void 0 ? color : defaultColor, verticalAlign: rotatedLayout ? "top" : effectiveVerticalAlignment, align: rotatedLayout ? "left" : canvasTextAlign, fontFamily: fontFamily, fontStyle: textStyle, fontSize: effectiveFontSize, textDecoration: paintStyledUnderline ? textDecorationFor(false) : textDecoration, padding: padding, wrap: textWrapStrategy, lineHeight: textLineHeight, rotation: rotationDegrees, direction: textDirection, hitStrokeWidth: 0, perfectDrawEnabled: false }),
616
+ paintStyledUnderline ? (react_1.default.createElement(react_konva_1.Shape, { sceneFunc: underlineSceneFunc, listening: false, perfectDrawEnabled: false })) : null)))) : imageUrl ? (react_1.default.createElement(grid_1.Image, { x: x, y: y, spacing: 1, width: width, height: height, url: imageUrl, perfectDrawEnabled: false, horizontalAlignment: canvasTextAlign === "justify" ? "left" : canvasTextAlign, verticalAlignment: verticalAlignment })) : null,
617
+ showFilter ? (react_1.default.createElement(cell_filter_1.CellFilter, { scale: scale, isActive: isFilterActive, onClick: readonly ? undefined : onFilterClick, rowIndex: props.rowIndex, columnIndex: props.columnIndex, x: x, y: y, height: height, width: width, filterIconColor: filterIconColor, verticalAlignment: verticalAlignment, backgroundColor: defaultBackgroundColor, sortOrder: sortOrder })) : showArrow && !readonly ? (react_1.default.createElement(cell_arrow_1.CellArrow, { scale: scale, onClick: onArrowClick !== null && onArrowClick !== void 0 ? onArrowClick : onRequestEdit, rowIndex: rowIndex, columnIndex: columnIndex, x: arrowOutside ? x + (config_1.ARROW_DOWN_WIDTH + 4) * scale : x, y: y, height: height, width: width, verticalAlignment: verticalAlignment })) : null,
277
618
  expandable ? (react_1.default.createElement(cell_group_1.CellGroup, { scale: scale, onClick: function (cell) {
278
619
  onExpandCollapse === null || onExpandCollapse === void 0 ? void 0 : onExpandCollapse(cell, !expanded);
279
620
  }, rowIndex: rowIndex, columnIndex: columnIndex, x: x + indentSpacing, y: y, height: height, width: width, verticalAlignment: verticalAlignment, expanded: expanded, theme: theme })) : null,
@@ -0,0 +1,35 @@
1
+ import { type NumberFormatLayoutPart } from "@rowsncolumns/utils";
2
+ export type NumberFormatRun = {
3
+ text: string;
4
+ x: number;
5
+ width: number;
6
+ };
7
+ export type NumberFormatRunLayout = {
8
+ runs: NumberFormatRun[];
9
+ /** Left edge of the first painted glyph (or reserve). */
10
+ start: number;
11
+ /** Right edge of the last one. */
12
+ end: number;
13
+ };
14
+ /**
15
+ * Position the parts inside `availableWidth`. Parts before the (first) fill
16
+ * start at the left edge and parts after it end at the right edge, with the
17
+ * fill character repeated in between as many whole times as it fits —
18
+ * Excel's accounting format (`$` left, number right). Without a fill the
19
+ * block is aligned by `align`. Returns `undefined` when the fixed parts
20
+ * alone do not fit, so the caller keeps its plain-text paint.
21
+ */
22
+ export declare const layoutNumberFormatParts: ({ parts, measure, availableWidth, align, }: {
23
+ parts: readonly NumberFormatLayoutPart[];
24
+ measure: (text: string) => number;
25
+ availableWidth: number;
26
+ align: "left" | "center" | "right" | "justify";
27
+ }) => NumberFormatRunLayout | undefined;
28
+ /**
29
+ * The layout parts for a cell, or `undefined` when the pattern has no
30
+ * width-aware token or when the parts would paint a different string than
31
+ * the cell's formatted value (another engine, locale or conditional number
32
+ * format produced it) — the plain string then stays authoritative.
33
+ */
34
+ export declare const getCellNumberFormatLayout: (pattern: string | null | undefined, value: number | string | null | undefined, formattedValue: string | null | undefined, locale?: string) => NumberFormatLayoutPart[] | undefined;
35
+ //# sourceMappingURL=number-format-layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"number-format-layout.d.ts","sourceRoot":"","sources":["../../../../components/cell/number-format-layout.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,sBAAsB,EAG5B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAAI,4CAKrC;IACD,KAAK,EAAE,SAAS,sBAAsB,EAAE,CAAC;IACzC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;CAChD,KAAG,qBAAqB,GAAG,SA+D3B,CAAC;AAKF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,OAAO,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,gBAAgB,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,SAAS,MAAM,KACd,sBAAsB,EAAE,GAAG,SAa7B,CAAC"}