@svgrid/enterprise 3.0.0 → 3.0.2

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 (390) hide show
  1. package/README.md +95 -95
  2. package/dist/ExpressionEditorHarness.svelte.d.ts +2 -2
  3. package/dist/SvAdvancedFilter.svelte.d.ts +2 -2
  4. package/dist/SvAlertRuleEditor.svelte.d.ts +2 -2
  5. package/dist/SvAlertsManager.svelte.d.ts +3 -3
  6. package/dist/SvAlertsPanel.svelte.d.ts +1 -1
  7. package/dist/SvAuthGate.svelte +115 -115
  8. package/dist/SvAuthGate.svelte.d.ts +1 -1
  9. package/dist/SvBoard.svelte.d.ts +1 -1
  10. package/dist/SvExportMenu.svelte +553 -553
  11. package/dist/SvExportMenu.svelte.d.ts +2 -2
  12. package/dist/SvExpressionEditor.svelte.d.ts +2 -2
  13. package/dist/SvFileInput.svelte +113 -113
  14. package/dist/SvFormulaBar.svelte +606 -0
  15. package/dist/SvFormulaBar.svelte.d.ts +62 -0
  16. package/dist/SvGridAlerts.svelte.d.ts +2 -2
  17. package/dist/SvGridBoard.svelte +2358 -2358
  18. package/dist/SvGridBulkEditDrawer.svelte.d.ts +1 -1
  19. package/dist/SvGridEditPanel.svelte +1157 -1157
  20. package/dist/SvGridEditPanel.svelte.d.ts +3 -3
  21. package/dist/SvGridMasterDetail.svelte +116 -116
  22. package/dist/SvGridMasterDetail.svelte.d.ts +1 -1
  23. package/dist/SvGridScheduler.svelte +5358 -5358
  24. package/dist/SvImportDialog.svelte +1020 -1020
  25. package/dist/SvImportDialog.svelte.d.ts +2 -2
  26. package/dist/SvLookupInput.svelte +180 -180
  27. package/dist/SvLookupInput.svelte.d.ts +1 -1
  28. package/dist/SvPivotDesigner.svelte +2041 -1990
  29. package/dist/SvPivotDesigner.svelte.d.ts +2 -2
  30. package/dist/SvRecordDetail.svelte.d.ts +1 -1
  31. package/dist/SvRibbonIcon.svelte +46 -0
  32. package/dist/SvRibbonIcon.svelte.d.ts +17 -0
  33. package/dist/SvSchedule.svelte.d.ts +1 -1
  34. package/dist/SvSchemaChart.svelte +236 -234
  35. package/dist/SvSchemaChart.svelte.d.ts +2 -2
  36. package/dist/SvSchemaDashboard.svelte +130 -130
  37. package/dist/SvSchemaDashboard.svelte.d.ts +3 -3
  38. package/dist/SvSheet.svelte +4114 -0
  39. package/dist/SvSheet.svelte.d.ts +142 -0
  40. package/dist/SvSheetComment.svelte +98 -0
  41. package/dist/SvSheetComment.svelte.d.ts +22 -0
  42. package/dist/SvSheetConditionalFormat.svelte +162 -0
  43. package/dist/SvSheetConditionalFormat.svelte.d.ts +14 -0
  44. package/dist/SvSheetDataValidation.svelte +249 -0
  45. package/dist/SvSheetDataValidation.svelte.d.ts +14 -0
  46. package/dist/SvSheetFilterMenu.svelte +217 -0
  47. package/dist/SvSheetFilterMenu.svelte.d.ts +17 -0
  48. package/dist/SvSheetFindReplace.svelte +132 -0
  49. package/dist/SvSheetFindReplace.svelte.d.ts +10 -0
  50. package/dist/SvSheetFormatCells.svelte +421 -0
  51. package/dist/SvSheetFormatCells.svelte.d.ts +17 -0
  52. package/dist/SvSheetGoalSeek.svelte +144 -0
  53. package/dist/SvSheetGoalSeek.svelte.d.ts +12 -0
  54. package/dist/SvSheetInsertFunction.svelte +147 -0
  55. package/dist/SvSheetInsertFunction.svelte.d.ts +8 -0
  56. package/dist/SvSheetListPicker.svelte +89 -0
  57. package/dist/SvSheetListPicker.svelte.d.ts +16 -0
  58. package/dist/SvSheetManageRules.svelte +185 -0
  59. package/dist/SvSheetManageRules.svelte.d.ts +16 -0
  60. package/dist/SvSheetNameManager.svelte +225 -0
  61. package/dist/SvSheetNameManager.svelte.d.ts +11 -0
  62. package/dist/SvSheetPasteSpecial.svelte +105 -0
  63. package/dist/SvSheetPasteSpecial.svelte.d.ts +12 -0
  64. package/dist/SvSheetRemoveDuplicates.svelte +149 -0
  65. package/dist/SvSheetRemoveDuplicates.svelte.d.ts +12 -0
  66. package/dist/SvSheetRibbon.svelte +1201 -0
  67. package/dist/SvSheetRibbon.svelte.d.ts +34 -0
  68. package/dist/SvSheetSizeDialog.svelte +58 -0
  69. package/dist/SvSheetSizeDialog.svelte.d.ts +11 -0
  70. package/dist/SvSheetTabs.svelte +441 -0
  71. package/dist/SvSheetTabs.svelte.d.ts +36 -0
  72. package/dist/SvSheetTabs.test-harness.svelte.d.ts +17 -0
  73. package/dist/SvSheetTabs.test-harness.svelte.js +22 -0
  74. package/dist/SvSheetTextToColumns.svelte +172 -0
  75. package/dist/SvSheetTextToColumns.svelte.d.ts +13 -0
  76. package/dist/SvSheetValidationAlert.svelte +83 -0
  77. package/dist/SvSheetValidationAlert.svelte.d.ts +15 -0
  78. package/dist/advanced-filter/expr-columns-from-grid.d.ts +1 -1
  79. package/dist/advanced-filter-enable.js +3 -3
  80. package/dist/alerts/alert-engine-attach.d.ts +2 -2
  81. package/dist/alerts/alert-engine-attach.js +3 -3
  82. package/dist/alerts/alert-engine.d.ts +1 -1
  83. package/dist/alerts/alert-engine.js +2 -2
  84. package/dist/alerts/alert-formats.d.ts +1 -1
  85. package/dist/alerts/alert-formats.js +1 -1
  86. package/dist/alerts/alert-observer.d.ts +3 -3
  87. package/dist/alerts/alert-observer.js +1 -1
  88. package/dist/alerts/alert-storage.d.ts +1 -1
  89. package/dist/alerts/alert-store.svelte.d.ts +1 -1
  90. package/dist/alerts/alert-types.d.ts +2 -2
  91. package/dist/alerts.js +2 -2
  92. package/dist/board.js +2 -2
  93. package/dist/cdn/svgrid-enterprise.svelte-external.js +19046 -5428
  94. package/dist/designer/assets/GridMenus-BlsvL_aU.js +8 -0
  95. package/dist/designer/assets/SvChartMenu-BYO9cYdy.css +1 -0
  96. package/dist/designer/assets/SvChartMenu-D9hEeHar.js +1 -0
  97. package/dist/designer/assets/SvDateRangeInput-BBRzrQeg.js +1 -0
  98. package/dist/designer/assets/SvDateRangeInput-C0iCCZ8o.css +1 -0
  99. package/dist/designer/assets/SvDateTimePicker-DARvKUL2.js +1 -0
  100. package/dist/designer/assets/SvDateTimePicker-DPv09DIT.css +1 -0
  101. package/dist/designer/assets/{preload-helper-CG0n22O7.js → SvGrid.helpers-BgT-gnCo.js} +1 -1
  102. package/dist/designer/assets/SvGridCellEditor-C7uQXYds.js +4 -0
  103. package/dist/designer/assets/SvGridChart-B8j1SSy3.js +3 -0
  104. package/dist/designer/assets/SvGridChart-BgLuPO7I.css +1 -0
  105. package/dist/designer/assets/SvGridChartBuilder-08YWWeqY.css +1 -0
  106. package/dist/designer/assets/SvGridChartBuilder-kvyIU_Rl.js +1 -0
  107. package/dist/designer/assets/SvGridChartPanel-4Pc8y5yO.css +1 -0
  108. package/dist/designer/assets/SvGridChartPanel-pT6ITc2P.js +4 -0
  109. package/dist/designer/assets/SvGridChartView-7msfnWZT.css +1 -0
  110. package/dist/designer/assets/SvGridChartView-bg281UA1.js +1 -0
  111. package/dist/designer/assets/SvGridDropdown-Bb3HH2Aj.js +1 -0
  112. package/dist/designer/assets/SvGridDropdown-CcidB3rm.css +1 -0
  113. package/dist/designer/assets/SvListBox-BDS66lmZ.js +110 -0
  114. package/dist/designer/assets/SvListBox-BXfyqy4a.css +1 -0
  115. package/dist/designer/assets/SvMenuList-DJ47ba1h.css +1 -0
  116. package/dist/designer/assets/SvMenuList-Dgq2D5VN.js +1 -0
  117. package/dist/designer/assets/SvTabs-DKmwb5p1.css +1 -0
  118. package/dist/designer/assets/SvTabs-UFCMTHXS.js +1 -0
  119. package/dist/designer/assets/cell-formatting-wr5wm7US.js +1 -0
  120. package/dist/designer/assets/chart-cIPUsbM5.js +1 -0
  121. package/dist/designer/assets/chart-export-B6bkQ3X8.js +11 -0
  122. package/dist/designer/assets/chart-export-pdf-BbA28-gt.js +11 -0
  123. package/dist/designer/assets/chart-panel-messages-DtTxpBUU.js +1 -0
  124. package/dist/designer/assets/chart-summary-Czu_5epb.js +1 -0
  125. package/dist/designer/assets/chart-trend-D5I5VEe8.js +1 -0
  126. package/dist/designer/assets/chart-validate-BMqM-qkF.js +1 -0
  127. package/dist/designer/assets/column-resize-BYDzR1Ve.js +1 -0
  128. package/dist/designer/assets/date-format-B8JbEtIG.js +1 -0
  129. package/dist/designer/assets/date-format-DKS-z0xS.css +1 -0
  130. package/dist/designer/assets/editor-contract-Bpoa7A5g.js +1 -0
  131. package/dist/designer/assets/export-format-D-eP4b2l.js +6 -0
  132. package/dist/designer/assets/focus-trap-CAreAhlU.js +1 -0
  133. package/dist/designer/assets/index-CMFgAoVV.css +1 -0
  134. package/dist/designer/assets/{index-zUBix-JQ.js → index-DwU7CAMm.js} +2985 -141
  135. package/dist/designer/assets/list-option-BP_dWS66.js +1 -0
  136. package/dist/designer/assets/preload-helper-HclGiUj8.js +1 -0
  137. package/dist/designer/assets/row-resize-DLktcqUK.js +1 -0
  138. package/dist/designer/assets/src-CITpcm6b.js +1 -0
  139. package/dist/designer/assets/src-EdI3Xqds.js +58 -0
  140. package/dist/designer/index.html +32 -23
  141. package/dist/export-conditional.d.ts +1 -1
  142. package/dist/export-pdf.d.ts +89 -0
  143. package/dist/export-pdf.js +130 -0
  144. package/dist/export-print.js +19 -19
  145. package/dist/export-xls.d.ts +2 -2
  146. package/dist/export.d.ts +2 -2
  147. package/dist/export.js +23 -16
  148. package/dist/expressions/builder-tree.d.ts +2 -2
  149. package/dist/expressions/builder-tree.js +1 -1
  150. package/dist/expressions/compile.d.ts +1 -1
  151. package/dist/import.js +1 -1
  152. package/dist/index.d.ts +116 -53
  153. package/dist/index.js +117 -50
  154. package/dist/install.d.ts +4 -4
  155. package/dist/install.js +16 -11
  156. package/dist/license.d.ts +3 -2
  157. package/dist/license.js +9 -4
  158. package/dist/node/studio.js +187 -116
  159. package/dist/pivot-chart.d.ts +26 -2
  160. package/dist/pivot-chart.js +25 -69
  161. package/dist/pivot-designer.d.ts +1 -1
  162. package/dist/pivot-enable.js +3 -3
  163. package/dist/print.d.ts +1 -1
  164. package/dist/print.js +4 -4
  165. package/dist/scheduler-config.d.ts +5 -5
  166. package/dist/scheduler-freebusy.d.ts +1 -1
  167. package/dist/scheduler-freebusy.js +1 -1
  168. package/dist/scheduler.js +2 -2
  169. package/dist/schema-designer.d.ts +1 -1
  170. package/dist/schema-designer.js +2 -2
  171. package/dist/selection-bar.js +2 -2
  172. package/dist/sheet/address.d.ts +43 -0
  173. package/dist/sheet/address.js +81 -0
  174. package/dist/sheet/ast.d.ts +94 -0
  175. package/dist/sheet/ast.js +56 -0
  176. package/dist/sheet/auto-filter.d.ts +66 -0
  177. package/dist/sheet/auto-filter.js +147 -0
  178. package/dist/sheet/autocomplete.d.ts +42 -0
  179. package/dist/sheet/autocomplete.js +162 -0
  180. package/dist/sheet/coerce.d.ts +31 -0
  181. package/dist/sheet/coerce.js +122 -0
  182. package/dist/sheet/commands.d.ts +89 -0
  183. package/dist/sheet/commands.js +230 -0
  184. package/dist/sheet/comments.d.ts +29 -0
  185. package/dist/sheet/comments.js +73 -0
  186. package/dist/sheet/conditional-formats.d.ts +144 -0
  187. package/dist/sheet/conditional-formats.js +316 -0
  188. package/dist/sheet/deps.d.ts +60 -0
  189. package/dist/sheet/deps.js +199 -0
  190. package/dist/sheet/document.d.ts +150 -0
  191. package/dist/sheet/document.js +264 -0
  192. package/dist/sheet/edit-keys.d.ts +14 -0
  193. package/dist/sheet/edit-keys.js +40 -0
  194. package/dist/sheet/entry.d.ts +31 -0
  195. package/dist/sheet/entry.js +76 -0
  196. package/dist/sheet/evaluate.d.ts +61 -0
  197. package/dist/sheet/evaluate.js +337 -0
  198. package/dist/sheet/find-replace.d.ts +62 -0
  199. package/dist/sheet/find-replace.js +152 -0
  200. package/dist/sheet/format-store.d.ts +99 -0
  201. package/dist/sheet/format-store.js +233 -0
  202. package/dist/sheet/freeze.d.ts +54 -0
  203. package/dist/sheet/freeze.js +58 -0
  204. package/dist/sheet/function-catalog.d.ts +10 -0
  205. package/dist/sheet/function-catalog.js +94 -0
  206. package/dist/sheet/functions.d.ts +28 -0
  207. package/dist/sheet/functions.js +362 -0
  208. package/dist/sheet/goal-seek.d.ts +73 -0
  209. package/dist/sheet/goal-seek.js +153 -0
  210. package/dist/sheet/index.d.ts +53 -0
  211. package/dist/sheet/index.js +53 -0
  212. package/dist/sheet/merges.d.ts +71 -0
  213. package/dist/sheet/merges.js +137 -0
  214. package/dist/sheet/names.d.ts +31 -0
  215. package/dist/sheet/names.js +87 -0
  216. package/dist/sheet/navigate.d.ts +52 -0
  217. package/dist/sheet/navigate.js +135 -0
  218. package/dist/sheet/number-format.d.ts +63 -0
  219. package/dist/sheet/number-format.js +508 -0
  220. package/dist/sheet/palette.d.ts +19 -0
  221. package/dist/sheet/palette.js +84 -0
  222. package/dist/sheet/parse.d.ts +13 -0
  223. package/dist/sheet/parse.js +108 -0
  224. package/dist/sheet/paste-special.d.ts +164 -0
  225. package/dist/sheet/paste-special.js +592 -0
  226. package/dist/sheet/protection.d.ts +21 -0
  227. package/dist/sheet/protection.js +48 -0
  228. package/dist/sheet/rects.d.ts +45 -0
  229. package/dist/sheet/rects.js +112 -0
  230. package/dist/sheet/refs.d.ts +82 -0
  231. package/dist/sheet/refs.js +266 -0
  232. package/dist/sheet/ribbon-icons.d.ts +31 -0
  233. package/dist/sheet/ribbon-icons.js +350 -0
  234. package/dist/sheet/ribbon.d.ts +173 -0
  235. package/dist/sheet/ribbon.js +753 -0
  236. package/dist/sheet/shortcuts.d.ts +164 -0
  237. package/dist/sheet/shortcuts.js +623 -0
  238. package/dist/sheet/structure.d.ts +87 -0
  239. package/dist/sheet/structure.js +166 -0
  240. package/dist/sheet/tables.d.ts +70 -0
  241. package/dist/sheet/tables.js +147 -0
  242. package/dist/sheet/tokenize.d.ts +54 -0
  243. package/dist/sheet/tokenize.js +304 -0
  244. package/dist/sheet/transforms.d.ts +76 -0
  245. package/dist/sheet/transforms.js +154 -0
  246. package/dist/sheet/validation.d.ts +92 -0
  247. package/dist/sheet/validation.js +241 -0
  248. package/dist/sheet/workbook.d.ts +72 -0
  249. package/dist/sheet/workbook.js +409 -0
  250. package/dist/sheet-enable.d.ts +6 -0
  251. package/dist/sheet-enable.js +46 -0
  252. package/dist/sources/aggregate.d.ts +1 -1
  253. package/dist/sources/auth-supabase.js +1 -1
  254. package/dist/sources/dashboard.d.ts +2 -2
  255. package/dist/sources/dashboard.js +1 -1
  256. package/dist/sources/index.d.ts +13 -13
  257. package/dist/sources/index.js +13 -13
  258. package/dist/sources/realtime-supabase.js +1 -1
  259. package/dist/sources/relation-lookup.d.ts +1 -1
  260. package/dist/sources/relation-lookup.js +1 -1
  261. package/dist/sources/rest-adapters.d.ts +1 -1
  262. package/dist/sources/rest-adapters.js +1 -1
  263. package/dist/sources/rest.d.ts +2 -2
  264. package/dist/sources/rest.js +3 -3
  265. package/dist/sources/supabase.d.ts +2 -2
  266. package/dist/sources/supabase.js +3 -3
  267. package/dist/sources/with-entity-rules.d.ts +1 -1
  268. package/dist/sources/with-entity-rules.js +1 -1
  269. package/dist/sources/with-relation-labels.d.ts +1 -1
  270. package/dist/studio/emit-project.js +2161 -2127
  271. package/dist/studio/emit-schema.js +369 -369
  272. package/dist/studio/index.d.ts +1 -1
  273. package/dist/studio/index.js +1 -1
  274. package/dist/studio/introspect-db.js +45 -45
  275. package/dist/studio/project.d.ts +10 -0
  276. package/dist/studio/samples/crm.js +6 -6
  277. package/dist/studio/samples/fleet.js +7 -7
  278. package/dist/studio/samples/insurance.js +9 -9
  279. package/dist/studio/samples/inventory.js +12 -12
  280. package/dist/studio/samples/projects.js +5 -5
  281. package/dist/studio/samples/support.js +8 -8
  282. package/dist/studio/scaffold-app.js +104 -104
  283. package/dist/studio/scaffold.js +151 -151
  284. package/dist/studio/ui-components.d.ts +7 -0
  285. package/dist/studio/ui-components.generated.js +63 -1
  286. package/dist/studio/ui-components.js +35 -0
  287. package/dist/sveltekit/in-memory.d.ts +3 -3
  288. package/dist/sveltekit/in-memory.js +4 -4
  289. package/dist/sveltekit/index.d.ts +6 -6
  290. package/dist/sveltekit/index.js +5 -5
  291. package/dist/sveltekit/query-plan.d.ts +1 -1
  292. package/dist/sveltekit/sql-source.d.ts +4 -4
  293. package/dist/sveltekit/sql-source.js +4 -4
  294. package/dist/sveltekit/sql.d.ts +1 -1
  295. package/dist/sveltekit/transport.d.ts +2 -2
  296. package/dist/sveltekit/transport.js +1 -1
  297. package/dist/upgrade-prompt.js +25 -25
  298. package/dist/version.d.ts +1 -1
  299. package/dist/version.js +1 -1
  300. package/package.json +12 -4
  301. package/dist/designer/assets/GridMenus-Cgilexpk.js +0 -8
  302. package/dist/designer/assets/SvDateRangeInput-BV5OXYQ2.css +0 -1
  303. package/dist/designer/assets/SvDateRangeInput-CVn-yqrQ.js +0 -1
  304. package/dist/designer/assets/SvDateTimePicker-BdioTrJQ.js +0 -1
  305. package/dist/designer/assets/SvDateTimePicker-CY8TK4BT.css +0 -1
  306. package/dist/designer/assets/SvField-BF-9TJSd.css +0 -1
  307. package/dist/designer/assets/SvField-BsqiA5me.js +0 -1
  308. package/dist/designer/assets/SvGridCellEditor-dLY7_kk9.js +0 -2
  309. package/dist/designer/assets/SvGridChart-BEDNTdc5.js +0 -2
  310. package/dist/designer/assets/SvGridChart-Vu4Nvjiv.css +0 -1
  311. package/dist/designer/assets/SvGridChartPanel-x3lzSxuf.js +0 -10
  312. package/dist/designer/assets/SvGridChartView-CAKhPELi.js +0 -1
  313. package/dist/designer/assets/SvGridChartView-DX9HfkBR.css +0 -1
  314. package/dist/designer/assets/SvGridDropdown-CAYG7Y-O.js +0 -1
  315. package/dist/designer/assets/SvGridDropdown-Crwb2P3Q.css +0 -1
  316. package/dist/designer/assets/SvListBox-CVYQcLX9.js +0 -1
  317. package/dist/designer/assets/SvListBox-DgN8kvjt.css +0 -1
  318. package/dist/designer/assets/chart-DHEgt4lN.js +0 -1
  319. package/dist/designer/assets/column-resize-C_inr5zT.js +0 -1
  320. package/dist/designer/assets/date-format-4DJvNtG2.js +0 -1
  321. package/dist/designer/assets/date-format-Dzy4mTGh.css +0 -1
  322. package/dist/designer/assets/easing-zaypKrr0.js +0 -3
  323. package/dist/designer/assets/export-format-DwjuTfrQ.js +0 -6
  324. package/dist/designer/assets/index-Cp7fDJ3b.css +0 -1
  325. package/dist/designer/assets/js-scroller.svelte-Bhxqb3-c.js +0 -110
  326. package/dist/designer/assets/row-resize-B0FWHcNr.js +0 -1
  327. package/dist/designer/assets/src-B7DNcoQK.css +0 -1
  328. package/dist/designer/assets/src-BoYyigAC.js +0 -2896
  329. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/_svelte_metadata.json +0 -1
  330. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/_metadata.json +0 -178
  331. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-BOv1rBKp.js +0 -3875
  332. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-BOv1rBKp.js.map +0 -1
  333. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-B9vgIdCd.js +0 -21
  334. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-B9vgIdCd.js.map +0 -1
  335. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-T1qbW_qD.js +0 -1938
  336. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-T1qbW_qD.js.map +0 -1
  337. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-Bo11SfVK.js +0 -205
  338. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-Bo11SfVK.js.map +0 -1
  339. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-X7D4vfrZ.js +0 -18
  340. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-X7D4vfrZ.js.map +0 -1
  341. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-oyUje5i1.js +0 -264
  342. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-oyUje5i1.js.map +0 -1
  343. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-DeSQgSFm.js +0 -697
  344. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-DeSQgSFm.js.map +0 -1
  345. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/package.json +0 -3
  346. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js +0 -134
  347. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js.map +0 -1
  348. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js +0 -55
  349. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js.map +0 -1
  350. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_attachments.js +0 -2
  351. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js +0 -46843
  352. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js.map +0 -1
  353. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js +0 -237
  354. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js.map +0 -1
  355. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_events.js +0 -2
  356. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js +0 -4
  357. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js.map +0 -1
  358. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_client.js +0 -7
  359. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js +0 -4
  360. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js.map +0 -1
  361. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js +0 -5
  362. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js.map +0 -1
  363. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js +0 -5
  364. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js.map +0 -1
  365. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js +0 -5
  366. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js.map +0 -1
  367. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_server.js +0 -6
  368. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js +0 -83
  369. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js.map +0 -1
  370. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js +0 -559
  371. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js.map +0 -1
  372. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js +0 -24
  373. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js.map +0 -1
  374. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js +0 -122
  375. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js.map +0 -1
  376. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_server.js +0 -2
  377. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js +0 -89
  378. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js.map +0 -1
  379. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js +0 -241
  380. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js.map +0 -1
  381. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-BbWyXNk1.js +0 -4938
  382. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-BbWyXNk1.js.map +0 -1
  383. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DI_fC7vt.js +0 -495
  384. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DI_fC7vt.js.map +0 -1
  385. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-Dyr3lQv9.js +0 -190
  386. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-Dyr3lQv9.js.map +0 -1
  387. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-_9FHH-LF.js +0 -8
  388. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-_9FHH-LF.js.map +0 -1
  389. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-CUbSPnyP.js +0 -138
  390. package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-CUbSPnyP.js.map +0 -1
