@svgrid/enterprise 3.0.2 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (364) hide show
  1. package/LICENSE +94 -24
  2. package/README.md +36 -4
  3. package/dist/SvAdvancedFilter.svelte +1 -1
  4. package/dist/SvAlertsManager.svelte +2 -1
  5. package/dist/SvBoard.svelte +2 -1
  6. package/dist/SvExportMenu.svelte +4 -1
  7. package/dist/SvExportMenu.svelte.d.ts +0 -13
  8. package/dist/SvExpressionEditor.svelte +3 -3
  9. package/dist/SvFormulaBar.svelte +94 -20
  10. package/dist/SvFormulaBar.svelte.d.ts +7 -0
  11. package/dist/SvGridAlerts.svelte +49 -9
  12. package/dist/SvGridBoard.svelte +13 -8
  13. package/dist/SvGridBulkEditDrawer.svelte +26 -2
  14. package/dist/SvGridEditPanel.svelte +3 -0
  15. package/dist/SvGridScheduler.svelte +69 -40
  16. package/dist/SvGridSelectionBar.svelte +10 -3
  17. package/dist/SvPivotDesigner.svelte +198 -40
  18. package/dist/SvPivotDesigner.svelte.d.ts +27 -20
  19. package/dist/SvSheet.svelte +4043 -243
  20. package/dist/SvSheet.svelte.d.ts +76 -3
  21. package/dist/SvSheetChartSetup.svelte +151 -0
  22. package/dist/SvSheetChartSetup.svelte.d.ts +18 -0
  23. package/dist/SvSheetComment.svelte +216 -31
  24. package/dist/SvSheetComment.svelte.d.ts +11 -11
  25. package/dist/SvSheetConditionalFormat.svelte +28 -31
  26. package/dist/SvSheetDataValidation.svelte +66 -42
  27. package/dist/SvSheetEditRanges.svelte +217 -0
  28. package/dist/SvSheetEditRanges.svelte.d.ts +15 -0
  29. package/dist/SvSheetErrors.svelte +125 -0
  30. package/dist/SvSheetErrors.svelte.d.ts +20 -0
  31. package/dist/SvSheetEvaluate.svelte +133 -0
  32. package/dist/SvSheetEvaluate.svelte.d.ts +15 -0
  33. package/dist/SvSheetFilterMenu.svelte +137 -34
  34. package/dist/SvSheetFilterMenu.svelte.d.ts +5 -0
  35. package/dist/SvSheetFindReplace.svelte +19 -19
  36. package/dist/SvSheetFormatCells.svelte +125 -81
  37. package/dist/SvSheetGoalSeek.svelte +17 -16
  38. package/dist/SvSheetInsertFunction.svelte +15 -13
  39. package/dist/SvSheetIteration.svelte +81 -0
  40. package/dist/SvSheetIteration.svelte.d.ts +10 -0
  41. package/dist/SvSheetLink.svelte +99 -0
  42. package/dist/SvSheetLink.svelte.d.ts +17 -0
  43. package/dist/SvSheetListPicker.svelte +4 -2
  44. package/dist/SvSheetListPicker.svelte.d.ts +0 -6
  45. package/dist/SvSheetManageRules.svelte +20 -18
  46. package/dist/SvSheetNameManager.svelte +17 -15
  47. package/dist/SvSheetPageSetup.svelte +159 -0
  48. package/dist/SvSheetPageSetup.svelte.d.ts +13 -0
  49. package/dist/SvSheetPasteSpecial.svelte +22 -20
  50. package/dist/SvSheetPivot.svelte +220 -0
  51. package/dist/SvSheetPivot.svelte.d.ts +21 -0
  52. package/dist/SvSheetProtectSheet.svelte +81 -0
  53. package/dist/SvSheetProtectSheet.svelte.d.ts +11 -0
  54. package/dist/SvSheetRemoveDuplicates.svelte +13 -10
  55. package/dist/SvSheetRibbon.svelte +104 -51
  56. package/dist/SvSheetSizeDialog.svelte +4 -2
  57. package/dist/SvSheetSort.svelte +218 -0
  58. package/dist/SvSheetSort.svelte.d.ts +28 -0
  59. package/dist/SvSheetSparklines.svelte +135 -0
  60. package/dist/SvSheetSparklines.svelte.d.ts +14 -0
  61. package/dist/SvSheetTable.svelte +160 -0
  62. package/dist/SvSheetTable.svelte.d.ts +24 -0
  63. package/dist/SvSheetTabs.svelte +161 -31
  64. package/dist/SvSheetTabs.svelte.d.ts +22 -8
  65. package/dist/SvSheetTextToColumns.svelte +20 -20
  66. package/dist/SvSheetValidationAlert.svelte +8 -6
  67. package/dist/advanced-filter-enable.js +1 -1
  68. package/dist/alerts/alert-engine.d.ts +6 -0
  69. package/dist/alerts/alert-engine.js +21 -4
  70. package/dist/alerts/alert-formats.js +2 -0
  71. package/dist/alerts/alert-types.d.ts +1 -1
  72. package/dist/alerts.d.ts +1 -1
  73. package/dist/alerts.js +2 -2
  74. package/dist/board.js +2 -2
  75. package/dist/bulk-edit.d.ts +3 -1
  76. package/dist/bulk-edit.js +1 -1
  77. package/dist/cdn/svgrid-enterprise.svelte-external.js +39827 -16429
  78. package/dist/designer/assets/GridMenus-8gTNssgV.js +8 -0
  79. package/dist/designer/assets/{SvChartMenu-D9hEeHar.js → SvChartMenu-BDoeqGz6.js} +1 -1
  80. package/dist/designer/assets/{SvDateTimePicker-DARvKUL2.js → SvDateTimePicker-DCPg7WGN.js} +1 -1
  81. package/dist/designer/assets/SvGridCellEditor-DMoWJjEI.js +4 -0
  82. package/dist/designer/assets/{SvGridChart-B8j1SSy3.js → SvGridChart-Cy1ATrWh.js} +2 -2
  83. package/dist/designer/assets/SvGridChartBuilder-eQ3mn0L9.js +1 -0
  84. package/dist/designer/assets/{SvGridChartPanel-pT6ITc2P.js → SvGridChartPanel-CATdVc9X.js} +3 -3
  85. package/dist/designer/assets/{SvGridChartView-bg281UA1.js → SvGridChartView-CmsZtCED.js} +1 -1
  86. package/dist/designer/assets/SvGridDropdown-Cjz0H-fI.js +1 -0
  87. package/dist/designer/assets/{SvTabs-UFCMTHXS.js → SvTabs-2mHC6oaz.js} +1 -1
  88. package/dist/designer/assets/cell-formatting-BbubJTVz.js +1 -0
  89. package/dist/designer/assets/{chart-cIPUsbM5.js → chart-Cn7MnNqA.js} +1 -1
  90. package/dist/designer/assets/{chart-panel-messages-DtTxpBUU.js → chart-panel-messages-Dz7PTIqT.js} +1 -1
  91. package/dist/designer/assets/{chart-summary-Czu_5epb.js → chart-summary-BD1qYB2R.js} +1 -1
  92. package/dist/designer/assets/{chart-trend-D5I5VEe8.js → chart-trend-B8xr5LuD.js} +1 -1
  93. package/dist/designer/assets/{dismissable-BO547MH9.js → dismissable-ChWRPkoa.js} +1 -1
  94. package/dist/designer/assets/{export-format-D-eP4b2l.js → export-format-DGckmgKr.js} +1 -1
  95. package/dist/designer/assets/{focus-trap-CAreAhlU.js → focus-trap-V2-6Fy9I.js} +1 -1
  96. package/dist/designer/assets/{index-DwU7CAMm.js → index-D5bVbuzI.js} +317 -315
  97. package/dist/designer/assets/index-_JVFxt02.css +1 -0
  98. package/dist/designer/assets/row-resize-BInFWCpr.js +1 -0
  99. package/dist/designer/assets/server-block-cache-CXJKkJpy.js +1 -0
  100. package/dist/designer/assets/src-DUQ4xE3x.js +58 -0
  101. package/dist/designer/assets/validate-C3B8QKsM.js +1 -0
  102. package/dist/designer/index.html +17 -16
  103. package/dist/export-pdf.d.ts +75 -0
  104. package/dist/export-pdf.js +216 -15
  105. package/dist/export.js +10 -2
  106. package/dist/gantt/SvGridGantt.svelte +2890 -0
  107. package/dist/gantt/SvGridGantt.svelte.d.ts +30 -0
  108. package/dist/gantt/gantt-config.d.ts +73 -0
  109. package/dist/gantt/gantt-config.js +1 -0
  110. package/dist/gantt/gantt-critical-path.d.ts +67 -0
  111. package/dist/gantt/gantt-critical-path.js +207 -0
  112. package/dist/gantt/gantt-model.d.ts +257 -0
  113. package/dist/gantt/gantt-model.js +651 -0
  114. package/dist/gantt/gantt-resources.d.ts +59 -0
  115. package/dist/gantt/gantt-resources.js +71 -0
  116. package/dist/gantt/gantt.d.ts +7 -0
  117. package/dist/gantt/gantt.js +36 -0
  118. package/dist/gantt/index.d.ts +15 -0
  119. package/dist/gantt/index.js +22 -0
  120. package/dist/gantt/timeline-arrows.d.ts +102 -0
  121. package/dist/gantt/timeline-arrows.js +181 -0
  122. package/dist/import.d.ts +2 -2
  123. package/dist/import.js +1 -1
  124. package/dist/index.d.ts +34 -7
  125. package/dist/index.js +44 -7
  126. package/dist/install.js +8 -1
  127. package/dist/license-core.d.ts +17 -1
  128. package/dist/license-core.js +16 -5
  129. package/dist/license.d.ts +18 -2
  130. package/dist/license.js +71 -6
  131. package/dist/node/studio.js +140 -8
  132. package/dist/pivot-enable.js +2 -2
  133. package/dist/scheduler-dependencies.d.ts +35 -0
  134. package/dist/scheduler-dependencies.js +36 -1
  135. package/dist/scheduler.js +2 -2
  136. package/dist/selection-bar.js +2 -2
  137. package/dist/server/SvGroupCell.svelte +213 -0
  138. package/dist/server/SvGroupCell.svelte.d.ts +62 -0
  139. package/dist/server/SvRowGroupPanel.svelte +322 -0
  140. package/dist/server/SvRowGroupPanel.svelte.d.ts +37 -0
  141. package/dist/server/enable.d.ts +17 -0
  142. package/dist/server/enable.js +49 -0
  143. package/dist/server/index.d.ts +22 -0
  144. package/dist/server/index.js +24 -0
  145. package/dist/server/messages.d.ts +45 -0
  146. package/dist/server/messages.js +35 -0
  147. package/dist/server/server-group-model.d.ts +104 -0
  148. package/dist/server/server-group-model.js +272 -0
  149. package/dist/server/server-pivot.d.ts +46 -0
  150. package/dist/server/server-pivot.js +57 -0
  151. package/dist/server/server-row-model.d.ts +547 -0
  152. package/dist/server/server-row-model.js +1551 -0
  153. package/dist/server/server-selection.d.ts +99 -0
  154. package/dist/server/server-selection.js +215 -0
  155. package/dist/server/svgrid-adapter.d.ts +155 -0
  156. package/dist/server/svgrid-adapter.js +202 -0
  157. package/dist/sheet/ast.d.ts +45 -1
  158. package/dist/sheet/ast.js +14 -0
  159. package/dist/sheet/auto-filter.d.ts +58 -4
  160. package/dist/sheet/auto-filter.js +159 -11
  161. package/dist/sheet/autocomplete.d.ts +9 -0
  162. package/dist/sheet/autocomplete.js +90 -4
  163. package/dist/sheet/cell-images.d.ts +39 -0
  164. package/dist/sheet/cell-images.js +90 -0
  165. package/dist/sheet/cell-types.d.ts +58 -0
  166. package/dist/sheet/cell-types.js +96 -0
  167. package/dist/sheet/coerce.d.ts +40 -0
  168. package/dist/sheet/coerce.js +170 -3
  169. package/dist/sheet/comments.d.ts +43 -9
  170. package/dist/sheet/comments.js +85 -27
  171. package/dist/sheet/conditional-formats.d.ts +29 -6
  172. package/dist/sheet/conditional-formats.js +37 -12
  173. package/dist/sheet/csv.d.ts +32 -0
  174. package/dist/sheet/csv.js +158 -0
  175. package/dist/sheet/culture.d.ts +87 -0
  176. package/dist/sheet/culture.js +247 -0
  177. package/dist/sheet/delta.d.ts +102 -0
  178. package/dist/sheet/delta.js +203 -0
  179. package/dist/sheet/deps.d.ts +45 -1
  180. package/dist/sheet/deps.js +77 -2
  181. package/dist/sheet/document.d.ts +106 -4
  182. package/dist/sheet/document.js +204 -3
  183. package/dist/sheet/engine.d.ts +67 -0
  184. package/dist/sheet/engine.js +19 -0
  185. package/dist/sheet/entry.d.ts +8 -4
  186. package/dist/sheet/entry.js +171 -21
  187. package/dist/sheet/error-check.d.ts +49 -0
  188. package/dist/sheet/error-check.js +83 -0
  189. package/dist/sheet/evaluate-steps.d.ts +48 -0
  190. package/dist/sheet/evaluate-steps.js +196 -0
  191. package/dist/sheet/evaluate.d.ts +67 -0
  192. package/dist/sheet/evaluate.js +725 -13
  193. package/dist/sheet/filter-files.d.ts +37 -0
  194. package/dist/sheet/filter-files.js +465 -0
  195. package/dist/sheet/format-store.d.ts +15 -0
  196. package/dist/sheet/format-store.js +11 -1
  197. package/dist/sheet/from-rows.d.ts +14 -0
  198. package/dist/sheet/from-rows.js +50 -0
  199. package/dist/sheet/function-catalog.d.ts +1 -1
  200. package/dist/sheet/function-catalog.js +296 -5
  201. package/dist/sheet/functions.js +363 -91
  202. package/dist/sheet/index.d.ts +35 -8
  203. package/dist/sheet/index.js +35 -8
  204. package/dist/sheet/links.d.ts +57 -0
  205. package/dist/sheet/links.js +174 -0
  206. package/dist/sheet/messages.d.ts +778 -0
  207. package/dist/sheet/messages.js +806 -0
  208. package/dist/sheet/number-format.d.ts +52 -5
  209. package/dist/sheet/number-format.js +465 -68
  210. package/dist/sheet/objects.d.ts +106 -0
  211. package/dist/sheet/objects.js +149 -0
  212. package/dist/sheet/ods-document.d.ts +44 -0
  213. package/dist/sheet/ods-document.js +1275 -0
  214. package/dist/sheet/open-file.d.ts +26 -0
  215. package/dist/sheet/open-file.js +56 -0
  216. package/dist/sheet/outline.d.ts +82 -0
  217. package/dist/sheet/outline.js +228 -0
  218. package/dist/sheet/packs/array.d.ts +16 -0
  219. package/dist/sheet/packs/array.js +172 -0
  220. package/dist/sheet/packs/database.d.ts +42 -0
  221. package/dist/sheet/packs/database.js +142 -0
  222. package/dist/sheet/packs/engineering.d.ts +2 -0
  223. package/dist/sheet/packs/engineering.js +296 -0
  224. package/dist/sheet/packs/financial.d.ts +5 -0
  225. package/dist/sheet/packs/financial.js +220 -0
  226. package/dist/sheet/packs/math-stats.d.ts +2 -0
  227. package/dist/sheet/packs/math-stats.js +372 -0
  228. package/dist/sheet/packs/special.d.ts +44 -0
  229. package/dist/sheet/packs/special.js +187 -0
  230. package/dist/sheet/packs/stats-dist.d.ts +2 -0
  231. package/dist/sheet/packs/stats-dist.js +785 -0
  232. package/dist/sheet/packs/text-date.d.ts +2 -0
  233. package/dist/sheet/packs/text-date.js +332 -0
  234. package/dist/sheet/packs/trig.d.ts +2 -0
  235. package/dist/sheet/packs/trig.js +73 -0
  236. package/dist/sheet/page-setup.d.ts +73 -0
  237. package/dist/sheet/page-setup.js +73 -0
  238. package/dist/sheet/parse.js +42 -10
  239. package/dist/sheet/paste-special.d.ts +22 -0
  240. package/dist/sheet/paste-special.js +14 -5
  241. package/dist/sheet/pivot-range.d.ts +160 -0
  242. package/dist/sheet/pivot-range.js +333 -0
  243. package/dist/sheet/presence.d.ts +73 -0
  244. package/dist/sheet/presence.js +79 -0
  245. package/dist/sheet/print.d.ts +104 -0
  246. package/dist/sheet/print.js +169 -0
  247. package/dist/sheet/protection.d.ts +55 -1
  248. package/dist/sheet/protection.js +55 -2
  249. package/dist/sheet/rects.d.ts +1 -1
  250. package/dist/sheet/refs.d.ts +48 -0
  251. package/dist/sheet/refs.js +155 -8
  252. package/dist/sheet/ribbon-icons.d.ts +1 -1
  253. package/dist/sheet/ribbon-icons.js +186 -0
  254. package/dist/sheet/ribbon.d.ts +1 -1
  255. package/dist/sheet/ribbon.js +324 -23
  256. package/dist/sheet/sheet-kinds.d.ts +74 -0
  257. package/dist/sheet/sheet-kinds.js +91 -0
  258. package/dist/sheet/shortcuts.d.ts +13 -3
  259. package/dist/sheet/shortcuts.js +63 -12
  260. package/dist/sheet/sort.d.ts +51 -0
  261. package/dist/sheet/sort.js +107 -0
  262. package/dist/sheet/sparklines.d.ts +111 -0
  263. package/dist/sheet/sparklines.js +204 -0
  264. package/dist/sheet/table-styles.d.ts +74 -0
  265. package/dist/sheet/table-styles.js +152 -0
  266. package/dist/sheet/tables.d.ts +19 -0
  267. package/dist/sheet/tables.js +31 -0
  268. package/dist/sheet/tokenize.d.ts +18 -1
  269. package/dist/sheet/tokenize.js +60 -9
  270. package/dist/sheet/validation.d.ts +16 -0
  271. package/dist/sheet/validation.js +37 -0
  272. package/dist/sheet/workbook.d.ts +148 -3
  273. package/dist/sheet/workbook.js +742 -31
  274. package/dist/sheet/xls-cfb.d.ts +32 -0
  275. package/dist/sheet/xls-cfb.js +290 -0
  276. package/dist/sheet/xls-document.d.ts +10 -0
  277. package/dist/sheet/xls-document.js +1243 -0
  278. package/dist/sheet/xls-formula.d.ts +40 -0
  279. package/dist/sheet/xls-formula.js +569 -0
  280. package/dist/sheet/xlsx-document.d.ts +108 -0
  281. package/dist/sheet/xlsx-document.js +1849 -0
  282. package/dist/sheet/xlsx-drawing.d.ts +99 -0
  283. package/dist/sheet/xlsx-drawing.js +420 -0
  284. package/dist/sheet-enable.js +6 -7
  285. package/dist/sheet-text.d.ts +7 -0
  286. package/dist/sheet-text.js +29 -0
  287. package/dist/sources/auth-supabase.js +2 -2
  288. package/dist/sources/realtime-supabase.js +2 -2
  289. package/dist/sources/rest.d.ts +6 -2
  290. package/dist/sources/rest.js +42 -7
  291. package/dist/sources/supabase.d.ts +10 -1
  292. package/dist/sources/supabase.js +73 -40
  293. package/dist/studio/emit-project.js +14 -1
  294. package/dist/studio/index.js +1 -1
  295. package/dist/studio/project.d.ts +11 -2
  296. package/dist/studio/project.js +5 -2
  297. package/dist/studio/ui-components.generated.js +107 -2
  298. package/dist/sveltekit/in-memory.d.ts +2 -2
  299. package/dist/sveltekit/in-memory.js +125 -4
  300. package/dist/sveltekit/index.d.ts +1 -1
  301. package/dist/sveltekit/index.js +1 -1
  302. package/dist/sveltekit/query-plan.d.ts +50 -4
  303. package/dist/sveltekit/query-plan.js +25 -3
  304. package/dist/sveltekit/sql-source.d.ts +6 -0
  305. package/dist/sveltekit/sql-source.js +34 -6
  306. package/dist/sveltekit/sql.d.ts +31 -0
  307. package/dist/sveltekit/sql.js +135 -25
  308. package/dist/sveltekit/transport.d.ts +10 -2
  309. package/dist/sveltekit/transport.js +30 -6
  310. package/dist/upgrade-prompt.d.ts +1 -1
  311. package/dist/version.d.ts +1 -1
  312. package/dist/version.js +1 -1
  313. package/dist/watermark.js +35 -2
  314. package/dist/wc/GridMenus-By9vPuq0.js +1088 -0
  315. package/dist/wc/SvChartMenu-CQNrQGT2.js +308 -0
  316. package/dist/wc/SvDateRangeInput-DR6m7bSM.js +199 -0
  317. package/dist/wc/SvDateTimePicker-D-vRnaMo.js +771 -0
  318. package/dist/wc/SvField-B_kurx_P.js +149 -0
  319. package/dist/wc/SvGrid.helpers-BdVDtjUm.js +135 -0
  320. package/dist/wc/SvGridCellEditor-Bnf1Kr5C.js +560 -0
  321. package/dist/wc/SvGridChart-BqUJh2pG.js +3572 -0
  322. package/dist/wc/SvGridChartBuilder-CGycC5cn.js +988 -0
  323. package/dist/wc/SvGridChartPanel-CRnizsHD.js +1746 -0
  324. package/dist/wc/SvGridChartView-D1pa_xMy.js +47 -0
  325. package/dist/wc/SvGridDropdown-45WsObLL.js +259 -0
  326. package/dist/wc/SvModal-DrfOYYyX.js +189 -0
  327. package/dist/wc/cell-formatting-CBfgahv1.js +86 -0
  328. package/dist/wc/chart-6OXlybVT.js +4341 -0
  329. package/dist/wc/chart-export-CeSADGfi.js +135 -0
  330. package/dist/wc/chart-export-pdf-BGko7MER.js +104 -0
  331. package/dist/wc/chart-summary-2m3ia1-n.js +137 -0
  332. package/dist/wc/chart-trend-CQOQtTMl.js +50 -0
  333. package/dist/wc/chart-validate-CD6ptiwg.js +180 -0
  334. package/dist/wc/client-DQIzjDBG.js +3064 -0
  335. package/dist/wc/column-resize-DUPgynvc.js +101 -0
  336. package/dist/wc/date-format-DS-z_h9v.js +1130 -0
  337. package/dist/wc/dismissable-CQ6XFXsk.js +45 -0
  338. package/dist/wc/editor-contract-peBDxir_.js +22 -0
  339. package/dist/wc/editor-registry-DxGKqcvx.js +24 -0
  340. package/dist/wc/focus-trap-Dbb2tJxb.js +65 -0
  341. package/dist/wc/list-option-DrRyivWp.js +82 -0
  342. package/dist/wc/popover-WsGlvtQv.js +69 -0
  343. package/dist/wc/positioning-BiKLfu1E.js +112 -0
  344. package/dist/wc/react.d.ts +41 -0
  345. package/dist/wc/react.js +90 -0
  346. package/dist/wc/rolldown-runtime-Dy4uBu1J.js +11 -0
  347. package/dist/wc/row-drag-touch-CycRR65n.js +93 -0
  348. package/dist/wc/row-resize-limG_N1z.js +111 -0
  349. package/dist/wc/sv-sheet-element.d.ts +97 -0
  350. package/dist/wc/sv-sheet-element.js +44213 -0
  351. package/dist/wc/svelte-virtualizer.svelte-CXtQy2TQ.js +530 -0
  352. package/dist/wc/validate-BqDthkNr.js +88 -0
  353. package/dist/wc/vue.d.ts +31 -0
  354. package/dist/wc/vue.js +75 -0
  355. package/package.json +30 -5
  356. package/dist/designer/assets/GridMenus-BlsvL_aU.js +0 -8
  357. package/dist/designer/assets/SvGridCellEditor-C7uQXYds.js +0 -4
  358. package/dist/designer/assets/SvGridChartBuilder-kvyIU_Rl.js +0 -1
  359. package/dist/designer/assets/SvGridDropdown-Bb3HH2Aj.js +0 -1
  360. package/dist/designer/assets/cell-formatting-wr5wm7US.js +0 -1
  361. package/dist/designer/assets/index-CMFgAoVV.css +0 -1
  362. package/dist/designer/assets/row-resize-DLktcqUK.js +0 -1
  363. package/dist/designer/assets/src-EdI3Xqds.js +0 -58
  364. package/dist/designer/assets/validate-h-aslRV9.js +0 -1