@@ -0,0 +1,753 @@
1
+ import { applyFormat, toggleFormat, preset, autoSum, structural, clearFormats, getFormatTarget, getWorkbook, withFormatUndo, nudgeFontSize, activeEntry, FONT_SIZES, DEFAULT_FONT_SIZE, applyBorders, formatAllowed, raiseRibbonAction, } from './shortcuts.js';
2
+ export { FONT_SIZES, applyBorders } from './shortcuts.js';
3
+ import { insertRows, deleteRows, getStructureTarget } from './structure.js';
4
+ import { fillDown, fillRight, targetRect } from './commands.js';
5
+ import { FORMAT_PRESETS, formatCategory } from './number-format.js';
6
+ import { ALL_COLOURS } from './palette.js';
7
+ // ---------------------------------------------------------------------------
8
+ // Shared predicates
9
+ // ---------------------------------------------------------------------------
10
+ /** True when there is at least one cell to act on. */
11
+ function hasTarget(cmd) {
12
+ return targetRect(cmd) !== null;
13
+ }
14
+ /**
15
+ * The rectangles an action should write to: the selection when there is one,
16
+ * otherwise the active cell alone.
17
+ *
18
+ * The same fallback `applyFormat` makes, so a button with nothing
19
+ * range-selected behaves like the key it mirrors rather than declining.
20
+ */
21
+ function rectsOf(cmd) {
22
+ if (cmd.ranges.length)
23
+ return cmd.ranges;
24
+ const rect = targetRect(cmd);
25
+ return rect ? [rect] : [];
26
+ }
27
+ /** Formatting needs somewhere to write. Without a store the keyboard
28
+ * bindings decline, so the buttons grey out for the same reason. */
29
+ function canFormat(cmd) {
30
+ const target = getFormatTarget();
31
+ if (!target || !hasTarget(cmd))
32
+ return false;
33
+ return target.guard?.(rectsOf(cmd)) !== false;
34
+ }
35
+ /** Insert and Delete grey out where the sheet refuses structural edits. */
36
+ function canRestructure() {
37
+ const target = getStructureTarget();
38
+ return !target || target.canApply?.({ kind: 'insertRows', at: 0, count: 1 }) !== false;
39
+ }
40
+ /**
41
+ * Whether every cell in the selection already carries `field`.
42
+ *
43
+ * Excel's own rule for a toggle button's pressed state, and the same rule
44
+ * `store.toggle` uses to decide which way the next press goes - so the button
45
+ * lights up exactly when pressing it would turn the attribute OFF.
46
+ */
47
+ function everyCellHas(cmd, test) {
48
+ const target = getFormatTarget();
49
+ if (!target)
50
+ return false;
51
+ const rects = rectsOf(cmd);
52
+ if (!rects.length)
53
+ return false;
54
+ let seen = 0;
55
+ for (const [minRow, minCol, maxRow, maxCol] of rects) {
56
+ for (let r = minRow; r <= maxRow; r += 1) {
57
+ for (let c = minCol; c <= maxCol; c += 1) {
58
+ const rowId = target.lookup.rowIdAt(r);
59
+ const columnId = target.lookup.columnIdAt(c);
60
+ if (rowId == null || columnId == null)
61
+ continue;
62
+ seen += 1;
63
+ if (!test(target.store.get(rowId, columnId)))
64
+ return false;
65
+ }
66
+ }
67
+ }
68
+ return seen > 0;
69
+ }
70
+ function styleToggle(field) {
71
+ return {
72
+ kind: 'toggle',
73
+ run: (cmd) => toggleFormat(cmd, field),
74
+ isOn: (cmd) => everyCellHas(cmd, (entry) => entry?.[field] === true),
75
+ isEnabled: canFormat,
76
+ };
77
+ }
78
+ function alignItem(align, title) {
79
+ return {
80
+ id: `align-${align}`,
81
+ label: '≡',
82
+ icon: `align-${align}`,
83
+ title,
84
+ kind: 'toggle',
85
+ run: (cmd) => applyFormat(cmd, { align }),
86
+ isOn: (cmd) => everyCellHas(cmd, (entry) => entry?.align === align),
87
+ isEnabled: canFormat,
88
+ };
89
+ }
90
+ function presetItem(id, label, title, name, keys) {
91
+ const run = preset(name);
92
+ return {
93
+ id,
94
+ label,
95
+ title,
96
+ keys,
97
+ kind: 'toggle',
98
+ run: (cmd) => run(cmd, new KeyboardEvent('keydown')),
99
+ isOn: (cmd) => everyCellHas(cmd, (entry) => entry?.numFmt === FORMAT_PRESETS[name]),
100
+ isEnabled: canFormat,
101
+ };
102
+ }
103
+ /** A command written for the keymap, adapted to a button. The event is only
104
+ * there because `SheetCommand` takes one; none of these read it. */
105
+ function fromCommand(command) {
106
+ return (cmd) => command(cmd, new KeyboardEvent('keydown'));
107
+ }
108
+ /**
109
+ * Excel's Increase/Decrease Decimal.
110
+ *
111
+ * Reads the active cell's current pattern rather than assuming one, so
112
+ * pressing it on a currency cell keeps the currency and only moves the point.
113
+ * A cell with no pattern starts from General, which Excel treats as 0 decimals.
114
+ */
115
+ function nudgeDecimals(delta) {
116
+ return (cmd) => {
117
+ const target = getFormatTarget();
118
+ const active = cmd.activeCell;
119
+ if (!target || !active)
120
+ return false;
121
+ const rowId = target.lookup.rowIdAt(active.rowIndex);
122
+ const columnId = target.lookup.columnIdAt(active.colIndex);
123
+ const current = rowId != null && columnId != null
124
+ ? target.store.get(rowId, columnId)?.numFmt
125
+ : undefined;
126
+ const next = withDecimals(current ?? '0', delta);
127
+ return next === null ? false : applyFormat(cmd, { numFmt: next });
128
+ };
129
+ }
130
+ /**
131
+ * Move the decimal count of a number-format pattern by `delta`.
132
+ *
133
+ * Exported because it is the fiddly part and deserves its own tests: the
134
+ * pattern can have a prefix and a suffix (`$#,##0.00`, `0.0%`), can have no
135
+ * decimal section at all, and must not go below zero or run away past the 30
136
+ * places Excel allows.
137
+ */
138
+ export function withDecimals(pattern, delta) {
139
+ // Every section moves together. The currency preset is
140
+ // '$#,##0.00;($#,##0.00)' - positives and negatives - and moving only the
141
+ // first half would leave a sheet where -1234.5 printed to a different
142
+ // precision than 1234.5. Excel moves both, so this does too.
143
+ //
144
+ // A quoted literal can contain a semicolon, which would make splitting on
145
+ // ';' cut a section in half, so a pattern with quotes declines instead of
146
+ // being mangled. Nothing in FORMAT_PRESETS has one.
147
+ if (pattern.includes('"'))
148
+ return null;
149
+ const sections = pattern.split(';');
150
+ const moved = [];
151
+ for (const section of sections) {
152
+ const next = sectionWithDecimals(section, delta);
153
+ // All or nothing: a partial rewrite is the very thing this guards.
154
+ if (next === null)
155
+ return null;
156
+ moved.push(next);
157
+ }
158
+ return moved.join(';');
159
+ }
160
+ function sectionWithDecimals(section, delta) {
161
+ const dot = section.indexOf('.');
162
+ const places = dot < 0 ? 0 : countLeading(section.slice(dot + 1), '0');
163
+ const next = places + delta;
164
+ if (next < 0 || next > 30)
165
+ return null;
166
+ const head = dot < 0 ? section : section.slice(0, dot);
167
+ const tail = dot < 0 ? '' : section.slice(dot + 1 + places);
168
+ return next === 0 ? head + tail : `${head}.${'0'.repeat(next)}${tail}`;
169
+ }
170
+ function countLeading(text, ch) {
171
+ let n = 0;
172
+ while (n < text.length && text[n] === ch)
173
+ n += 1;
174
+ return n;
175
+ }
176
+ // ---------------------------------------------------------------------------
177
+ // Fonts, sizes, borders
178
+ // ---------------------------------------------------------------------------
179
+ /**
180
+ * The fonts a spreadsheet user reaches for, with the stacks that make each
181
+ * render on a machine that lacks it. The empty value is the theme's own
182
+ * font, which is what "Default" means here and what a fresh cell has.
183
+ */
184
+ export const FONT_FAMILIES = [
185
+ { value: '', label: 'Default' },
186
+ { value: 'Aptos, "Aptos Narrow", "Segoe UI", sans-serif', label: 'Aptos' },
187
+ { value: 'Calibri, Carlito, "Segoe UI", sans-serif', label: 'Calibri' },
188
+ { value: 'Arial, Helvetica, sans-serif', label: 'Arial' },
189
+ { value: '"Segoe UI", system-ui, sans-serif', label: 'Segoe UI' },
190
+ { value: 'Verdana, Geneva, sans-serif', label: 'Verdana' },
191
+ { value: 'Georgia, "Times New Roman", serif', label: 'Georgia' },
192
+ { value: '"Times New Roman", Times, serif', label: 'Times New Roman' },
193
+ { value: '"Courier New", Courier, monospace', label: 'Courier New' },
194
+ { value: 'ui-monospace, Menlo, Consolas, monospace', label: 'Consolas' },
195
+ ];
196
+ const NUMBER_FORMATS = [
197
+ { value: 'general', label: 'General' },
198
+ { value: 'number', label: 'Number' },
199
+ { value: 'currency', label: 'Currency' },
200
+ { value: 'percent', label: 'Percentage' },
201
+ { value: 'date', label: 'Date' },
202
+ { value: 'time', label: 'Time' },
203
+ { value: 'scientific', label: 'Scientific' },
204
+ ];
205
+ const BORDER_OPTIONS = [
206
+ { value: 'bottom', label: 'Bottom Border', icon: 'border-bottom' },
207
+ { value: 'top', label: 'Top Border', icon: 'border-top' },
208
+ { value: 'left', label: 'Left Border', icon: 'border-left' },
209
+ { value: 'right', label: 'Right Border', icon: 'border-right' },
210
+ { value: 'none', label: 'No Border', icon: 'border-none' },
211
+ { value: 'all', label: 'All Borders', icon: 'border-all' },
212
+ { value: 'outside', label: 'Outside Borders', icon: 'border-outside' },
213
+ { value: 'thick-bottom', label: 'Thick Bottom Border', icon: 'border-thick-bottom' },
214
+ ];
215
+ // ---------------------------------------------------------------------------
216
+ // The tabs
217
+ // ---------------------------------------------------------------------------
218
+ const small = (row, item) => ({ ...item, row });
219
+ const HOME = {
220
+ id: 'home',
221
+ label: 'Home',
222
+ groups: [
223
+ {
224
+ id: 'clipboard',
225
+ icon: 'paste',
226
+ label: 'Clipboard',
227
+ launcher: 'paste-special',
228
+ items: [
229
+ // Excel's Clipboard group: the large Paste, and beside it Cut, Copy and
230
+ // Format Painter as icons alone, which is how Excel draws them at
231
+ // every width but the widest. Paste is a split button: the face
232
+ // pastes, the arrow opens the paste kinds with Paste Special... last.
233
+ {
234
+ id: 'paste', label: 'Paste', title: 'Paste', keys: 'Ctrl+V', icon: 'paste',
235
+ kind: 'dropdown', split: true, size: 'large',
236
+ run: (cmd) => { void cmd.paste(); return true; },
237
+ options: [
238
+ { value: 'paste', label: 'Paste', keys: 'Ctrl+V', icon: 'paste' },
239
+ { value: 'paste-formulas', label: 'Formulas', emits: 'paste-formulas' },
240
+ { value: 'paste-values', label: 'Values', emits: 'paste-values' },
241
+ { value: 'paste-formats', label: 'Formatting', emits: 'paste-formats' },
242
+ { value: 'paste-transpose', label: 'Transpose', emits: 'paste-transpose' },
243
+ { value: 'paste-special', label: 'Paste Special...', keys: 'Ctrl+Shift+V', emits: 'paste-special' },
244
+ ],
245
+ },
246
+ // The same copy and cut as Ctrl+C and Ctrl+X: the selection, cell
247
+ // by cell through the sheet's clipboard hook. They went through the
248
+ // api's copyToClipboard, which is the export, and put the whole
249
+ // sheet with its column letters on the clipboard whatever was
250
+ // selected; Cut then blanked the selection by hand.
251
+ small(1, {
252
+ id: 'cut', label: 'Cut', title: 'Cut', keys: 'Ctrl+X', icon: 'cut', kind: 'button',
253
+ isEnabled: hasTarget,
254
+ run: (cmd) => { void cmd.cut(); return true; },
255
+ }),
256
+ small(2, {
257
+ id: 'copy', label: 'Copy', title: 'Copy', keys: 'Ctrl+C', icon: 'copy', kind: 'button',
258
+ isEnabled: hasTarget,
259
+ run: (cmd) => { cmd.copy(); return true; },
260
+ }),
261
+ // Raised: the shell holds the copied formats and paints them onto the
262
+ // next selection. The button reads pressed while it is armed.
263
+ small(3, {
264
+ id: 'format-painter', label: 'Format Painter', title: 'Format Painter',
265
+ icon: 'format-painter', kind: 'button', emits: 'format-painter',
266
+ }),
267
+ ],
268
+ },
269
+ {
270
+ id: 'font',
271
+ icon: 'font',
272
+ label: 'Font',
273
+ layout: 'flow',
274
+ launcher: 'format-cells',
275
+ items: [
276
+ small(1, {
277
+ id: 'font-family', label: 'Font', title: 'Font', kind: 'select',
278
+ options: FONT_FAMILIES, isEnabled: canFormat,
279
+ current: (cmd) => activeEntry(cmd)?.fontFamily ?? '',
280
+ run: (cmd, value) => applyFormat(cmd, { fontFamily: value || undefined }),
281
+ }),
282
+ small(1, {
283
+ id: 'font-size', label: 'Size', title: 'Font Size', kind: 'select',
284
+ options: FONT_SIZES.map((n) => ({ value: String(n), label: String(n) })),
285
+ isEnabled: canFormat,
286
+ current: (cmd) => String(activeEntry(cmd)?.fontSize ?? DEFAULT_FONT_SIZE),
287
+ run: (cmd, value) => applyFormat(cmd, { fontSize: Number(value) === DEFAULT_FONT_SIZE ? undefined : Number(value) }),
288
+ }),
289
+ small(1, {
290
+ id: 'font-grow', label: 'A', title: 'Increase Font Size', keys: 'Ctrl+Shift+>',
291
+ icon: 'font-grow', kind: 'button', isEnabled: canFormat, run: fromCommand(nudgeFontSize(1)),
292
+ }),
293
+ small(1, {
294
+ id: 'font-shrink', label: 'A', title: 'Decrease Font Size', keys: 'Ctrl+Shift+<',
295
+ icon: 'font-shrink', kind: 'button', isEnabled: canFormat, run: fromCommand(nudgeFontSize(-1)),
296
+ }),
297
+ small(2, { id: 'bold', label: 'B', title: 'Bold', keys: 'Ctrl+B', ...styleToggle('bold') }),
298
+ small(2, { id: 'italic', label: 'I', title: 'Italic', keys: 'Ctrl+I', ...styleToggle('italic') }),
299
+ small(2, { id: 'underline', label: 'U', title: 'Underline', keys: 'Ctrl+U', ...styleToggle('underline') }),
300
+ small(2, { id: 'strike', label: 'S', title: 'Strikethrough', keys: 'Ctrl+5', ...styleToggle('strike') }),
301
+ small(2, {
302
+ id: 'borders', label: 'Borders', title: 'Borders', icon: 'borders', kind: 'menu',
303
+ options: BORDER_OPTIONS, isEnabled: canFormat,
304
+ run: (cmd, value) => applyBorders(cmd, (value || 'bottom')),
305
+ }),
306
+ small(2, {
307
+ id: 'fill', label: 'Fill Color', title: 'Fill Color', icon: 'fill-colour', kind: 'menu',
308
+ palette: true, none: { value: 'transparent', label: 'No Fill' }, initial: '#FFFF00',
309
+ options: ALL_COLOURS, isEnabled: canFormat,
310
+ run: (cmd, value) => applyFormat(cmd, { fill: !value || value === 'transparent' ? undefined : value }),
311
+ }),
312
+ small(2, {
313
+ id: 'text-colour', label: 'A', title: 'Font Color', icon: 'font-colour', kind: 'menu',
314
+ palette: true, none: { value: 'inherit', label: 'Automatic' }, initial: '#FF0000',
315
+ options: ALL_COLOURS, isEnabled: canFormat,
316
+ run: (cmd, value) => applyFormat(cmd, { color: !value || value === 'inherit' ? undefined : value }),
317
+ }),
318
+ ],
319
+ },
320
+ {
321
+ id: 'alignment',
322
+ icon: 'align-center',
323
+ label: 'Alignment',
324
+ layout: 'flow',
325
+ launcher: 'format-cells',
326
+ items: [
327
+ small(1, {
328
+ id: 'wrap', label: 'Wrap Text', title: 'Wrap Text', icon: 'wrap', kind: 'toggle', wide: true,
329
+ run: (cmd) => toggleWrap(cmd),
330
+ isOn: (cmd) => everyCellHas(cmd, (entry) => entry?.wrap === true),
331
+ isEnabled: canFormat,
332
+ }),
333
+ small(2, alignItem('left', 'Align Left')),
334
+ small(2, alignItem('center', 'Center')),
335
+ small(2, alignItem('right', 'Align Right')),
336
+ // Excel's split button: the face merges and centres, the arrow
337
+ // opens the kinds. Raised for the shell, which keeps the merges
338
+ // per sheet and hands them to the grid.
339
+ small(3, {
340
+ id: 'merge', label: 'Merge & Center', title: 'Merge & Center', icon: 'merge',
341
+ kind: 'dropdown', split: true, wide: true, lit: 'merge-center',
342
+ // Greyed on a protected sheet, as Excel's is: merging is a format.
343
+ isEnabled: canFormat,
344
+ run: (cmd) => raiseRibbonAction('merge-center', cmd),
345
+ options: [
346
+ { value: 'merge-center', label: 'Merge & Center', icon: 'merge', emits: 'merge-center' },
347
+ { value: 'merge-across', label: 'Merge Across', emits: 'merge-across' },
348
+ { value: 'merge-cells', label: 'Merge Cells', emits: 'merge-cells' },
349
+ { value: 'unmerge-cells', label: 'Unmerge Cells', icon: 'unmerge', emits: 'unmerge-cells' },
350
+ ],
351
+ }),
352
+ ],
353
+ },
354
+ {
355
+ id: 'number',
356
+ icon: 'number',
357
+ label: 'Number',
358
+ layout: 'flow',
359
+ launcher: 'format-cells',
360
+ items: [
361
+ small(1, {
362
+ id: 'num-format', label: 'General', title: 'Number Format', kind: 'select',
363
+ options: NUMBER_FORMATS, isEnabled: canFormat,
364
+ // The category, not the exact pattern: a typed 12% carries 0%,
365
+ // and Excel's combo calls that Percentage too. A pattern outside
366
+ // every category shows as itself.
367
+ current: (cmd) => {
368
+ const fmt = activeEntry(cmd)?.numFmt;
369
+ const { category } = formatCategory(fmt);
370
+ return category === 'custom' ? fmt ?? 'general' : category;
371
+ },
372
+ run: (cmd, value) => applyFormat(cmd, { numFmt: FORMAT_PRESETS[value] }),
373
+ }),
374
+ small(2, presetItem('fmt-currency', '$', 'Accounting Number Format', 'currency', 'Ctrl+Shift+4')),
375
+ small(2, presetItem('fmt-percent', '%', 'Percent Style', 'percent', 'Ctrl+Shift+5')),
376
+ small(2, presetItem('fmt-number', ',', 'Comma Style', 'number', 'Ctrl+Shift+1')),
377
+ small(2, {
378
+ id: 'dec-more', label: '.00', title: 'Increase Decimal', icon: 'dec-more', kind: 'button',
379
+ isEnabled: canFormat, run: nudgeDecimals(1),
380
+ }),
381
+ small(2, {
382
+ id: 'dec-less', label: '.0', title: 'Decrease Decimal', icon: 'dec-less', kind: 'button',
383
+ isEnabled: canFormat, run: nudgeDecimals(-1),
384
+ }),
385
+ ],
386
+ },
387
+ {
388
+ id: 'cells',
389
+ icon: 'table',
390
+ label: 'Cells',
391
+ items: [
392
+ small(1, {
393
+ id: 'insert', label: 'Insert', title: 'Insert Cells', keys: 'Ctrl+Shift++',
394
+ icon: 'insert-cells', kind: 'button', wide: true,
395
+ // A plain cell is ambiguous for the keystroke, which declines; the
396
+ // button behaves as Excel's does with a cell selected and inserts
397
+ // a row, shifting the sheet down.
398
+ run: (cmd) => structural(cmd, 'insert') || insertRows(cmd),
399
+ isEnabled: canRestructure,
400
+ }),
401
+ small(2, {
402
+ id: 'delete', label: 'Delete', title: 'Delete Cells', keys: 'Ctrl+-',
403
+ icon: 'delete-cells', kind: 'button', wide: true,
404
+ run: (cmd) => structural(cmd, 'delete') || deleteRows(cmd),
405
+ isEnabled: canRestructure,
406
+ }),
407
+ // Excel's Format menu: Cell Size, Visibility, and Format Cells at
408
+ // the end. Each entry is raised for the shell, which owns the size
409
+ // dialogs and keeps hidden lines per sheet.
410
+ small(3, {
411
+ id: 'format', label: 'Format', title: 'Format', icon: 'format-cells', kind: 'dropdown', wide: true,
412
+ options: [
413
+ { value: 'cell-size', label: 'Cell Size', heading: true },
414
+ { value: 'row-height', label: 'Row Height...', emits: 'row-height' },
415
+ { value: 'autofit-rows', label: 'AutoFit Row Height', emits: 'autofit-rows' },
416
+ { value: 'column-width', label: 'Column Width...', emits: 'column-width' },
417
+ { value: 'autofit-columns', label: 'AutoFit Column Width', emits: 'autofit-columns' },
418
+ { value: 'visibility', label: 'Visibility', heading: true },
419
+ { value: 'hide-rows', label: 'Hide Rows', keys: 'Ctrl+9', emits: 'hide-rows' },
420
+ { value: 'hide-columns', label: 'Hide Columns', keys: 'Ctrl+0', emits: 'hide-columns' },
421
+ { value: 'unhide-rows', label: 'Unhide Rows', keys: 'Ctrl+Shift+9', emits: 'unhide-rows' },
422
+ { value: 'unhide-columns', label: 'Unhide Columns', keys: 'Ctrl+Shift+0', emits: 'unhide-columns' },
423
+ { value: 'protection', label: 'Protection', heading: true },
424
+ { value: 'lock-cell', label: 'Lock Cell', icon: 'lock', emits: 'toggle-lock', toggle: true },
425
+ { value: 'format-cells', label: 'Format Cells...', keys: 'Ctrl+1', emits: 'format-cells' },
426
+ ],
427
+ }),
428
+ ],
429
+ },
430
+ {
431
+ // Excel's Styles group, the part with something behind it: one large
432
+ // Conditional Formatting dropdown. Its entries are raised for the
433
+ // shell, which owns the small dialogs and the rules per sheet; the
434
+ // headings are Excel's submenus, flattened.
435
+ id: 'styles',
436
+ icon: 'cf',
437
+ label: 'Styles',
438
+ items: [
439
+ {
440
+ id: 'conditional-formatting', label: 'Conditional Formatting', title: 'Conditional Formatting',
441
+ icon: 'cf', kind: 'dropdown', size: 'large',
442
+ options: [
443
+ { value: 'h', label: 'Highlight Cells Rules', heading: true },
444
+ { value: 'cf-greater', label: 'Greater Than...', icon: 'cf-greater', emits: 'cf-greater' },
445
+ { value: 'cf-less', label: 'Less Than...', icon: 'cf-less', emits: 'cf-less' },
446
+ { value: 'cf-between', label: 'Between...', icon: 'cf-between', emits: 'cf-between' },
447
+ { value: 'cf-equal', label: 'Equal To...', icon: 'cf-equal', emits: 'cf-equal' },
448
+ { value: 'cf-text', label: 'Text that Contains...', icon: 'cf-text', emits: 'cf-text' },
449
+ { value: 'cf-duplicates', label: 'Duplicate Values...', icon: 'cf-duplicates', emits: 'cf-duplicates' },
450
+ { value: 't', label: 'Top/Bottom Rules', heading: true },
451
+ { value: 'cf-top10', label: 'Top 10 Items...', icon: 'cf-top', emits: 'cf-top10' },
452
+ { value: 'cf-bottom10', label: 'Bottom 10 Items...', icon: 'cf-bottom', emits: 'cf-bottom10' },
453
+ { value: 'cf-above-average', label: 'Above Average...', icon: 'cf-above', emits: 'cf-above-average' },
454
+ { value: 'cf-below-average', label: 'Below Average...', icon: 'cf-below', emits: 'cf-below-average' },
455
+ { value: 'b', label: 'Data Bars, Color Scales, Icon Sets', heading: true },
456
+ { value: 'cf-data-bar', label: 'Data Bar', icon: 'cf-bar', emits: 'cf-data-bar' },
457
+ { value: 'cf-color-scale-3', label: 'Green - Yellow - Red Color Scale', icon: 'cf-scale', emits: 'cf-color-scale-3' },
458
+ { value: 'cf-color-scale-2', label: 'Green - White Color Scale', icon: 'cf-scale', emits: 'cf-color-scale-2' },
459
+ { value: 'cf-icon-set', label: 'Icon Set (3 Arrows)', icon: 'cf-icons', emits: 'cf-icon-set' },
460
+ { value: 'c', label: 'Clear Rules', heading: true },
461
+ { value: 'cf-clear-selection', label: 'Clear Rules from Selected Cells', emits: 'cf-clear-selection' },
462
+ { value: 'cf-clear-sheet', label: 'Clear Rules from Entire Sheet', emits: 'cf-clear-sheet' },
463
+ { value: 'm', label: 'Manage', heading: true },
464
+ { value: 'cf-manage', label: 'Manage Rules...', emits: 'cf-manage' },
465
+ ],
466
+ },
467
+ ],
468
+ },
469
+ {
470
+ id: 'editing',
471
+ icon: 'find',
472
+ label: 'Editing',
473
+ items: [
474
+ // Undo and Redo open the group as a column of two small icons, the
475
+ // way Cut and Copy stand beside Paste; the owner wanted them here
476
+ // rather than in a group of their own.
477
+ small(1, {
478
+ id: 'undo', label: 'Undo', title: 'Undo', keys: 'Ctrl+Z', icon: 'undo', kind: 'button',
479
+ isEnabled: (cmd) => cmd.api.canUndo(),
480
+ run: (cmd) => cmd.api.undo(),
481
+ }),
482
+ small(2, {
483
+ id: 'redo', label: 'Redo', title: 'Redo', keys: 'Ctrl+Y', icon: 'redo', kind: 'button',
484
+ isEnabled: (cmd) => cmd.api.canRedo(),
485
+ run: (cmd) => cmd.api.redo(),
486
+ }),
487
+ small(1, {
488
+ id: 'autosum', label: 'AutoSum', title: 'AutoSum', keys: 'Alt+=',
489
+ icon: 'autosum', kind: 'button', wide: true, run: fromCommand(autoSum),
490
+ }),
491
+ small(2, {
492
+ id: 'fill-down', label: 'Fill Down', title: 'Fill Down', keys: 'Ctrl+D',
493
+ icon: 'fill-down', kind: 'button', wide: true, run: (cmd) => fillDown(cmd),
494
+ }),
495
+ small(3, {
496
+ id: 'fill-right', label: 'Fill Right', title: 'Fill Right', keys: 'Ctrl+R',
497
+ icon: 'fill-right', kind: 'button', wide: true, run: (cmd) => fillRight(cmd),
498
+ }),
499
+ small(1, {
500
+ id: 'clear-formats', label: 'Clear', title: 'Clear Formats (keeps values)',
501
+ icon: 'clear', kind: 'button', wide: true, isEnabled: canFormat,
502
+ run: clearFormats,
503
+ }),
504
+ small(2, {
505
+ id: 'filter', label: 'Filter', title: 'Filter', keys: 'Ctrl+Shift+L',
506
+ icon: 'filter', kind: 'toggle', wide: true, emits: 'toggle-filter',
507
+ }),
508
+ small(3, {
509
+ id: 'find', label: 'Find & Select', title: 'Find and Replace', keys: 'Ctrl+H',
510
+ icon: 'find', kind: 'button', wide: true, emits: 'find-replace',
511
+ }),
512
+ ],
513
+ },
514
+ ],
515
+ };
516
+ const INSERT = {
517
+ id: 'insert',
518
+ label: 'Insert',
519
+ groups: [
520
+ {
521
+ id: 'tables',
522
+ icon: 'table',
523
+ label: 'Tables',
524
+ items: [
525
+ { id: 'table', label: 'Table', title: 'Format the selection as a table', keys: 'Ctrl+T', icon: 'table', kind: 'button', size: 'large', emits: 'insert-table' },
526
+ ],
527
+ },
528
+ {
529
+ id: 'charts',
530
+ icon: 'chart',
531
+ label: 'Charts',
532
+ items: [
533
+ { id: 'chart', label: 'Chart', title: 'Chart the selected range', icon: 'chart', kind: 'button', size: 'large', emits: 'insert-chart' },
534
+ ],
535
+ },
536
+ {
537
+ id: 'insert-cells',
538
+ icon: 'insert-cells',
539
+ label: 'Cells',
540
+ items: [
541
+ small(1, {
542
+ id: 'insert-rows', label: 'Insert', title: 'Insert rows or columns', icon: 'insert-cells', kind: 'button', wide: true,
543
+ run: (cmd) => structural(cmd, 'insert') || insertRows(cmd),
544
+ isEnabled: canRestructure,
545
+ }),
546
+ small(2, {
547
+ id: 'delete-rows', label: 'Delete', title: 'Delete rows or columns', icon: 'delete-cells', kind: 'button', wide: true,
548
+ run: (cmd) => structural(cmd, 'delete') || deleteRows(cmd),
549
+ isEnabled: canRestructure,
550
+ }),
551
+ ],
552
+ },
553
+ {
554
+ id: 'insert-function',
555
+ icon: 'function',
556
+ label: 'Functions',
557
+ items: [
558
+ { id: 'function', label: 'Insert Function', title: 'Insert Function', keys: 'Shift+F3', icon: 'function', kind: 'button', size: 'large', emits: 'insert-function' },
559
+ ],
560
+ },
561
+ {
562
+ id: 'insert-sheet',
563
+ icon: 'new-sheet',
564
+ label: 'Sheets',
565
+ items: [
566
+ {
567
+ id: 'new-sheet', label: 'New Sheet', title: 'New sheet', keys: 'Shift+F11',
568
+ icon: 'new-sheet', kind: 'button', size: 'large',
569
+ isEnabled: () => getWorkbook() !== null,
570
+ run: () => {
571
+ const wb = getWorkbook();
572
+ if (!wb)
573
+ return false;
574
+ wb.addSheet();
575
+ return true;
576
+ },
577
+ },
578
+ ],
579
+ },
580
+ ],
581
+ };
582
+ const FORMULAS = {
583
+ id: 'formulas',
584
+ label: 'Formulas',
585
+ groups: [
586
+ {
587
+ id: 'function-library',
588
+ icon: 'function',
589
+ label: 'Function Library',
590
+ items: [
591
+ { id: 'f-insert', label: 'Insert Function', title: 'Insert Function', keys: 'Shift+F3', icon: 'function', kind: 'button', size: 'large', emits: 'insert-function' },
592
+ { id: 'f-autosum', label: 'AutoSum', title: 'AutoSum', keys: 'Alt+=', icon: 'autosum', kind: 'button', size: 'large', run: fromCommand(autoSum) },
593
+ ],
594
+ },
595
+ {
596
+ id: 'defined-names',
597
+ icon: 'name-manager',
598
+ label: 'Defined Names',
599
+ items: [
600
+ { id: 'name-manager', label: 'Name Manager', title: 'Name Manager', keys: 'Ctrl+F3', icon: 'name-manager', kind: 'button', size: 'large', emits: 'name-manager' },
601
+ ],
602
+ },
603
+ {
604
+ id: 'auditing',
605
+ icon: 'show-formulas',
606
+ label: 'Formula Auditing',
607
+ items: [
608
+ small(1, { id: 'show-formulas', label: 'Show Formulas', title: 'Show formulas instead of their results', keys: 'Ctrl+`', icon: 'show-formulas', kind: 'toggle', wide: true, emits: 'toggle-formulas' }),
609
+ ],
610
+ },
611
+ {
612
+ id: 'calculation',
613
+ icon: 'calculate',
614
+ label: 'Calculation',
615
+ items: [
616
+ { id: 'recalc', label: 'Calculate Now', title: 'Recalculate the workbook', keys: 'F9', icon: 'calculate', kind: 'button', size: 'large', emits: 'recalculate' },
617
+ small(1, { id: 'goal-seek-f', label: 'Goal Seek', title: 'Goal Seek', icon: 'goal-seek', kind: 'button', wide: true, emits: 'goal-seek' }),
618
+ ],
619
+ },
620
+ ],
621
+ };
622
+ const DATA = {
623
+ id: 'data',
624
+ label: 'Data',
625
+ groups: [
626
+ {
627
+ id: 'sort-filter',
628
+ icon: 'filter',
629
+ label: 'Sort & Filter',
630
+ items: [
631
+ small(1, { id: 'sort-asc', label: 'Sort A to Z', title: 'Sort A to Z', icon: 'sort-asc', kind: 'button', emits: 'sort-asc' }),
632
+ small(2, { id: 'sort-desc', label: 'Sort Z to A', title: 'Sort Z to A', icon: 'sort-desc', kind: 'button', emits: 'sort-desc' }),
633
+ { id: 'filter-data', label: 'Filter', title: 'Filter', keys: 'Ctrl+Shift+L', icon: 'filter', kind: 'toggle', size: 'large', emits: 'toggle-filter' },
634
+ ],
635
+ },
636
+ {
637
+ id: 'data-tools',
638
+ icon: 'text-to-columns',
639
+ label: 'Data Tools',
640
+ items: [
641
+ { id: 'text-to-columns', label: 'Text to Columns', title: 'Split the selected column on a delimiter', icon: 'text-to-columns', kind: 'button', size: 'large', emits: 'text-to-columns' },
642
+ { id: 'remove-duplicates', label: 'Remove Duplicates', title: 'Remove duplicate rows', icon: 'remove-duplicates', kind: 'button', size: 'large', emits: 'remove-duplicates' },
643
+ { id: 'data-validation', label: 'Data Validation', title: 'Data Validation: what may be typed into the selected cells', icon: 'validation', kind: 'button', size: 'large', emits: 'data-validation' },
644
+ ],
645
+ },
646
+ {
647
+ id: 'forecast',
648
+ icon: 'goal-seek',
649
+ label: 'Forecast',
650
+ items: [
651
+ { id: 'goal-seek', label: 'Goal Seek', title: 'Change one input until a formula hits a target', icon: 'goal-seek', kind: 'button', size: 'large', emits: 'goal-seek' },
652
+ ],
653
+ },
654
+ ],
655
+ };
656
+ function toggleWrap(cmd) {
657
+ const target = getFormatTarget();
658
+ if (!target)
659
+ return false;
660
+ const rects = rectsOf(cmd);
661
+ if (!rects.length)
662
+ return false;
663
+ if (!formatAllowed(target, rects))
664
+ return false;
665
+ withFormatUndo(cmd, target, rects, () => target.store.toggle(rects, 'wrap', target.lookup));
666
+ target.onChange?.();
667
+ return true;
668
+ }
669
+ /**
670
+ * Excel's Review tab, the parts with something behind them. Comments are
671
+ * the sheet's notes: New Comment opens the editor on the active cell (and
672
+ * edits the one there), Delete, Previous and Next walk them, Show All
673
+ * Comments lists them. Protect Sheet and Unprotect Sheet are one slot, the
674
+ * shell leaving off whichever does not apply. There is no password, as the
675
+ * sheet documents.
676
+ */
677
+ const REVIEW = {
678
+ id: 'review',
679
+ label: 'Review',
680
+ groups: [
681
+ {
682
+ id: 'comments',
683
+ icon: 'comment',
684
+ label: 'Comments',
685
+ items: [
686
+ { id: 'new-comment', label: 'New Comment', title: 'New Comment', keys: 'Shift+F2', icon: 'comment', kind: 'button', size: 'large', emits: 'new-comment' },
687
+ small(1, { id: 'delete-comment', label: 'Delete', title: 'Delete Comment', icon: 'comment-delete', kind: 'button', wide: true, emits: 'delete-comment' }),
688
+ small(2, { id: 'prev-comment', label: 'Previous', title: 'Previous Comment', icon: 'comment-prev', kind: 'button', wide: true, emits: 'prev-comment' }),
689
+ small(3, { id: 'next-comment', label: 'Next', title: 'Next Comment', icon: 'comment-next', kind: 'button', wide: true, emits: 'next-comment' }),
690
+ { id: 'toggle-comments', label: 'Show All Comments', title: 'Show All Comments', icon: 'comments-all', kind: 'toggle', size: 'large', emits: 'toggle-comments' },
691
+ ],
692
+ },
693
+ {
694
+ id: 'protect',
695
+ icon: 'protect',
696
+ label: 'Protect',
697
+ items: [
698
+ {
699
+ id: 'protect-sheet', label: 'Protect Sheet', title: 'Protect Sheet: locked cells can no longer be changed',
700
+ icon: 'protect', kind: 'button', size: 'large', emits: 'protect-sheet',
701
+ },
702
+ {
703
+ id: 'unprotect-sheet', label: 'Unprotect Sheet', title: 'Unprotect Sheet',
704
+ icon: 'unprotect', kind: 'button', size: 'large', emits: 'unprotect-sheet',
705
+ },
706
+ ],
707
+ },
708
+ ],
709
+ };
710
+ /**
711
+ * Excel's View tab, the part with something behind it: Window > Freeze
712
+ * Panes, Excel's dropdown of Freeze Panes / Freeze Top Row / Freeze First
713
+ * Column / Unfreeze Panes. Raised rather than run here: the sheet shell
714
+ * keeps the freeze per sheet and puts it back when the sheet comes up
715
+ * again.
716
+ */
717
+ const VIEW = {
718
+ id: 'view',
719
+ label: 'View',
720
+ groups: [
721
+ {
722
+ id: 'show',
723
+ icon: 'gridlines',
724
+ label: 'Show',
725
+ items: [
726
+ small(1, { id: 'gridlines', label: 'Gridlines', title: 'Show or hide the gridlines', icon: 'gridlines', kind: 'toggle', wide: true, emits: 'toggle-gridlines' }),
727
+ small(2, { id: 'formula-bar', label: 'Formula Bar', title: 'Show or hide the formula bar', icon: 'formula-bar', kind: 'toggle', wide: true, emits: 'toggle-formula-bar' }),
728
+ small(3, { id: 'headings', label: 'Headings', title: 'Show or hide the row numbers and column letters', icon: 'headings', kind: 'toggle', wide: true, emits: 'toggle-headings' }),
729
+ ],
730
+ },
731
+ {
732
+ id: 'window',
733
+ icon: 'freeze',
734
+ label: 'Window',
735
+ items: [
736
+ {
737
+ id: 'freeze', label: 'Freeze Panes', title: 'Freeze Panes', icon: 'freeze', kind: 'dropdown', size: 'large',
738
+ options: [
739
+ { value: 'freeze-panes', label: 'Freeze Panes', icon: 'freeze', emits: 'freeze-panes' },
740
+ { value: 'freeze-top-row', label: 'Freeze Top Row', emits: 'freeze-top-row' },
741
+ { value: 'freeze-first-column', label: 'Freeze First Column', emits: 'freeze-first-column' },
742
+ { value: 'unfreeze-panes', label: 'Unfreeze Panes', icon: 'unfreeze', emits: 'unfreeze-panes' },
743
+ ],
744
+ },
745
+ ],
746
+ },
747
+ ],
748
+ };
749
+ export const RIBBON_TABS = [HOME, INSERT, FORMULAS, DATA, REVIEW, VIEW];
750
+ /** Every item across every tab, for tests and for a command palette. */
751
+ export function ribbonItems() {
752
+ return RIBBON_TABS.flatMap((tab) => tab.groups.flatMap((group) => group.items));
753
+ }