@@ -6,8 +6,11 @@
6
6
  * and calls back, so the keyboard shortcuts and the tabs cannot disagree
7
7
  * about which sheet is active.
8
8
  */
9
+ import { tick } from 'svelte'
10
+ import { SvModal } from '@svgrid/grid'
9
11
  import type { Workbook } from './sheet/workbook'
10
12
  import { isValidSheetName } from './sheet/workbook'
13
+ import { useSheetText } from './sheet-text'
11
14
 
12
15
  type Props = {
13
16
  workbook: Workbook
@@ -21,6 +24,25 @@
21
24
  */
22
25
  onRename?: (from: string, to: string) => void
23
26
  onRemove?: (name: string) => void
27
+ /**
28
+ * Called when a pointer action on the strip is over: a tab clicked, the
29
+ * add button, an entry of the tab menu, a delete confirmed. Each leaves
30
+ * the focus on a button or nowhere; a consumer whose cells should keep
31
+ * the keyboard, as a spreadsheet's do, puts it back from here. Not
32
+ * called for the arrow keys inside the strip, which keep the focus on
33
+ * the tab they moved to, nor after a rename ends, which goes to its tab.
34
+ */
35
+ onReturnFocus?: () => void
36
+ /**
37
+ * The sheets that are hidden: their tabs are not drawn and the menu
38
+ * offers Unhide for each. The consumer keeps the list (the shell keeps
39
+ * it in the document) and answers `onHide` / `onUnhide`.
40
+ */
41
+ hidden?: ReadonlyArray<string>
42
+ onHide?: (name: string) => void
43
+ onUnhide?: (name: string) => void
44
+ /** Excel's Move or Copy > Create a copy. Without it the entry is not offered. */
45
+ onDuplicate?: (name: string) => void
24
46
  /** Off hides the add button and the context actions. */
25
47
  editable?: boolean
26
48
  /**
@@ -35,7 +57,9 @@
35
57
  version?: number
36
58
  }
37
59
 
38
- let { workbook, onChange, onRename, onRemove, editable = true, version = 0 }: Props = $props()
60
+ let { workbook, onChange, onRename, onRemove, onReturnFocus, hidden = [], onHide, onUnhide, onDuplicate, editable = true, version = 0 }: Props = $props()
61
+
62
+ const t = useSheetText()
39
63
 
40
64
  let renaming = $state<string | null>(null)
41
65
  let draft = $state('')
@@ -46,10 +70,17 @@
46
70
  // keeps one of its own and reads both.
47
71
  let localVersion = $state(0)
48
72
 
73
+ const isHidden = (name: string) => hidden.some((h) => h.toLowerCase() === name.toLowerCase())
74
+ /** The tabs drawn: the workbook's sheets less the hidden ones. */
49
75
  const sheets = $derived.by(() => {
50
76
  void version
51
77
  void localVersion
52
- return workbook.sheets
78
+ return workbook.sheets.filter((name) => !isHidden(name))
79
+ })
80
+ const hiddenSheets = $derived.by(() => {
81
+ void version
82
+ void localVersion
83
+ return workbook.sheets.filter((name) => isHidden(name))
53
84
  })
54
85
  const activeSheet = $derived.by(() => {
55
86
  void version
@@ -67,11 +98,16 @@
67
98
  changed()
68
99
  }
69
100
 
101
+ let renameInput = $state<HTMLInputElement | null>(null)
70
102
  function startRename(name: string) {
71
103
  if (!editable) return
72
104
  renaming = name
73
105
  draft = name
74
106
  error = null
107
+ // Focused by hand rather than with `autofocus`, which only takes when
108
+ // nothing has the focus: the consumer may have just put it back on its
109
+ // cells after the click that preceded this double-click.
110
+ void tick().then(() => { renameInput?.focus(); renameInput?.select() })
75
111
  }
76
112
 
77
113
  function commitRename() {
@@ -81,11 +117,11 @@
81
117
  renaming = null
82
118
  if (to === '' || to === from) return
83
119
  if (!isValidSheetName(to)) {
84
- error = `"${to}" is not a valid sheet name`
120
+ error = t('invalidSheetName', { name: to })
85
121
  return
86
122
  }
87
123
  if (!workbook.renameSheet(from, to)) {
88
- error = `a sheet named "${to}" already exists`
124
+ error = t('duplicateSheetName', { name: to })
89
125
  return
90
126
  }
91
127
  error = null
@@ -93,12 +129,40 @@
93
129
  changed()
94
130
  }
95
131
 
132
+ function focusActiveTab() {
133
+ void tick().then(() => strip?.querySelector<HTMLElement>('[role="tab"][aria-selected="true"]')?.focus())
134
+ }
135
+
96
136
  function add() {
97
137
  workbook.addSheet()
98
138
  changed()
99
139
  }
100
140
 
141
+ /** Delete, once confirmed when the sheet holds anything, as Excel asks. */
142
+ let confirmDelete = $state<string | null>(null)
143
+
144
+ function hasContent(name: string): boolean {
145
+ for (let r = 0; r < workbook.rowCount(name); r += 1) {
146
+ for (let c = 0; c < workbook.colCount(name); c += 1) {
147
+ if (workbook.getRaw(name, r, c).trim() !== '') return true
148
+ }
149
+ }
150
+ return false
151
+ }
152
+
153
+ function askRemove(name: string) {
154
+ if (workbook.sheets.length < 2) return
155
+ if (hasContent(name)) confirmDelete = name
156
+ else remove(name)
157
+ }
158
+ /** The ribbon's Delete Sheet: the tab menu's Delete for the active sheet,
159
+ * with the same question first when the sheet holds anything. */
160
+ export function deleteSheet(name: string = workbook.active): void {
161
+ askRemove(name)
162
+ }
163
+
101
164
  function remove(name: string) {
165
+ confirmDelete = null
102
166
  // The workbook refuses to remove the last sheet; reflect that rather than
103
167
  // showing a button that does nothing.
104
168
  if (!workbook.removeSheet(name)) return
@@ -106,6 +170,23 @@
106
170
  changed()
107
171
  }
108
172
 
173
+ function hide(name: string) {
174
+ // Excel refuses to hide the last visible sheet.
175
+ if (sheets.length < 2) return
176
+ onHide?.(name)
177
+ changed()
178
+ }
179
+
180
+ function unhide(name: string) {
181
+ onUnhide?.(name)
182
+ changed()
183
+ }
184
+
185
+ function duplicate(name: string) {
186
+ onDuplicate?.(name)
187
+ changed()
188
+ }
189
+
109
190
  // ---- Excel's right-click menu on a tab ------------------------------------
110
191
  let menu = $state<{ name: string; x: number; y: number } | null>(null)
111
192
 
@@ -115,6 +196,13 @@
115
196
  select(name)
116
197
  menu = { name, x: event.clientX, y: event.clientY }
117
198
  }
199
+ /** An entry was taken: the menu goes, and the keyboard goes back to the
200
+ * consumer's cells, unless the entry opened something of its own (the
201
+ * rename input, the delete question), which hands it on itself. */
202
+ function closeMenu() {
203
+ menu = null
204
+ if (renaming === null && confirmDelete === null) onReturnFocus?.()
205
+ }
118
206
  /**
119
207
  * The tabs sit at the foot of the sheet, so a menu dropped from the click
120
208
  * runs off the bottom of the window; it opens upward from the click, as
@@ -186,21 +274,30 @@
186
274
  changed()
187
275
  }
188
276
 
189
- /** Left and right arrows move between tabs, which is what a tablist owes a
190
- * keyboard user; the shortcut layer's Ctrl+PageUp/Down does the same from
191
- * anywhere in the grid. */
277
+ /** The arrows move between tabs and Home and End reach the ends, which is
278
+ * what a tablist owes a keyboard user; the shortcut layer's
279
+ * Ctrl+PageUp/Down does the same from anywhere in the grid. Focus follows
280
+ * the selection, and the arrows are mirrored on a right-to-left strip. */
192
281
  function onTabKey(event: KeyboardEvent, name: string) {
193
- const at = sheets.indexOf(name)
194
- if (event.key === 'ArrowRight' && at < sheets.length - 1) {
195
- event.preventDefault()
196
- select(sheets[at + 1]!)
197
- } else if (event.key === 'ArrowLeft' && at > 0) {
198
- event.preventDefault()
199
- select(sheets[at - 1]!)
200
- } else if (event.key === 'F2') {
282
+ if (event.key === 'F2') {
201
283
  event.preventDefault()
202
284
  startRename(name)
285
+ return
203
286
  }
287
+ const at = sheets.indexOf(name)
288
+ const list = (event.currentTarget as HTMLElement).closest<HTMLElement>('[role="tablist"]')
289
+ const rtl = list ? getComputedStyle(list).direction === 'rtl' : false
290
+ const forward = rtl ? 'ArrowLeft' : 'ArrowRight'
291
+ const back = rtl ? 'ArrowRight' : 'ArrowLeft'
292
+ let next = -1
293
+ if (event.key === forward && at < sheets.length - 1) next = at + 1
294
+ else if (event.key === back && at > 0) next = at - 1
295
+ else if (event.key === 'Home') next = 0
296
+ else if (event.key === 'End') next = sheets.length - 1
297
+ if (next < 0 || next === at) return
298
+ event.preventDefault()
299
+ select(sheets[next]!)
300
+ void tick().then(() => list?.querySelector<HTMLElement>('[role="tab"][aria-selected="true"]')?.focus())
204
301
  }
205
302
  </script>
206
303
 
@@ -212,15 +309,15 @@
212
309
  <div class="sv-sheet-tabs">
213
310
  <!-- Excel's tab-scrolling arrows: always drawn, greyed until they can move something. -->
214
311
  <div class="nav">
215
- <button type="button" class="nav-btn" tabindex="-1" aria-label="Scroll tabs left" disabled={!canLeft} onclick={() => scrollTabs(-120)}>
312
+ <button type="button" class="nav-btn" tabindex="-1" aria-label={t('scrollTabsLeft')} disabled={!canLeft} onclick={() => scrollTabs(-120)}>
216
313
  <svg viewBox="0 0 8 8" width="8" height="8"><path d="M5.5 1L2.5 4l3 3" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" /></svg>
217
314
  </button>
218
- <button type="button" class="nav-btn" tabindex="-1" aria-label="Scroll tabs right" disabled={!canRight} onclick={() => scrollTabs(120)}>
315
+ <button type="button" class="nav-btn" tabindex="-1" aria-label={t('scrollTabsRight')} disabled={!canRight} onclick={() => scrollTabs(120)}>
219
316
  <svg viewBox="0 0 8 8" width="8" height="8"><path d="M2.5 1l3 3-3 3" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" /></svg>
220
317
  </button>
221
318
  </div>
222
319
 
223
- <div role="tablist" aria-label="Sheets" class="tabs" bind:this={strip}>
320
+ <div role="tablist" aria-label={t('sheets')} class="tabs" bind:this={strip}>
224
321
  {#each sheets as name (name)}
225
322
  {@const isActive = name === activeSheet}
226
323
  <!-- role="presentation" so the tablist still OWNS the role="tab"
@@ -239,17 +336,18 @@
239
336
  oncontextmenu={(e) => openMenu(e, name)}
240
337
  >
241
338
  {#if renaming === name}
242
- <!-- svelte-ignore a11y_autofocus -->
243
339
  <input
244
340
  class="rename"
245
- aria-label="Sheet name"
246
- autofocus
341
+ aria-label={t('sheetName')}
342
+ bind:this={renameInput}
247
343
  value={draft}
248
344
  oninput={(e) => (draft = e.currentTarget.value)}
249
345
  onblur={commitRename}
250
346
  onkeydown={(e) => {
251
- if (e.key === 'Enter') { e.preventDefault(); commitRename() }
252
- if (e.key === 'Escape') { e.preventDefault(); renaming = null }
347
+ // Enter and Escape hand the focus to the active tab, where a
348
+ // keyboard user came from; a click elsewhere keeps its own.
349
+ if (e.key === 'Enter') { e.preventDefault(); commitRename(); focusActiveTab() }
350
+ if (e.key === 'Escape') { e.preventDefault(); renaming = null; focusActiveTab() }
253
351
  }}
254
352
  />
255
353
  {:else}
@@ -258,7 +356,7 @@
258
356
  role="tab"
259
357
  aria-selected={isActive}
260
358
  tabindex={isActive ? 0 : -1}
261
- onclick={() => select(name)}
359
+ onclick={() => { select(name); onReturnFocus?.() }}
262
360
  ondblclick={() => startRename(name)}
263
361
  onkeydown={(e) => onTabKey(e, name)}
264
362
  >{name}</button>
@@ -268,7 +366,7 @@
268
366
  </div>
269
367
 
270
368
  {#if editable}
271
- <button type="button" class="add" aria-label="New sheet" title="New sheet (Shift+F11)" onclick={add}>
369
+ <button type="button" class="add" aria-label={t('newSheet')} title={`${t('newSheet')} (Shift+F11)`} onclick={() => { add(); onReturnFocus?.() }}>
272
370
  <svg viewBox="0 0 10 10" width="10" height="10" aria-hidden="true"><path d="M5 1.5v7M1.5 5h7" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" /></svg>
273
371
  </button>
274
372
  {/if}
@@ -284,15 +382,41 @@
284
382
  on the tab face, so a stray click cannot remove a sheet.
285
383
  -->
286
384
  <div class="sheet-menu" role="menu" aria-label={`${menu.name} sheet`} style:left={`${menu.x}px`} style:top={`${menu.y}px`} use:keepMenuInView={menu}>
287
- <button type="button" role="menuitem" onclick={() => { insertBefore(menu!.name); menu = null }}>Insert...</button>
288
- <button type="button" role="menuitem" disabled={sheets.length < 2} onclick={() => { remove(menu!.name); menu = null }}>Delete</button>
289
- <button type="button" role="menuitem" onclick={() => { startRename(menu!.name); menu = null }}>Rename</button>
385
+ <button type="button" role="menuitem" onclick={() => { insertBefore(menu!.name); closeMenu() }}>{t('tabInsert')}</button>
386
+ <button type="button" role="menuitem" disabled={workbook.sheets.length < 2} onclick={() => { askRemove(menu!.name); closeMenu() }}>{t('tabDelete')}</button>
387
+ <button type="button" role="menuitem" onclick={() => { startRename(menu!.name); menu = null }}>{t('tabRename')}</button>
388
+ {#if onDuplicate}
389
+ <button type="button" role="menuitem" onclick={() => { duplicate(menu!.name); closeMenu() }}>{t('tabDuplicate')}</button>
390
+ {/if}
290
391
  <div class="sep" role="separator"></div>
291
- <button type="button" role="menuitem" disabled={sheets.indexOf(menu.name) === 0} onclick={() => { moveBy(menu!.name, -1); menu = null }}>Move Left</button>
292
- <button type="button" role="menuitem" disabled={sheets.indexOf(menu.name) === sheets.length - 1} onclick={() => { moveBy(menu!.name, 1); menu = null }}>Move Right</button>
392
+ <button type="button" role="menuitem" disabled={sheets.indexOf(menu.name) === 0} onclick={() => { moveBy(menu!.name, -1); closeMenu() }}>{t('tabMoveLeft')}</button>
393
+ <button type="button" role="menuitem" disabled={sheets.indexOf(menu.name) === sheets.length - 1} onclick={() => { moveBy(menu!.name, 1); closeMenu() }}>{t('tabMoveRight')}</button>
394
+ {#if onHide}
395
+ <div class="sep" role="separator"></div>
396
+ <button type="button" role="menuitem" disabled={sheets.length < 2} onclick={() => { hide(menu!.name); closeMenu() }}>{t('tabHide')}</button>
397
+ {#if hiddenSheets.length}
398
+ <!-- Excel's Unhide opens a list; here each hidden sheet is an entry. -->
399
+ <div class="heading" role="presentation">{t('tabUnhide')}</div>
400
+ {#each hiddenSheets as name (name)}
401
+ <button type="button" role="menuitem" class="indent" onclick={() => { unhide(name); closeMenu() }}>{name}</button>
402
+ {/each}
403
+ {/if}
404
+ {/if}
293
405
  </div>
294
406
  {/if}
295
407
 
408
+ <SvModal open={confirmDelete !== null} title={t('deleteSheetTitle')} size="sm" onClose={() => (confirmDelete = null)}>
409
+ <div class="sv-sheet-dialog">
410
+ <p class="note">{t('deleteSheetMessage', { name: confirmDelete ?? '' })}</p>
411
+ </div>
412
+ {#snippet footer()}
413
+ <div class="sv-sheet-dialog-buttons">
414
+ <button type="button" class="btn primary" onclick={() => { if (confirmDelete) remove(confirmDelete); onReturnFocus?.() }}>{t('delete')}</button>
415
+ <button type="button" class="btn" onclick={() => { confirmDelete = null; onReturnFocus?.() }}>{t('cancel')}</button>
416
+ </div>
417
+ {/snippet}
418
+ </SvModal>
419
+
296
420
  <style>
297
421
  .sv-sheet-tabs {
298
422
  display: flex;
@@ -351,7 +475,10 @@
351
475
  box-shadow: inset 0 -2px 0 0 var(--sg-accent, #107c41);
352
476
  }
353
477
  .tab.active button {
354
- color: var(--sg-accent, #107c41);
478
+ /* Mixed toward the text colour: the raw accent under 4.5:1 on the
479
+ lifted white tab is what axe finds and a low-vision reader feels.
480
+ The line along the bottom edge above keeps the accent pure. */
481
+ color: color-mix(in srgb, var(--sg-accent, #107c41) 72%, var(--sg-fg, #242424));
355
482
  font-weight: 600;
356
483
  }
357
484
  .tab:not(.active):hover { background: var(--sg-row-hover-bg, #e9e9e9); }
@@ -438,4 +565,7 @@
438
565
  .sheet-menu button:hover:not(:disabled) { background: var(--sg-row-hover-bg, #f0f0f0); }
439
566
  .sheet-menu button:disabled { opacity: 0.4; cursor: default; }
440
567
  .sheet-menu .sep { height: 1px; margin: 4px 6px; background: var(--sg-border, #e0e0e0); }
568
+ .sheet-menu .heading { padding: 4px 10px 2px; color: var(--sg-muted, #616161); font-size: 11px; }
569
+ .sheet-menu button.indent { padding-left: 22px; }
570
+ .note { margin: 0; }
441
571
  </style>
@@ -1,10 +1,3 @@
1
- /**
2
- * The sheet tab strip along the bottom of a workbook.
3
- *
4
- * Owns no workbook state of its own: it renders what the workbook reports
5
- * and calls back, so the keyboard shortcuts and the tabs cannot disagree
6
- * about which sheet is active.
7
- */
8
1
  import type { Workbook } from './sheet/workbook.js';
9
2
  type Props = {
10
3
  workbook: Workbook;
@@ -18,6 +11,25 @@ type Props = {
18
11
  */
19
12
  onRename?: (from: string, to: string) => void;
20
13
  onRemove?: (name: string) => void;
14
+ /**
15
+ * Called when a pointer action on the strip is over: a tab clicked, the
16
+ * add button, an entry of the tab menu, a delete confirmed. Each leaves
17
+ * the focus on a button or nowhere; a consumer whose cells should keep
18
+ * the keyboard, as a spreadsheet's do, puts it back from here. Not
19
+ * called for the arrow keys inside the strip, which keep the focus on
20
+ * the tab they moved to, nor after a rename ends, which goes to its tab.
21
+ */
22
+ onReturnFocus?: () => void;
23
+ /**
24
+ * The sheets that are hidden: their tabs are not drawn and the menu
25
+ * offers Unhide for each. The consumer keeps the list (the shell keeps
26
+ * it in the document) and answers `onHide` / `onUnhide`.
27
+ */
28
+ hidden?: ReadonlyArray<string>;
29
+ onHide?: (name: string) => void;
30
+ onUnhide?: (name: string) => void;
31
+ /** Excel's Move or Copy > Create a copy. Without it the entry is not offered. */
32
+ onDuplicate?: (name: string) => void;
21
33
  /** Off hides the add button and the context actions. */
22
34
  editable?: boolean;
23
35
  /**
@@ -31,6 +43,8 @@ type Props = {
31
43
  */
32
44
  version?: number;
33
45
  };
34
- declare const SvSheetTabs: import("svelte").Component<Props, {}, "">;
46
+ declare const SvSheetTabs: import("svelte").Component<Props, {
47
+ deleteSheet: (name?: string) => void;
48
+ }, "">;
35
49
  type SvSheetTabs = ReturnType<typeof SvSheetTabs>;
36
50
  export default SvSheetTabs;
@@ -5,6 +5,7 @@
5
5
  * Finish writes the fields into the columns to the right of the source
6
6
  * inside one batch, so the whole split is one Ctrl+Z.
7
7
  */
8
+ import { useSheetText } from './sheet-text'
8
9
  import { untrack } from 'svelte'
9
10
  import { SvModal } from '@svgrid/grid'
10
11
  import type { GridCommandContext } from '@svgrid/grid/shortcuts'
@@ -22,13 +23,14 @@
22
23
  }
23
24
 
24
25
  let { open = $bindable(false), workbook, cmd, onDone, onClose }: Props = $props()
26
+ const t = useSheetText()
25
27
 
26
28
  const DELIMITERS = [
27
- { id: 'tab', label: 'Tab', sep: '\t' },
28
- { id: 'semicolon', label: 'Semicolon', sep: ';' },
29
- { id: 'comma', label: 'Comma', sep: ',' },
30
- { id: 'space', label: 'Space', sep: ' ' },
31
- { id: 'other', label: 'Other', sep: '' },
29
+ { id: 'tab', label: 'textToColumns.tab', sep: '\t' },
30
+ { id: 'semicolon', label: 'textToColumns.semicolon', sep: ';' },
31
+ { id: 'comma', label: 'textToColumns.comma', sep: ',' },
32
+ { id: 'space', label: 'textToColumns.space', sep: ' ' },
33
+ { id: 'other', label: 'textToColumns.other', sep: '' },
32
34
  ] as const
33
35
  type DelimiterId = (typeof DELIMITERS)[number]['id']
34
36
 
@@ -90,7 +92,7 @@
90
92
  open = false
91
93
  c.setSelection(column.top, column.index)
92
94
  c.extendSelection(column.top + rows.length - 1, column.index + width - 1)
93
- onDone(`Split ${rows.length} rows into ${width} columns.`)
95
+ onDone(t('textToColumns.done', { rows: rows.length, columns: width }))
94
96
  onClose?.()
95
97
  }
96
98
 
@@ -100,26 +102,26 @@
100
102
  }
101
103
  </script>
102
104
 
103
- <SvModal bind:open onClose={onClose} title="Convert Text to Columns Wizard" size="md">
104
- <div class="sv-sheet-dialog" role="group" aria-label="Convert Text to Columns">
105
- <p class="lead">Choose the delimiter your data contains. The preview shows how it splits.</p>
105
+ <SvModal bind:open onClose={onClose} title={t('textToColumns.title')} size="md">
106
+ <div class="sv-sheet-dialog" role="group" aria-label={t('textToColumns.group')}>
107
+ <p class="lead">{t('textToColumns.lead')}</p>
106
108
  <fieldset class="group">
107
- <legend>Delimiters</legend>
109
+ <legend>{t('textToColumns.delimiters')}</legend>
108
110
  {#each DELIMITERS as d (d.id)}
109
111
  <label class="check">
110
112
  <input type="radio" name="sheet-delimiter" value={d.id} bind:group={delimiter} />
111
- {d.label}
113
+ {t(d.label)}
112
114
  {#if d.id === 'other'}
113
- <input class="other" type="text" maxlength="1" bind:value={other} aria-label="Other delimiter" />
115
+ <input class="other" type="text" maxlength="1" bind:value={other} aria-label={t('textToColumns.otherDelimiter')} />
114
116
  {/if}
115
117
  </label>
116
118
  {/each}
117
119
  </fieldset>
118
120
  <div class="checks">
119
- <label class="check"><input type="checkbox" bind:checked={collapse} /> Treat consecutive delimiters as one</label>
120
- <label class="check"><input type="checkbox" bind:checked={trim} /> Trim spaces around each field</label>
121
+ <label class="check"><input type="checkbox" bind:checked={collapse} /> {t('textToColumns.collapse')}</label>
122
+ <label class="check"><input type="checkbox" bind:checked={trim} /> {t('textToColumns.trim')}</label>
121
123
  </div>
122
- <div class="preview" aria-label="Data preview">
124
+ <div class="preview" aria-label={t('textToColumns.preview')}>
123
125
  <table>
124
126
  <tbody>
125
127
  {#each preview.rows as fields, i (i)}
@@ -129,15 +131,13 @@
129
131
  </table>
130
132
  </div>
131
133
  <p class="status">
132
- {column.texts.length} rows in column {colToLetters(column.index)}
133
- become {preview.width} column{preview.width === 1 ? '' : 's'} from column {colToLetters(column.index)}.
134
- Anything already in those columns is replaced.
134
+ {t('textToColumns.status', { rows: column.texts.length, from: colToLetters(column.index), count: preview.width, unit: t(preview.width === 1 ? 'textToColumns.column' : 'textToColumns.columns') })}
135
135
  </p>
136
136
  </div>
137
137
  {#snippet footer()}
138
138
  <div class="sv-sheet-dialog-buttons">
139
- <button type="button" class="btn primary" onclick={finish} disabled={column.texts.length === 0}>Finish</button>
140
- <button type="button" class="btn" onclick={close}>Cancel</button>
139
+ <button type="button" class="btn primary" onclick={finish} disabled={column.texts.length === 0}>{t('textToColumns.finish')}</button>
140
+ <button type="button" class="btn" onclick={close}>{t('cancel')}</button>
141
141
  </div>
142
142
  {/snippet}
143
143
  </SvModal>
@@ -5,6 +5,7 @@
5
5
  * the message, "Continue?", Yes (the entry lands anyway), No (retry) and
6
6
  * Cancel. Enter takes the first button, Escape cancels.
7
7
  */
8
+ import { useSheetText } from './sheet-text'
8
9
  import { SvModal } from '@svgrid/grid'
9
10
 
10
11
  type Props = {
@@ -17,6 +18,7 @@
17
18
  }
18
19
 
19
20
  let { open = $bindable(false), alert, onRetry, onAccept, onCancel }: Props = $props()
21
+ const t = useSheetText()
20
22
  let first = $state<HTMLButtonElement | null>(null)
21
23
 
22
24
  $effect(() => {
@@ -30,23 +32,23 @@
30
32
  }
31
33
  </script>
32
34
 
33
- <SvModal bind:open onClose={onCancel} title={alert?.title ?? 'Data validation'} size="sm">
35
+ <SvModal bind:open onClose={onCancel} title={alert?.title ?? t('dataValidationTitle')} size="sm">
34
36
  <div class="sv-sheet-dialog alert" role="alertdialog" aria-describedby="sv-sheet-validation-message">
35
37
  <span class="mark" class:warning={alert?.style === 'warning'} aria-hidden="true">{alert?.style === 'warning' ? '!' : '×'}</span>
36
38
  <div>
37
39
  <p id="sv-sheet-validation-message" class="message">{alert?.message}</p>
38
- {#if alert?.style === 'warning'}<p class="message">Continue?</p>{/if}
40
+ {#if alert?.style === 'warning'}<p class="message">{t('validationContinue')}</p>{/if}
39
41
  </div>
40
42
  </div>
41
43
  {#snippet footer()}
42
44
  <div class="sv-sheet-dialog-buttons">
43
45
  {#if alert?.style === 'warning'}
44
- <button bind:this={first} type="button" class="btn primary" onclick={() => done(onAccept)}>Yes</button>
45
- <button type="button" class="btn" onclick={() => done(onRetry)}>No</button>
46
+ <button bind:this={first} type="button" class="btn primary" onclick={() => done(onAccept)}>{t('yes')}</button>
47
+ <button type="button" class="btn" onclick={() => done(onRetry)}>{t('no')}</button>
46
48
  {:else}
47
- <button bind:this={first} type="button" class="btn primary" onclick={() => done(onRetry)}>Retry</button>
49
+ <button bind:this={first} type="button" class="btn primary" onclick={() => done(onRetry)}>{t('retry')}</button>
48
50
  {/if}
49
- <button type="button" class="btn" onclick={() => done(onCancel)}>Cancel</button>
51
+ <button type="button" class="btn" onclick={() => done(onCancel)}>{t('cancel')}</button>
50
52
  </div>
51
53
  {/snippet}
52
54
  </SvModal>
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Advanced Filter (Pro): register the expression compiler with the grid.
3
3
  *
4
- * Same shape as `pivot-enable.ts` - idempotent flag, register, soft-gate nudge.
4
+ * Same shape as `pivot-enable.ts` - idempotent flag, register, unlicensed nudge.
5
5
  * The grid owns the filter state and the pipeline slot; this supplies the
6
6
  * compiler that turns an expression into a row predicate.
7
7
  */
@@ -19,6 +19,12 @@ export type AlertEngine<TData> = {
19
19
  evaluate(rows: ReadonlyArray<TData>): AlertEvent[];
20
20
  /** Prev -> next pass: fires `relativeChange` plus `dataChange` edges. */
21
21
  evaluateTransition(prev: ReadonlyArray<TData>, next: ReadonlyArray<TData>): AlertEvent[];
22
+ /**
23
+ * Scheduled pass for one rule: every row matching its predicate now, with
24
+ * no edge memory, since the point of a schedule is the standing list at
25
+ * that moment. Aggregate rules answer with one event or none.
26
+ */
27
+ evaluateScheduled(ruleId: string, rows: ReadonlyArray<TData>): AlertEvent[];
22
28
  /** Would editing `(row, columnId) -> nextValue` trip a validation rule? */
23
29
  validateEdit(row: TData, columnId: string, nextValue: unknown): ValidateEditResult;
24
30
  /**
@@ -26,21 +26,23 @@ function defaultMessage(rule) {
26
26
  }
27
27
  export function createAlertEngine(options) {
28
28
  let rules = options.rules;
29
- const getValue = options.getValue;
30
29
  const now = options.now ?? (() => Date.now());
31
30
  // Edge memory: keys currently satisfying a `dataChange`/aggregate predicate.
32
31
  const active = new Set();
32
+ // Read off `options` at use, not once here: the overlay hands in getters
33
+ // for its `getValue` and `locale` props so a change after mount reaches
34
+ // the next evaluation.
33
35
  const ctxFor = (row, rows, prev) => ({
34
36
  row,
35
37
  prev,
36
38
  rows,
37
- getValue,
39
+ getValue: options.getValue,
38
40
  locale: options.locale,
39
41
  });
40
42
  const val = (row, columnId) => columnId == null
41
43
  ? undefined
42
- : getValue
43
- ? getValue(row, columnId)
44
+ : options.getValue
45
+ ? options.getValue(row, columnId)
44
46
  : row?.[columnId];
45
47
  // A representative column for the message `{value}`/`{column}` tokens: the
46
48
  // rule's explicit target, else the first column its predicate references.
@@ -172,6 +174,21 @@ export function createAlertEngine(options) {
172
174
  }
173
175
  return events;
174
176
  },
177
+ evaluateScheduled(ruleId, rows) {
178
+ const rule = activeRules().find((r) => r.id === ruleId);
179
+ if (!rule)
180
+ return [];
181
+ if (rule.scope === 'aggregate')
182
+ return evaluateAggregate(rule, rows);
183
+ const events = [];
184
+ for (const row of rows) {
185
+ if (!evaluatePredicate(rule.predicate, ctxFor(row, rows)))
186
+ continue;
187
+ const source = primaryColumn(rule);
188
+ events.push(buildEvent(rule, { row, rowId: options.getRowId(row), columnId: rule.scope === 'cell' ? source : undefined, value: val(row, source) }));
189
+ }
190
+ return events;
191
+ },
175
192
  validateEdit(row, columnId, nextValue) {
176
193
  const candidate = { ...row, [columnId]: nextValue };
177
194
  const events = [];
@@ -24,6 +24,7 @@ export function rulesToConditionalFormats(rules, ctx = {}) {
24
24
  when: ({ row }) => evaluatePredicate(rule.predicate, { row, getValue: ctx.getValue, locale: ctx.locale }),
25
25
  ...(style.background ? { background: style.background } : {}),
26
26
  ...(style.color ? { color: style.color } : {}),
27
+ ...(style.icon ? { icon: style.icon } : {}),
27
28
  });
28
29
  }
29
30
  }
@@ -51,6 +52,7 @@ export function toConditionalFormats(events, getRowId) {
51
52
  when: ({ row }) => getRowId(row) === rowId,
52
53
  ...(style.background ? { background: style.background } : {}),
53
54
  ...(style.color ? { color: style.color } : {}),
55
+ ...(style.icon ? { icon: style.icon } : {}),
54
56
  });
55
57
  }
56
58
  }
@@ -40,7 +40,7 @@ export type AlertActionKind = 'toast' | 'badge' | 'cellFlash' | 'highlight' | 'p
40
40
  export type AlertActionStyle = {
41
41
  background?: string;
42
42
  color?: string;
43
- /** A short glyph/emoji shown as a badge. */
43
+ /** A short glyph/emoji drawn before the cell value while the rule matches. */
44
44
  icon?: string;
45
45
  };
46
46
  export type AlertAction = {
package/dist/alerts.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- /** Turn on the alerts feature (soft-gated). Idempotent. */
1
+ /** Turn on the alerts feature (runs without a key, with the watermark and the console notice). Idempotent. */
2
2
  export declare function enableAlerts(): void;
package/dist/alerts.js CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Unlike the scheduler/board *views*, alerts are an overlay the consumer mounts
5
5
  * next to the grid (`<SvGridAlerts>`), so there is no renderer to register with
6
- * the grid. `enableAlerts()` exists only to keep the Pro soft-gate consistent
6
+ * the grid. `enableAlerts()` exists only to keep the evaluation behaviour consistent
7
7
  * with the rest of Enterprise: it works without a license key but nudges once in
8
8
  * the console when unlicensed.
9
9
  *
@@ -18,7 +18,7 @@
18
18
  import { isLicenseKeySet } from './license.js';
19
19
  import { emitUnlicensedNudge } from './watermark.js';
20
20
  let enabled = false;
21
- /** Turn on the alerts feature (soft-gated). Idempotent. */
21
+ /** Turn on the alerts feature (runs without a key, with the watermark and the console notice). Idempotent. */
22
22
  export function enableAlerts() {
23
23
  if (enabled)
24
24
  return;