@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.
- package/LICENSE +94 -24
- package/README.md +36 -4
- package/dist/SvAdvancedFilter.svelte +1 -1
- package/dist/SvAlertsManager.svelte +2 -1
- package/dist/SvBoard.svelte +2 -1
- package/dist/SvExportMenu.svelte +4 -1
- package/dist/SvExportMenu.svelte.d.ts +0 -13
- package/dist/SvExpressionEditor.svelte +3 -3
- package/dist/SvFormulaBar.svelte +94 -20
- package/dist/SvFormulaBar.svelte.d.ts +7 -0
- package/dist/SvGridAlerts.svelte +49 -9
- package/dist/SvGridBoard.svelte +13 -8
- package/dist/SvGridBulkEditDrawer.svelte +26 -2
- package/dist/SvGridEditPanel.svelte +3 -0
- package/dist/SvGridScheduler.svelte +69 -40
- package/dist/SvGridSelectionBar.svelte +10 -3
- package/dist/SvPivotDesigner.svelte +198 -40
- package/dist/SvPivotDesigner.svelte.d.ts +27 -20
- package/dist/SvSheet.svelte +4043 -243
- package/dist/SvSheet.svelte.d.ts +76 -3
- package/dist/SvSheetChartSetup.svelte +151 -0
- package/dist/SvSheetChartSetup.svelte.d.ts +18 -0
- package/dist/SvSheetComment.svelte +216 -31
- package/dist/SvSheetComment.svelte.d.ts +11 -11
- package/dist/SvSheetConditionalFormat.svelte +28 -31
- package/dist/SvSheetDataValidation.svelte +66 -42
- package/dist/SvSheetEditRanges.svelte +217 -0
- package/dist/SvSheetEditRanges.svelte.d.ts +15 -0
- package/dist/SvSheetErrors.svelte +125 -0
- package/dist/SvSheetErrors.svelte.d.ts +20 -0
- package/dist/SvSheetEvaluate.svelte +133 -0
- package/dist/SvSheetEvaluate.svelte.d.ts +15 -0
- package/dist/SvSheetFilterMenu.svelte +137 -34
- package/dist/SvSheetFilterMenu.svelte.d.ts +5 -0
- package/dist/SvSheetFindReplace.svelte +19 -19
- package/dist/SvSheetFormatCells.svelte +125 -81
- package/dist/SvSheetGoalSeek.svelte +17 -16
- package/dist/SvSheetInsertFunction.svelte +15 -13
- package/dist/SvSheetIteration.svelte +81 -0
- package/dist/SvSheetIteration.svelte.d.ts +10 -0
- package/dist/SvSheetLink.svelte +99 -0
- package/dist/SvSheetLink.svelte.d.ts +17 -0
- package/dist/SvSheetListPicker.svelte +4 -2
- package/dist/SvSheetListPicker.svelte.d.ts +0 -6
- package/dist/SvSheetManageRules.svelte +20 -18
- package/dist/SvSheetNameManager.svelte +17 -15
- package/dist/SvSheetPageSetup.svelte +159 -0
- package/dist/SvSheetPageSetup.svelte.d.ts +13 -0
- package/dist/SvSheetPasteSpecial.svelte +22 -20
- package/dist/SvSheetPivot.svelte +220 -0
- package/dist/SvSheetPivot.svelte.d.ts +21 -0
- package/dist/SvSheetProtectSheet.svelte +81 -0
- package/dist/SvSheetProtectSheet.svelte.d.ts +11 -0
- package/dist/SvSheetRemoveDuplicates.svelte +13 -10
- package/dist/SvSheetRibbon.svelte +104 -51
- package/dist/SvSheetSizeDialog.svelte +4 -2
- package/dist/SvSheetSort.svelte +218 -0
- package/dist/SvSheetSort.svelte.d.ts +28 -0
- package/dist/SvSheetSparklines.svelte +135 -0
- package/dist/SvSheetSparklines.svelte.d.ts +14 -0
- package/dist/SvSheetTable.svelte +160 -0
- package/dist/SvSheetTable.svelte.d.ts +24 -0
- package/dist/SvSheetTabs.svelte +161 -31
- package/dist/SvSheetTabs.svelte.d.ts +22 -8
- package/dist/SvSheetTextToColumns.svelte +20 -20
- package/dist/SvSheetValidationAlert.svelte +8 -6
- package/dist/advanced-filter-enable.js +1 -1
- package/dist/alerts/alert-engine.d.ts +6 -0
- package/dist/alerts/alert-engine.js +21 -4
- package/dist/alerts/alert-formats.js +2 -0
- package/dist/alerts/alert-types.d.ts +1 -1
- package/dist/alerts.d.ts +1 -1
- package/dist/alerts.js +2 -2
- package/dist/board.js +2 -2
- package/dist/bulk-edit.d.ts +3 -1
- package/dist/bulk-edit.js +1 -1
- package/dist/cdn/svgrid-enterprise.svelte-external.js +39827 -16429
- package/dist/designer/assets/GridMenus-8gTNssgV.js +8 -0
- package/dist/designer/assets/{SvChartMenu-D9hEeHar.js → SvChartMenu-BDoeqGz6.js} +1 -1
- package/dist/designer/assets/{SvDateTimePicker-DARvKUL2.js → SvDateTimePicker-DCPg7WGN.js} +1 -1
- package/dist/designer/assets/SvGridCellEditor-DMoWJjEI.js +4 -0
- package/dist/designer/assets/{SvGridChart-B8j1SSy3.js → SvGridChart-Cy1ATrWh.js} +2 -2
- package/dist/designer/assets/SvGridChartBuilder-eQ3mn0L9.js +1 -0
- package/dist/designer/assets/{SvGridChartPanel-pT6ITc2P.js → SvGridChartPanel-CATdVc9X.js} +3 -3
- package/dist/designer/assets/{SvGridChartView-bg281UA1.js → SvGridChartView-CmsZtCED.js} +1 -1
- package/dist/designer/assets/SvGridDropdown-Cjz0H-fI.js +1 -0
- package/dist/designer/assets/{SvTabs-UFCMTHXS.js → SvTabs-2mHC6oaz.js} +1 -1
- package/dist/designer/assets/cell-formatting-BbubJTVz.js +1 -0
- package/dist/designer/assets/{chart-cIPUsbM5.js → chart-Cn7MnNqA.js} +1 -1
- package/dist/designer/assets/{chart-panel-messages-DtTxpBUU.js → chart-panel-messages-Dz7PTIqT.js} +1 -1
- package/dist/designer/assets/{chart-summary-Czu_5epb.js → chart-summary-BD1qYB2R.js} +1 -1
- package/dist/designer/assets/{chart-trend-D5I5VEe8.js → chart-trend-B8xr5LuD.js} +1 -1
- package/dist/designer/assets/{dismissable-BO547MH9.js → dismissable-ChWRPkoa.js} +1 -1
- package/dist/designer/assets/{export-format-D-eP4b2l.js → export-format-DGckmgKr.js} +1 -1
- package/dist/designer/assets/{focus-trap-CAreAhlU.js → focus-trap-V2-6Fy9I.js} +1 -1
- package/dist/designer/assets/{index-DwU7CAMm.js → index-D5bVbuzI.js} +317 -315
- package/dist/designer/assets/index-_JVFxt02.css +1 -0
- package/dist/designer/assets/row-resize-BInFWCpr.js +1 -0
- package/dist/designer/assets/server-block-cache-CXJKkJpy.js +1 -0
- package/dist/designer/assets/src-DUQ4xE3x.js +58 -0
- package/dist/designer/assets/validate-C3B8QKsM.js +1 -0
- package/dist/designer/index.html +17 -16
- package/dist/export-pdf.d.ts +75 -0
- package/dist/export-pdf.js +216 -15
- package/dist/export.js +10 -2
- package/dist/gantt/SvGridGantt.svelte +2890 -0
- package/dist/gantt/SvGridGantt.svelte.d.ts +30 -0
- package/dist/gantt/gantt-config.d.ts +73 -0
- package/dist/gantt/gantt-config.js +1 -0
- package/dist/gantt/gantt-critical-path.d.ts +67 -0
- package/dist/gantt/gantt-critical-path.js +207 -0
- package/dist/gantt/gantt-model.d.ts +257 -0
- package/dist/gantt/gantt-model.js +651 -0
- package/dist/gantt/gantt-resources.d.ts +59 -0
- package/dist/gantt/gantt-resources.js +71 -0
- package/dist/gantt/gantt.d.ts +7 -0
- package/dist/gantt/gantt.js +36 -0
- package/dist/gantt/index.d.ts +15 -0
- package/dist/gantt/index.js +22 -0
- package/dist/gantt/timeline-arrows.d.ts +102 -0
- package/dist/gantt/timeline-arrows.js +181 -0
- package/dist/import.d.ts +2 -2
- package/dist/import.js +1 -1
- package/dist/index.d.ts +34 -7
- package/dist/index.js +44 -7
- package/dist/install.js +8 -1
- package/dist/license-core.d.ts +17 -1
- package/dist/license-core.js +16 -5
- package/dist/license.d.ts +18 -2
- package/dist/license.js +71 -6
- package/dist/node/studio.js +140 -8
- package/dist/pivot-enable.js +2 -2
- package/dist/scheduler-dependencies.d.ts +35 -0
- package/dist/scheduler-dependencies.js +36 -1
- package/dist/scheduler.js +2 -2
- package/dist/selection-bar.js +2 -2
- package/dist/server/SvGroupCell.svelte +213 -0
- package/dist/server/SvGroupCell.svelte.d.ts +62 -0
- package/dist/server/SvRowGroupPanel.svelte +322 -0
- package/dist/server/SvRowGroupPanel.svelte.d.ts +37 -0
- package/dist/server/enable.d.ts +17 -0
- package/dist/server/enable.js +49 -0
- package/dist/server/index.d.ts +22 -0
- package/dist/server/index.js +24 -0
- package/dist/server/messages.d.ts +45 -0
- package/dist/server/messages.js +35 -0
- package/dist/server/server-group-model.d.ts +104 -0
- package/dist/server/server-group-model.js +272 -0
- package/dist/server/server-pivot.d.ts +46 -0
- package/dist/server/server-pivot.js +57 -0
- package/dist/server/server-row-model.d.ts +547 -0
- package/dist/server/server-row-model.js +1551 -0
- package/dist/server/server-selection.d.ts +99 -0
- package/dist/server/server-selection.js +215 -0
- package/dist/server/svgrid-adapter.d.ts +155 -0
- package/dist/server/svgrid-adapter.js +202 -0
- package/dist/sheet/ast.d.ts +45 -1
- package/dist/sheet/ast.js +14 -0
- package/dist/sheet/auto-filter.d.ts +58 -4
- package/dist/sheet/auto-filter.js +159 -11
- package/dist/sheet/autocomplete.d.ts +9 -0
- package/dist/sheet/autocomplete.js +90 -4
- package/dist/sheet/cell-images.d.ts +39 -0
- package/dist/sheet/cell-images.js +90 -0
- package/dist/sheet/cell-types.d.ts +58 -0
- package/dist/sheet/cell-types.js +96 -0
- package/dist/sheet/coerce.d.ts +40 -0
- package/dist/sheet/coerce.js +170 -3
- package/dist/sheet/comments.d.ts +43 -9
- package/dist/sheet/comments.js +85 -27
- package/dist/sheet/conditional-formats.d.ts +29 -6
- package/dist/sheet/conditional-formats.js +37 -12
- package/dist/sheet/csv.d.ts +32 -0
- package/dist/sheet/csv.js +158 -0
- package/dist/sheet/culture.d.ts +87 -0
- package/dist/sheet/culture.js +247 -0
- package/dist/sheet/delta.d.ts +102 -0
- package/dist/sheet/delta.js +203 -0
- package/dist/sheet/deps.d.ts +45 -1
- package/dist/sheet/deps.js +77 -2
- package/dist/sheet/document.d.ts +106 -4
- package/dist/sheet/document.js +204 -3
- package/dist/sheet/engine.d.ts +67 -0
- package/dist/sheet/engine.js +19 -0
- package/dist/sheet/entry.d.ts +8 -4
- package/dist/sheet/entry.js +171 -21
- package/dist/sheet/error-check.d.ts +49 -0
- package/dist/sheet/error-check.js +83 -0
- package/dist/sheet/evaluate-steps.d.ts +48 -0
- package/dist/sheet/evaluate-steps.js +196 -0
- package/dist/sheet/evaluate.d.ts +67 -0
- package/dist/sheet/evaluate.js +725 -13
- package/dist/sheet/filter-files.d.ts +37 -0
- package/dist/sheet/filter-files.js +465 -0
- package/dist/sheet/format-store.d.ts +15 -0
- package/dist/sheet/format-store.js +11 -1
- package/dist/sheet/from-rows.d.ts +14 -0
- package/dist/sheet/from-rows.js +50 -0
- package/dist/sheet/function-catalog.d.ts +1 -1
- package/dist/sheet/function-catalog.js +296 -5
- package/dist/sheet/functions.js +363 -91
- package/dist/sheet/index.d.ts +35 -8
- package/dist/sheet/index.js +35 -8
- package/dist/sheet/links.d.ts +57 -0
- package/dist/sheet/links.js +174 -0
- package/dist/sheet/messages.d.ts +778 -0
- package/dist/sheet/messages.js +806 -0
- package/dist/sheet/number-format.d.ts +52 -5
- package/dist/sheet/number-format.js +465 -68
- package/dist/sheet/objects.d.ts +106 -0
- package/dist/sheet/objects.js +149 -0
- package/dist/sheet/ods-document.d.ts +44 -0
- package/dist/sheet/ods-document.js +1275 -0
- package/dist/sheet/open-file.d.ts +26 -0
- package/dist/sheet/open-file.js +56 -0
- package/dist/sheet/outline.d.ts +82 -0
- package/dist/sheet/outline.js +228 -0
- package/dist/sheet/packs/array.d.ts +16 -0
- package/dist/sheet/packs/array.js +172 -0
- package/dist/sheet/packs/database.d.ts +42 -0
- package/dist/sheet/packs/database.js +142 -0
- package/dist/sheet/packs/engineering.d.ts +2 -0
- package/dist/sheet/packs/engineering.js +296 -0
- package/dist/sheet/packs/financial.d.ts +5 -0
- package/dist/sheet/packs/financial.js +220 -0
- package/dist/sheet/packs/math-stats.d.ts +2 -0
- package/dist/sheet/packs/math-stats.js +372 -0
- package/dist/sheet/packs/special.d.ts +44 -0
- package/dist/sheet/packs/special.js +187 -0
- package/dist/sheet/packs/stats-dist.d.ts +2 -0
- package/dist/sheet/packs/stats-dist.js +785 -0
- package/dist/sheet/packs/text-date.d.ts +2 -0
- package/dist/sheet/packs/text-date.js +332 -0
- package/dist/sheet/packs/trig.d.ts +2 -0
- package/dist/sheet/packs/trig.js +73 -0
- package/dist/sheet/page-setup.d.ts +73 -0
- package/dist/sheet/page-setup.js +73 -0
- package/dist/sheet/parse.js +42 -10
- package/dist/sheet/paste-special.d.ts +22 -0
- package/dist/sheet/paste-special.js +14 -5
- package/dist/sheet/pivot-range.d.ts +160 -0
- package/dist/sheet/pivot-range.js +333 -0
- package/dist/sheet/presence.d.ts +73 -0
- package/dist/sheet/presence.js +79 -0
- package/dist/sheet/print.d.ts +104 -0
- package/dist/sheet/print.js +169 -0
- package/dist/sheet/protection.d.ts +55 -1
- package/dist/sheet/protection.js +55 -2
- package/dist/sheet/rects.d.ts +1 -1
- package/dist/sheet/refs.d.ts +48 -0
- package/dist/sheet/refs.js +155 -8
- package/dist/sheet/ribbon-icons.d.ts +1 -1
- package/dist/sheet/ribbon-icons.js +186 -0
- package/dist/sheet/ribbon.d.ts +1 -1
- package/dist/sheet/ribbon.js +324 -23
- package/dist/sheet/sheet-kinds.d.ts +74 -0
- package/dist/sheet/sheet-kinds.js +91 -0
- package/dist/sheet/shortcuts.d.ts +13 -3
- package/dist/sheet/shortcuts.js +63 -12
- package/dist/sheet/sort.d.ts +51 -0
- package/dist/sheet/sort.js +107 -0
- package/dist/sheet/sparklines.d.ts +111 -0
- package/dist/sheet/sparklines.js +204 -0
- package/dist/sheet/table-styles.d.ts +74 -0
- package/dist/sheet/table-styles.js +152 -0
- package/dist/sheet/tables.d.ts +19 -0
- package/dist/sheet/tables.js +31 -0
- package/dist/sheet/tokenize.d.ts +18 -1
- package/dist/sheet/tokenize.js +60 -9
- package/dist/sheet/validation.d.ts +16 -0
- package/dist/sheet/validation.js +37 -0
- package/dist/sheet/workbook.d.ts +148 -3
- package/dist/sheet/workbook.js +742 -31
- package/dist/sheet/xls-cfb.d.ts +32 -0
- package/dist/sheet/xls-cfb.js +290 -0
- package/dist/sheet/xls-document.d.ts +10 -0
- package/dist/sheet/xls-document.js +1243 -0
- package/dist/sheet/xls-formula.d.ts +40 -0
- package/dist/sheet/xls-formula.js +569 -0
- package/dist/sheet/xlsx-document.d.ts +108 -0
- package/dist/sheet/xlsx-document.js +1849 -0
- package/dist/sheet/xlsx-drawing.d.ts +99 -0
- package/dist/sheet/xlsx-drawing.js +420 -0
- package/dist/sheet-enable.js +6 -7
- package/dist/sheet-text.d.ts +7 -0
- package/dist/sheet-text.js +29 -0
- package/dist/sources/auth-supabase.js +2 -2
- package/dist/sources/realtime-supabase.js +2 -2
- package/dist/sources/rest.d.ts +6 -2
- package/dist/sources/rest.js +42 -7
- package/dist/sources/supabase.d.ts +10 -1
- package/dist/sources/supabase.js +73 -40
- package/dist/studio/emit-project.js +14 -1
- package/dist/studio/index.js +1 -1
- package/dist/studio/project.d.ts +11 -2
- package/dist/studio/project.js +5 -2
- package/dist/studio/ui-components.generated.js +107 -2
- package/dist/sveltekit/in-memory.d.ts +2 -2
- package/dist/sveltekit/in-memory.js +125 -4
- package/dist/sveltekit/index.d.ts +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/dist/sveltekit/query-plan.d.ts +50 -4
- package/dist/sveltekit/query-plan.js +25 -3
- package/dist/sveltekit/sql-source.d.ts +6 -0
- package/dist/sveltekit/sql-source.js +34 -6
- package/dist/sveltekit/sql.d.ts +31 -0
- package/dist/sveltekit/sql.js +135 -25
- package/dist/sveltekit/transport.d.ts +10 -2
- package/dist/sveltekit/transport.js +30 -6
- package/dist/upgrade-prompt.d.ts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/watermark.js +35 -2
- package/dist/wc/GridMenus-By9vPuq0.js +1088 -0
- package/dist/wc/SvChartMenu-CQNrQGT2.js +308 -0
- package/dist/wc/SvDateRangeInput-DR6m7bSM.js +199 -0
- package/dist/wc/SvDateTimePicker-D-vRnaMo.js +771 -0
- package/dist/wc/SvField-B_kurx_P.js +149 -0
- package/dist/wc/SvGrid.helpers-BdVDtjUm.js +135 -0
- package/dist/wc/SvGridCellEditor-Bnf1Kr5C.js +560 -0
- package/dist/wc/SvGridChart-BqUJh2pG.js +3572 -0
- package/dist/wc/SvGridChartBuilder-CGycC5cn.js +988 -0
- package/dist/wc/SvGridChartPanel-CRnizsHD.js +1746 -0
- package/dist/wc/SvGridChartView-D1pa_xMy.js +47 -0
- package/dist/wc/SvGridDropdown-45WsObLL.js +259 -0
- package/dist/wc/SvModal-DrfOYYyX.js +189 -0
- package/dist/wc/cell-formatting-CBfgahv1.js +86 -0
- package/dist/wc/chart-6OXlybVT.js +4341 -0
- package/dist/wc/chart-export-CeSADGfi.js +135 -0
- package/dist/wc/chart-export-pdf-BGko7MER.js +104 -0
- package/dist/wc/chart-summary-2m3ia1-n.js +137 -0
- package/dist/wc/chart-trend-CQOQtTMl.js +50 -0
- package/dist/wc/chart-validate-CD6ptiwg.js +180 -0
- package/dist/wc/client-DQIzjDBG.js +3064 -0
- package/dist/wc/column-resize-DUPgynvc.js +101 -0
- package/dist/wc/date-format-DS-z_h9v.js +1130 -0
- package/dist/wc/dismissable-CQ6XFXsk.js +45 -0
- package/dist/wc/editor-contract-peBDxir_.js +22 -0
- package/dist/wc/editor-registry-DxGKqcvx.js +24 -0
- package/dist/wc/focus-trap-Dbb2tJxb.js +65 -0
- package/dist/wc/list-option-DrRyivWp.js +82 -0
- package/dist/wc/popover-WsGlvtQv.js +69 -0
- package/dist/wc/positioning-BiKLfu1E.js +112 -0
- package/dist/wc/react.d.ts +41 -0
- package/dist/wc/react.js +90 -0
- package/dist/wc/rolldown-runtime-Dy4uBu1J.js +11 -0
- package/dist/wc/row-drag-touch-CycRR65n.js +93 -0
- package/dist/wc/row-resize-limG_N1z.js +111 -0
- package/dist/wc/sv-sheet-element.d.ts +97 -0
- package/dist/wc/sv-sheet-element.js +44213 -0
- package/dist/wc/svelte-virtualizer.svelte-CXtQy2TQ.js +530 -0
- package/dist/wc/validate-BqDthkNr.js +88 -0
- package/dist/wc/vue.d.ts +31 -0
- package/dist/wc/vue.js +75 -0
- package/package.json +30 -5
- package/dist/designer/assets/GridMenus-BlsvL_aU.js +0 -8
- package/dist/designer/assets/SvGridCellEditor-C7uQXYds.js +0 -4
- package/dist/designer/assets/SvGridChartBuilder-kvyIU_Rl.js +0 -1
- package/dist/designer/assets/SvGridDropdown-Bb3HH2Aj.js +0 -1
- package/dist/designer/assets/cell-formatting-wr5wm7US.js +0 -1
- package/dist/designer/assets/index-CMFgAoVV.css +0 -1
- package/dist/designer/assets/row-resize-DLktcqUK.js +0 -1
- package/dist/designer/assets/src-EdI3Xqds.js +0 -58
- package/dist/designer/assets/validate-h-aslRV9.js +0 -1
package/dist/sheet/deps.js
CHANGED
|
@@ -48,7 +48,25 @@ export function precedentsOf(ast, self, lastRow,
|
|
|
48
48
|
* `Tax` leaves the formula showing its old value until something else
|
|
49
49
|
* forces a recalculation.
|
|
50
50
|
*/
|
|
51
|
-
resolveName,
|
|
51
|
+
resolveName,
|
|
52
|
+
/**
|
|
53
|
+
* The rectangle behind a structured reference (`Orders[Amount]`,
|
|
54
|
+
* `[@Qty]`). Without it a formula over a table records no precedents, so
|
|
55
|
+
* editing a cell in the table leaves every total reading it stale until
|
|
56
|
+
* something forces a full recalculation.
|
|
57
|
+
*/
|
|
58
|
+
resolveTable,
|
|
59
|
+
/**
|
|
60
|
+
* The rectangle a spilled-range operator (`A1#`) currently covers. The
|
|
61
|
+
* anchor cell is always recorded regardless, so a formula reading `A1#`
|
|
62
|
+
* recalculates whenever the array is re-typed and picks up the new extent;
|
|
63
|
+
* the covered cells are added on top so a change anywhere in the spill
|
|
64
|
+
* reaches it too.
|
|
65
|
+
*/
|
|
66
|
+
resolveSpill,
|
|
67
|
+
/** The sheets a 3D reference spans, so it recalculates when the cell on any
|
|
68
|
+
* of them changes. */
|
|
69
|
+
resolveSheets, depth = 0) {
|
|
52
70
|
const out = [];
|
|
53
71
|
visit(ast, (n) => {
|
|
54
72
|
if (n.k === 'name') {
|
|
@@ -56,7 +74,46 @@ resolveName, depth = 0) {
|
|
|
56
74
|
// after a few hops rather than recursing forever.
|
|
57
75
|
const target = depth < 8 ? resolveName?.(n.name) : null;
|
|
58
76
|
if (target)
|
|
59
|
-
out.push(...precedentsOf(target, self, lastRow, resolveName, depth + 1));
|
|
77
|
+
out.push(...precedentsOf(target, self, lastRow, resolveName, resolveTable, resolveSpill, resolveSheets, depth + 1));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (n.k === 'ref3d') {
|
|
81
|
+
const sheets = resolveSheets?.(n.sheetFrom, n.sheetTo);
|
|
82
|
+
if (!sheets)
|
|
83
|
+
return;
|
|
84
|
+
const r1 = Math.min(n.from.row ?? 0, n.to.row ?? 0);
|
|
85
|
+
const r2 = Math.max(n.from.row ?? 0, n.to.row ?? 0);
|
|
86
|
+
const c1 = Math.min(n.from.col, n.to.col);
|
|
87
|
+
const c2 = Math.max(n.from.col, n.to.col);
|
|
88
|
+
for (const s of sheets) {
|
|
89
|
+
for (let r = r1; r <= r2; r += 1) {
|
|
90
|
+
for (let c = c1; c <= c2; c += 1)
|
|
91
|
+
out.push(cellKey(s, r, c));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (n.k === 'spill') {
|
|
97
|
+
// The anchor always: retyping the array changes the anchor cell, so
|
|
98
|
+
// this makes the reader recalculate and re-derive the extent below.
|
|
99
|
+
out.push(cellKey(n.ref.sheet ?? self.sheet, n.ref.row ?? 0, n.ref.col));
|
|
100
|
+
const rect = resolveSpill?.(n);
|
|
101
|
+
if (rect) {
|
|
102
|
+
for (let r = rect.r1; r <= rect.r2; r += 1) {
|
|
103
|
+
for (let c = rect.c1; c <= rect.c2; c += 1)
|
|
104
|
+
out.push(cellKey(rect.sheet ?? self.sheet, r, c));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (n.k === 'table') {
|
|
110
|
+
const rect = resolveTable?.(n);
|
|
111
|
+
if (!rect)
|
|
112
|
+
return;
|
|
113
|
+
for (let r = rect.firstRow; r <= rect.lastRow; r += 1) {
|
|
114
|
+
for (let c = rect.firstCol; c <= rect.lastCol; c += 1)
|
|
115
|
+
out.push(cellKey(rect.sheet, r, c));
|
|
116
|
+
}
|
|
60
117
|
return;
|
|
61
118
|
}
|
|
62
119
|
if (n.k === 'ref' && n.ref.row !== null) {
|
|
@@ -79,6 +136,21 @@ resolveName, depth = 0) {
|
|
|
79
136
|
});
|
|
80
137
|
return out;
|
|
81
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Functions whose result can change without any precedent changing: a
|
|
141
|
+
* reference built from text, a range built from arithmetic, the clock, a
|
|
142
|
+
* random number. A cell holding one is recomputed on every edit, as Excel
|
|
143
|
+
* recomputes its volatile cells, rather than trusting the graph.
|
|
144
|
+
*/
|
|
145
|
+
export const VOLATILE_FUNCTIONS = new Set(['INDIRECT', 'OFFSET', 'RAND', 'RANDBETWEEN', 'NOW', 'TODAY']);
|
|
146
|
+
export function isVolatile(ast) {
|
|
147
|
+
let found = false;
|
|
148
|
+
visit(ast, (n) => {
|
|
149
|
+
if (n.k === 'fn' && VOLATILE_FUNCTIONS.has(n.name))
|
|
150
|
+
found = true;
|
|
151
|
+
});
|
|
152
|
+
return found;
|
|
153
|
+
}
|
|
82
154
|
export function createDependencyGraph() {
|
|
83
155
|
/** cell -> what it reads. */
|
|
84
156
|
const precedents = new Map();
|
|
@@ -188,6 +260,9 @@ export function createDependencyGraph() {
|
|
|
188
260
|
}
|
|
189
261
|
return out;
|
|
190
262
|
},
|
|
263
|
+
precedentsOf(cell) {
|
|
264
|
+
return [...(precedents.get(cell) ?? [])];
|
|
265
|
+
},
|
|
191
266
|
dependentsOf(cell) {
|
|
192
267
|
return [...(dependents.get(cell) ?? [])];
|
|
193
268
|
},
|
package/dist/sheet/document.d.ts
CHANGED
|
@@ -21,10 +21,20 @@ import { type Workbook, type SheetData } from './workbook.js';
|
|
|
21
21
|
import { type SheetFormatStore, type CellFormatEntry } from './format-store.js';
|
|
22
22
|
import type { FreezeState } from './freeze.js';
|
|
23
23
|
import type { StructuralEdit } from './refs.js';
|
|
24
|
-
import { type
|
|
24
|
+
import { type Rect } from './rects.js';
|
|
25
|
+
import type { CommentsMap } from './comments.js';
|
|
26
|
+
import { type SheetProtection } from './protection.js';
|
|
27
|
+
import { type PageSetup } from './page-setup.js';
|
|
28
|
+
import { type SheetObject } from './objects.js';
|
|
29
|
+
import { type SparklineGroup } from './sparklines.js';
|
|
30
|
+
import { type SheetPivot } from './pivot-range.js';
|
|
31
|
+
import { type LinksMap } from './links.js';
|
|
25
32
|
import { type ValidationRule } from './validation.js';
|
|
26
33
|
import { type CfRule } from './conditional-formats.js';
|
|
27
34
|
import { type AutoFilterState } from './auto-filter.js';
|
|
35
|
+
import { type CellTypeRegion } from './cell-types.js';
|
|
36
|
+
import { type GridSheetSpec, type SheetKind } from './sheet-kinds.js';
|
|
37
|
+
import { type OutlineState } from './outline.js';
|
|
28
38
|
/** Why the document changed. A listener gets every reason since its last call. */
|
|
29
39
|
export type SheetChangeReason = {
|
|
30
40
|
kind: 'cells';
|
|
@@ -46,6 +56,27 @@ export type SheetChangeReason = {
|
|
|
46
56
|
kind: 'conditional-formats';
|
|
47
57
|
} | {
|
|
48
58
|
kind: 'protection';
|
|
59
|
+
} | {
|
|
60
|
+
kind: 'page-setup';
|
|
61
|
+
} | {
|
|
62
|
+
kind: 'objects';
|
|
63
|
+
} | {
|
|
64
|
+
kind: 'sparklines';
|
|
65
|
+
} | {
|
|
66
|
+
kind: 'pivots';
|
|
67
|
+
} | {
|
|
68
|
+
kind: 'links';
|
|
69
|
+
} | {
|
|
70
|
+
kind: 'tables';
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The workbook's own parts rather than a sheet's: its defined names and
|
|
74
|
+
* its calculation settings. They belong to no sheet, so nothing keyed by
|
|
75
|
+
* sheet can carry them, and a listener that mirrors a document elsewhere
|
|
76
|
+
* has to hear about them separately.
|
|
77
|
+
*/
|
|
78
|
+
| {
|
|
79
|
+
kind: 'workbook';
|
|
49
80
|
} | {
|
|
50
81
|
kind: 'merges';
|
|
51
82
|
} | {
|
|
@@ -68,15 +99,48 @@ export type PerSheetState = {
|
|
|
68
99
|
rows: Set<number>;
|
|
69
100
|
cols: Set<number>;
|
|
70
101
|
};
|
|
102
|
+
/** Data > Group: the outline level of each row and column, and which
|
|
103
|
+
* summary lines are collapsed. Lines a collapsed group hides are kept
|
|
104
|
+
* apart from `hidden`, so expanding a group does not un-hide a row the
|
|
105
|
+
* user hid by hand. */
|
|
106
|
+
outline: {
|
|
107
|
+
rows: OutlineState;
|
|
108
|
+
cols: OutlineState;
|
|
109
|
+
};
|
|
71
110
|
freeze: FreezeState;
|
|
72
|
-
/** Cell comments
|
|
73
|
-
notes:
|
|
111
|
+
/** Cell comments keyed like the grid's `notes`: `r4` -> `B` -> a note's text or a thread. */
|
|
112
|
+
notes: CommentsMap;
|
|
74
113
|
protected: boolean;
|
|
114
|
+
/** What stays allowed while protected, and the ranges that take an edit anyway. */
|
|
115
|
+
protection: SheetProtection;
|
|
116
|
+
/** Page Layout: orientation, paper, margins, print area, title rows, gridlines, headings, scale. */
|
|
117
|
+
pageSetup: PageSetup;
|
|
118
|
+
/** Charts and pictures anchored over the cells, back to front. */
|
|
119
|
+
objects: SheetObject[];
|
|
120
|
+
sparklines: SparklineGroup[];
|
|
121
|
+
pivots: SheetPivot[];
|
|
122
|
+
/** Hyperlinks by cell, keyed like the comments: `r4` -> `B` -> the link. */
|
|
123
|
+
links: LinksMap;
|
|
124
|
+
/** Excel's Hide Sheet: the tab is not shown and the shortcuts skip it. */
|
|
125
|
+
sheetHidden: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* What this tab is: a cell grid, or a table bound to records.
|
|
128
|
+
*
|
|
129
|
+
* A `grid` sheet keeps its records in `grid` and projects them into the
|
|
130
|
+
* workbook's cells, so a formula on any other sheet reads it the way it
|
|
131
|
+
* reads a cell sheet. See `sheet-kinds.ts`.
|
|
132
|
+
*/
|
|
133
|
+
kind: SheetKind;
|
|
134
|
+
/** The records and columns of a `grid` sheet; absent on a cell sheet. */
|
|
135
|
+
grid?: GridSheetSpec;
|
|
75
136
|
merges: Rect[];
|
|
76
137
|
/** Data validation rules, in order; the last one covering a cell applies. */
|
|
77
138
|
validation: ValidationRule[];
|
|
78
139
|
/** Conditional formatting rules, in priority order: the first one decides. */
|
|
79
140
|
conditionalFormats: CfRule[];
|
|
141
|
+
/** Cells drawn as a control rather than as text: a checkbox, a button,
|
|
142
|
+
* a radio group. The cell's value stays the truth. */
|
|
143
|
+
cellTypes: CellTypeRegion[];
|
|
80
144
|
/** Excel's AutoFilter over a region, or null when the arrows are off. */
|
|
81
145
|
autoFilter: AutoFilterState | null;
|
|
82
146
|
/** The rows the AutoFilter hides right now; worked out, never saved. */
|
|
@@ -91,12 +155,37 @@ export type SheetStateEntry = {
|
|
|
91
155
|
rows: number[];
|
|
92
156
|
cols: number[];
|
|
93
157
|
};
|
|
158
|
+
/** Absent in documents saved before outlining existed. */
|
|
159
|
+
outline?: {
|
|
160
|
+
rows: OutlineState;
|
|
161
|
+
cols: OutlineState;
|
|
162
|
+
};
|
|
94
163
|
freeze: FreezeState;
|
|
95
|
-
|
|
164
|
+
/** `r4` -> `B` -> a note's text, or a thread with its author, replies and state. */
|
|
165
|
+
comments: CommentsMap;
|
|
96
166
|
protected: boolean;
|
|
167
|
+
/** Absent in documents saved before the allow list and edit ranges existed. */
|
|
168
|
+
protection?: SheetProtection;
|
|
169
|
+
/** Absent in documents saved before Page Layout existed. */
|
|
170
|
+
pageSetup?: PageSetup;
|
|
171
|
+
/** Absent in documents saved before objects existed. */
|
|
172
|
+
objects?: SheetObject[];
|
|
173
|
+
/** Absent in documents saved before sparklines existed. */
|
|
174
|
+
sparklines?: SparklineGroup[];
|
|
175
|
+
/** Absent in documents saved before pivots existed. */
|
|
176
|
+
pivots?: SheetPivot[];
|
|
177
|
+
/** Absent in documents saved before hyperlinks existed. */
|
|
178
|
+
links?: LinksMap;
|
|
179
|
+
/** Absent in documents saved before hidden sheets existed. */
|
|
180
|
+
sheetHidden?: boolean;
|
|
181
|
+
/** Absent in documents saved before sheet kinds existed; reads as 'cells'. */
|
|
182
|
+
kind?: SheetKind;
|
|
183
|
+
grid?: GridSheetSpec;
|
|
97
184
|
merges: Array<[number, number, number, number]>;
|
|
98
185
|
validation: ValidationRule[];
|
|
99
186
|
conditionalFormats: CfRule[];
|
|
187
|
+
/** Absent in documents saved before cell types existed. */
|
|
188
|
+
cellTypes?: CellTypeRegion[];
|
|
100
189
|
autoFilter: AutoFilterState | null;
|
|
101
190
|
};
|
|
102
191
|
/**
|
|
@@ -116,6 +205,12 @@ export type SheetDocument = {
|
|
|
116
205
|
has(name: string): boolean;
|
|
117
206
|
rename(from: string, to: string): void;
|
|
118
207
|
remove(name: string): void;
|
|
208
|
+
/**
|
|
209
|
+
* Excel's Move or Copy > Create a copy: a new sheet after `from` with
|
|
210
|
+
* its cells and everything this document keeps beside them, named `to`
|
|
211
|
+
* or "Name (2)". Returns the new name, or null when it could not.
|
|
212
|
+
*/
|
|
213
|
+
duplicate(from: string, to?: string): string | null;
|
|
119
214
|
/** The sheets that have state, in no particular order. */
|
|
120
215
|
names(): string[];
|
|
121
216
|
/**
|
|
@@ -135,6 +230,13 @@ export type SheetDocument = {
|
|
|
135
230
|
setState(state: SheetState): void;
|
|
136
231
|
/** Hear about changes, once per tick with every reason since the last call. */
|
|
137
232
|
subscribe(listener: (reasons: ReadonlyArray<SheetChangeReason>) => void): () => void;
|
|
233
|
+
/**
|
|
234
|
+
* Put back only the parts `entry` names, leaving the rest of the sheet as
|
|
235
|
+
* it is: what a delta from another user applies, and what a host that
|
|
236
|
+
* wants to set one feature calls. Reports the change, so the shell
|
|
237
|
+
* repaints; wrap it in `mute` where it should not.
|
|
238
|
+
*/
|
|
239
|
+
patch(name: string, entry: Partial<SheetStateEntry>): void;
|
|
138
240
|
/** Record a change. Coalesced per microtask; silent while muted. */
|
|
139
241
|
changed(reason: SheetChangeReason): void;
|
|
140
242
|
/** Run `fn` without reporting changes: restores and mount-time seeding. */
|
package/dist/sheet/document.js
CHANGED
|
@@ -20,29 +20,89 @@
|
|
|
20
20
|
import { createWorkbook } from './workbook.js';
|
|
21
21
|
import { createFormatStore } from './format-store.js';
|
|
22
22
|
import { lineShift, remapNotes, shiftRect } from './rects.js';
|
|
23
|
+
import { copyProtection, defaultProtection } from './protection.js';
|
|
24
|
+
import { copyPageSetup, defaultPageSetup, shiftPageSetup } from './page-setup.js';
|
|
25
|
+
import { copyObject, objectId, shiftObjects } from './objects.js';
|
|
26
|
+
import { copySparkline, shiftSparklines, sparklineId } from './sparklines.js';
|
|
27
|
+
import { copyPivot, pivotId, shiftPivots } from './pivot-range.js';
|
|
28
|
+
import { copyLinks, shiftLinks } from './links.js';
|
|
29
|
+
import { releaseFilteredRows } from './filter-files.js';
|
|
23
30
|
import { colToLetters, lettersToCol } from './address.js';
|
|
24
31
|
import { shiftValidation } from './validation.js';
|
|
25
32
|
import { shiftCf } from './conditional-formats.js';
|
|
26
33
|
import { shiftAutoFilter } from './auto-filter.js';
|
|
34
|
+
import { copyCellType, shiftCellTypes } from './cell-types.js';
|
|
35
|
+
import { copyGridSheet } from './sheet-kinds.js';
|
|
36
|
+
import { emptyOutline, shiftOutline } from './outline.js';
|
|
37
|
+
/** A deep copy of one axis's outline, absent reading as an empty one. */
|
|
38
|
+
const copyOutline = (o) => (o ? { levels: { ...o.levels }, collapsed: [...o.collapsed] } : emptyOutline());
|
|
39
|
+
/** Which change a patched part of a sheet counts as, so listeners hear it. */
|
|
40
|
+
function reasonsForEntry(entry) {
|
|
41
|
+
const out = [];
|
|
42
|
+
if (entry.formats !== undefined)
|
|
43
|
+
out.push({ kind: 'formats' });
|
|
44
|
+
if (entry.columnWidths !== undefined || entry.rowHeights !== undefined)
|
|
45
|
+
out.push({ kind: 'sizes' });
|
|
46
|
+
if (entry.hidden !== undefined || entry.sheetHidden !== undefined)
|
|
47
|
+
out.push({ kind: 'hidden' });
|
|
48
|
+
if (entry.freeze !== undefined)
|
|
49
|
+
out.push({ kind: 'freeze' });
|
|
50
|
+
if (entry.comments !== undefined)
|
|
51
|
+
out.push({ kind: 'comments' });
|
|
52
|
+
if (entry.protected !== undefined || entry.protection !== undefined)
|
|
53
|
+
out.push({ kind: 'protection' });
|
|
54
|
+
if (entry.pageSetup !== undefined)
|
|
55
|
+
out.push({ kind: 'page-setup' });
|
|
56
|
+
if (entry.objects !== undefined)
|
|
57
|
+
out.push({ kind: 'objects' });
|
|
58
|
+
if (entry.sparklines !== undefined)
|
|
59
|
+
out.push({ kind: 'sparklines' });
|
|
60
|
+
if (entry.pivots !== undefined)
|
|
61
|
+
out.push({ kind: 'pivots' });
|
|
62
|
+
if (entry.links !== undefined)
|
|
63
|
+
out.push({ kind: 'links' });
|
|
64
|
+
if (entry.merges !== undefined)
|
|
65
|
+
out.push({ kind: 'merges' });
|
|
66
|
+
if (entry.validation !== undefined)
|
|
67
|
+
out.push({ kind: 'validation' });
|
|
68
|
+
if (entry.conditionalFormats !== undefined)
|
|
69
|
+
out.push({ kind: 'conditional-formats' });
|
|
70
|
+
if (entry.autoFilter !== undefined)
|
|
71
|
+
out.push({ kind: 'filter' });
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
27
74
|
function emptySheetState() {
|
|
28
75
|
return {
|
|
29
76
|
formats: createFormatStore(),
|
|
30
77
|
widths: {},
|
|
31
78
|
heights: new Map(),
|
|
32
79
|
hidden: { rows: new Set(), cols: new Set() },
|
|
80
|
+
outline: { rows: emptyOutline(), cols: emptyOutline() },
|
|
33
81
|
freeze: { rows: 0, cols: 0 },
|
|
34
82
|
notes: {},
|
|
35
83
|
protected: false,
|
|
84
|
+
protection: defaultProtection(),
|
|
85
|
+
pageSetup: defaultPageSetup(),
|
|
86
|
+
objects: [],
|
|
87
|
+
sparklines: [],
|
|
88
|
+
pivots: [],
|
|
89
|
+
links: {},
|
|
90
|
+
sheetHidden: false,
|
|
91
|
+
kind: 'cells',
|
|
36
92
|
merges: [],
|
|
37
93
|
validation: [],
|
|
38
94
|
conditionalFormats: [],
|
|
95
|
+
cellTypes: [],
|
|
39
96
|
autoFilter: null,
|
|
40
97
|
filterHidden: new Set(),
|
|
41
98
|
};
|
|
42
99
|
}
|
|
43
100
|
export function createSheetDocument(init = {}) {
|
|
44
101
|
const workbook = init.workbook ??
|
|
45
|
-
createWorkbook(init.state ? init.state.workbook.sheets.map((s) => ({ name: s.name, cells: s.cells })) : (init.sheets ? [...init.sheets] : [{ name: 'Sheet1', cells: [] }])
|
|
102
|
+
createWorkbook(init.state ? init.state.workbook.sheets.map((s) => ({ name: s.name, cells: s.cells })) : (init.sheets ? [...init.sheets] : [{ name: 'Sheet1', cells: [] }]), {
|
|
103
|
+
...(init.state?.workbook.tables?.length ? { tables: init.state.workbook.tables } : {}),
|
|
104
|
+
...(init.state?.workbook.iteration ? { iteration: init.state.workbook.iteration } : {}),
|
|
105
|
+
});
|
|
46
106
|
const entries = new Map();
|
|
47
107
|
const listeners = new Set();
|
|
48
108
|
let pending = [];
|
|
@@ -77,29 +137,121 @@ export function createSheetDocument(init = {}) {
|
|
|
77
137
|
scheduled = true;
|
|
78
138
|
queueMicrotask(flush);
|
|
79
139
|
}
|
|
140
|
+
/** A row of comments copied deep enough that a saved thread is not the live one. */
|
|
141
|
+
function copyLine(line) {
|
|
142
|
+
const out = {};
|
|
143
|
+
for (const [c, v] of Object.entries(line))
|
|
144
|
+
out[c] = typeof v === 'string' ? v : { ...v, ...(v.replies ? { replies: v.replies.map((r) => ({ ...r })) } : {}) };
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
80
147
|
function serializeEntry(state) {
|
|
81
148
|
return {
|
|
82
149
|
formats: state.formats.serialize(),
|
|
83
150
|
columnWidths: { ...state.widths },
|
|
84
151
|
rowHeights: [...state.heights].map(([r, h]) => [r, h]),
|
|
85
152
|
hidden: { rows: [...state.hidden.rows], cols: [...state.hidden.cols] },
|
|
153
|
+
outline: { rows: copyOutline(state.outline.rows), cols: copyOutline(state.outline.cols) },
|
|
86
154
|
freeze: { ...state.freeze },
|
|
87
|
-
comments: Object.fromEntries(Object.entries(state.notes).map(([r, line]) => [r,
|
|
155
|
+
comments: Object.fromEntries(Object.entries(state.notes).map(([r, line]) => [r, copyLine(line)])),
|
|
88
156
|
protected: state.protected,
|
|
157
|
+
protection: copyProtection(state.protection),
|
|
158
|
+
pageSetup: copyPageSetup(state.pageSetup),
|
|
159
|
+
objects: state.objects.map(copyObject),
|
|
160
|
+
sparklines: state.sparklines.map(copySparkline),
|
|
161
|
+
pivots: state.pivots.map(copyPivot),
|
|
162
|
+
links: copyLinks(state.links),
|
|
163
|
+
sheetHidden: state.sheetHidden,
|
|
164
|
+
kind: state.kind,
|
|
165
|
+
...(state.grid ? { grid: copyGridSheet(state.grid) } : {}),
|
|
89
166
|
merges: state.merges.map(([r1, c1, r2, c2]) => [r1, c1, r2, c2]),
|
|
90
167
|
validation: state.validation.map((rule) => ({ ...rule, rects: rule.rects.map((r) => [...r]), alert: { ...rule.alert } })),
|
|
91
168
|
conditionalFormats: state.conditionalFormats.map((rule) => ({ ...rule, rects: rule.rects.map((r) => [...r]) })),
|
|
169
|
+
cellTypes: state.cellTypes.map(copyCellType),
|
|
92
170
|
autoFilter: state.autoFilter ? { range: [...state.autoFilter.range], filters: { ...state.autoFilter.filters } } : null,
|
|
93
171
|
};
|
|
94
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Put back only the parts an entry names, leaving the rest as they are.
|
|
175
|
+
* `hydrateEntry` below is the whole-sheet version, which resets what is
|
|
176
|
+
* absent to its default; this one is what a delta applies, since a delta
|
|
177
|
+
* carries the one feature that changed.
|
|
178
|
+
*/
|
|
179
|
+
function patchEntry(state, entry) {
|
|
180
|
+
if (entry.formats !== undefined)
|
|
181
|
+
state.formats.hydrate(entry.formats);
|
|
182
|
+
if (entry.columnWidths !== undefined)
|
|
183
|
+
state.widths = { ...entry.columnWidths };
|
|
184
|
+
if (entry.rowHeights !== undefined)
|
|
185
|
+
state.heights = new Map(entry.rowHeights);
|
|
186
|
+
if (entry.hidden !== undefined)
|
|
187
|
+
state.hidden = { rows: new Set(entry.hidden.rows ?? []), cols: new Set(entry.hidden.cols ?? []) };
|
|
188
|
+
if (entry.outline !== undefined)
|
|
189
|
+
state.outline = { rows: copyOutline(entry.outline.rows), cols: copyOutline(entry.outline.cols) };
|
|
190
|
+
if (entry.freeze !== undefined)
|
|
191
|
+
state.freeze = { rows: entry.freeze.rows ?? 0, cols: entry.freeze.cols ?? 0 };
|
|
192
|
+
if (entry.comments !== undefined)
|
|
193
|
+
state.notes = Object.fromEntries(Object.entries(entry.comments).map(([r, line]) => [r, copyLine(line)]));
|
|
194
|
+
if (entry.protected !== undefined)
|
|
195
|
+
state.protected = entry.protected;
|
|
196
|
+
if (entry.protection !== undefined)
|
|
197
|
+
state.protection = copyProtection({ allow: entry.protection.allow ?? {}, ranges: entry.protection.ranges ?? [] });
|
|
198
|
+
if (entry.pageSetup !== undefined)
|
|
199
|
+
state.pageSetup = copyPageSetup({ ...defaultPageSetup(), ...entry.pageSetup });
|
|
200
|
+
if (entry.objects !== undefined)
|
|
201
|
+
state.objects = entry.objects.map(copyObject);
|
|
202
|
+
if (entry.sparklines !== undefined)
|
|
203
|
+
state.sparklines = entry.sparklines.map(copySparkline);
|
|
204
|
+
if (entry.pivots !== undefined)
|
|
205
|
+
state.pivots = entry.pivots.map(copyPivot);
|
|
206
|
+
if (entry.links !== undefined)
|
|
207
|
+
state.links = copyLinks(entry.links);
|
|
208
|
+
if (entry.sheetHidden !== undefined)
|
|
209
|
+
state.sheetHidden = entry.sheetHidden;
|
|
210
|
+
if (entry.kind !== undefined)
|
|
211
|
+
state.kind = entry.kind;
|
|
212
|
+
if (entry.grid !== undefined)
|
|
213
|
+
state.grid = copyGridSheet(entry.grid);
|
|
214
|
+
if (entry.merges !== undefined)
|
|
215
|
+
state.merges = entry.merges.map(([r1, c1, r2, c2]) => [r1, c1, r2, c2]);
|
|
216
|
+
if (entry.validation !== undefined) {
|
|
217
|
+
state.validation = entry.validation.map((rule) => ({
|
|
218
|
+
...rule,
|
|
219
|
+
rects: rule.rects.map(([r1, c1, r2, c2]) => [r1, c1, r2, c2]),
|
|
220
|
+
alert: { ...rule.alert },
|
|
221
|
+
}));
|
|
222
|
+
}
|
|
223
|
+
if (entry.conditionalFormats !== undefined) {
|
|
224
|
+
state.conditionalFormats = entry.conditionalFormats.map((rule) => ({
|
|
225
|
+
...rule,
|
|
226
|
+
rects: rule.rects.map(([r1, c1, r2, c2]) => [r1, c1, r2, c2]),
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
if (entry.cellTypes !== undefined)
|
|
230
|
+
state.cellTypes = entry.cellTypes.map(copyCellType);
|
|
231
|
+
if (entry.autoFilter !== undefined) {
|
|
232
|
+
const af = entry.autoFilter;
|
|
233
|
+
state.autoFilter = af ? { range: [af.range[0], af.range[1], af.range[2], af.range[3]], filters: { ...af.filters } } : null;
|
|
234
|
+
state.filterHidden = new Set();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
95
237
|
function hydrateEntry(state, entry) {
|
|
96
238
|
state.formats.hydrate(entry.formats ?? {});
|
|
97
239
|
state.widths = { ...(entry.columnWidths ?? {}) };
|
|
98
240
|
state.heights = new Map(entry.rowHeights ?? []);
|
|
99
241
|
state.hidden = { rows: new Set(entry.hidden?.rows ?? []), cols: new Set(entry.hidden?.cols ?? []) };
|
|
242
|
+
state.outline = { rows: copyOutline(entry.outline?.rows), cols: copyOutline(entry.outline?.cols) };
|
|
100
243
|
state.freeze = { rows: entry.freeze?.rows ?? 0, cols: entry.freeze?.cols ?? 0 };
|
|
101
|
-
state.notes = Object.fromEntries(Object.entries(entry.comments ?? {}).map(([r, line]) => [r,
|
|
244
|
+
state.notes = Object.fromEntries(Object.entries(entry.comments ?? {}).map(([r, line]) => [r, copyLine(line)]));
|
|
102
245
|
state.protected = entry.protected ?? false;
|
|
246
|
+
state.protection = entry.protection ? copyProtection({ allow: entry.protection.allow ?? {}, ranges: entry.protection.ranges ?? [] }) : defaultProtection();
|
|
247
|
+
state.pageSetup = entry.pageSetup ? copyPageSetup({ ...defaultPageSetup(), ...entry.pageSetup }) : defaultPageSetup();
|
|
248
|
+
state.objects = (entry.objects ?? []).map(copyObject);
|
|
249
|
+
state.sparklines = (entry.sparklines ?? []).map(copySparkline);
|
|
250
|
+
state.pivots = (entry.pivots ?? []).map(copyPivot);
|
|
251
|
+
state.links = copyLinks(entry.links ?? {});
|
|
252
|
+
state.sheetHidden = entry.sheetHidden ?? false;
|
|
253
|
+
state.kind = entry.kind ?? 'cells';
|
|
254
|
+
state.grid = entry.grid ? copyGridSheet(entry.grid) : undefined;
|
|
103
255
|
state.merges = (entry.merges ?? []).map(([r1, c1, r2, c2]) => [r1, c1, r2, c2]);
|
|
104
256
|
state.validation = (entry.validation ?? []).map((rule) => ({
|
|
105
257
|
...rule,
|
|
@@ -110,6 +262,7 @@ export function createSheetDocument(init = {}) {
|
|
|
110
262
|
...rule,
|
|
111
263
|
rects: rule.rects.map(([r1, c1, r2, c2]) => [r1, c1, r2, c2]),
|
|
112
264
|
}));
|
|
265
|
+
state.cellTypes = (entry.cellTypes ?? []).map(copyCellType);
|
|
113
266
|
const af = entry.autoFilter;
|
|
114
267
|
state.autoFilter = af ? { range: [af.range[0], af.range[1], af.range[2], af.range[3]], filters: { ...af.filters } } : null;
|
|
115
268
|
state.filterHidden = new Set();
|
|
@@ -117,6 +270,11 @@ export function createSheetDocument(init = {}) {
|
|
|
117
270
|
const document = {
|
|
118
271
|
workbook,
|
|
119
272
|
get,
|
|
273
|
+
patch(name, entry) {
|
|
274
|
+
patchEntry(get(name), entry);
|
|
275
|
+
for (const reason of reasonsForEntry(entry))
|
|
276
|
+
changed(reason);
|
|
277
|
+
},
|
|
120
278
|
has: (name) => entries.has(key(name)),
|
|
121
279
|
rename(from, to) {
|
|
122
280
|
const moved = entries.get(key(from));
|
|
@@ -127,6 +285,24 @@ export function createSheetDocument(init = {}) {
|
|
|
127
285
|
remove(name) {
|
|
128
286
|
entries.delete(key(name));
|
|
129
287
|
},
|
|
288
|
+
duplicate(from, to) {
|
|
289
|
+
const made = workbook.copySheet(from, to);
|
|
290
|
+
if (made === null)
|
|
291
|
+
return null;
|
|
292
|
+
// Through the JSON shape, so nothing is shared between the two.
|
|
293
|
+
const copy = JSON.parse(JSON.stringify(serializeEntry(get(from))));
|
|
294
|
+
copy.sheetHidden = false;
|
|
295
|
+
// The copy's chart, picture, sparkline and pivot are its own, so they
|
|
296
|
+
// get their own ids the way Excel's Move or Copy does. Sharing them
|
|
297
|
+
// would mean a shell that tracks the selected object by id following
|
|
298
|
+
// the copy's one across a sheet switch, and deleting it there.
|
|
299
|
+
copy.objects = copy.objects?.map((object) => ({ ...object, id: objectId() }));
|
|
300
|
+
copy.sparklines = copy.sparklines?.map((group) => ({ ...group, id: sparklineId() }));
|
|
301
|
+
copy.pivots = copy.pivots?.map((pivot) => ({ ...pivot, id: pivotId() }));
|
|
302
|
+
hydrateEntry(get(made), copy);
|
|
303
|
+
changed({ kind: 'sheets' });
|
|
304
|
+
return made;
|
|
305
|
+
},
|
|
130
306
|
names: () => [...entries.keys()],
|
|
131
307
|
shift(name, edit) {
|
|
132
308
|
const state = get(name);
|
|
@@ -175,12 +351,25 @@ export function createSheetDocument(init = {}) {
|
|
|
175
351
|
hiddenCols.add(next);
|
|
176
352
|
}
|
|
177
353
|
state.hidden = { rows: state.hidden.rows, cols: hiddenCols };
|
|
354
|
+
state.outline = { rows: state.outline.rows, cols: shiftOutline(state.outline.cols, edit.at, edit.count * (edit.kind === 'deleteCols' ? -1 : 1)) };
|
|
178
355
|
state.notes = remapNotes(state.notes, 'cols', shift);
|
|
179
356
|
}
|
|
180
357
|
state.merges = state.merges.map((m) => shiftRect(m, edit)).filter((m) => m !== null);
|
|
181
358
|
state.validation = shiftValidation(state.validation, edit);
|
|
182
359
|
state.conditionalFormats = shiftCf(state.conditionalFormats, edit);
|
|
360
|
+
state.cellTypes = shiftCellTypes(state.cellTypes, edit);
|
|
183
361
|
state.autoFilter = shiftAutoFilter(state.autoFilter, edit);
|
|
362
|
+
state.pageSetup = shiftPageSetup(state.pageSetup, edit);
|
|
363
|
+
state.objects = shiftObjects(state.objects, edit);
|
|
364
|
+
state.sparklines = shiftSparklines(state.sparklines, edit);
|
|
365
|
+
state.pivots = shiftPivots(state.pivots, edit);
|
|
366
|
+
state.links = shiftLinks(state.links, edit);
|
|
367
|
+
state.protection = {
|
|
368
|
+
allow: state.protection.allow,
|
|
369
|
+
ranges: state.protection.ranges
|
|
370
|
+
.map((range) => ({ ...range, rects: range.rects.map((r) => shiftRect(r, edit)).filter((r) => r !== null) }))
|
|
371
|
+
.filter((range) => range.rects.length > 0),
|
|
372
|
+
};
|
|
184
373
|
},
|
|
185
374
|
getState() {
|
|
186
375
|
const sheets = {};
|
|
@@ -220,6 +409,14 @@ export function createSheetDocument(init = {}) {
|
|
|
220
409
|
}
|
|
221
410
|
}
|
|
222
411
|
workbook.names.hydrate(state.workbook.names ?? {});
|
|
412
|
+
// Tables are workbook-wide, and the registry is what a structured
|
|
413
|
+
// reference resolves through: put back exactly the saved set.
|
|
414
|
+
workbook.tables.clear();
|
|
415
|
+
for (const table of state.workbook.tables ?? [])
|
|
416
|
+
workbook.tables.define({ ...table });
|
|
417
|
+
// Iterative calculation is workbook-wide too, and absent in a saved
|
|
418
|
+
// document that never turned it on, which means off.
|
|
419
|
+
workbook.setIteration(state.workbook.iteration ?? { enabled: false });
|
|
223
420
|
if (workbook.sheets.some((s) => key(s) === key(state.workbook.active)))
|
|
224
421
|
workbook.setActive(state.workbook.active);
|
|
225
422
|
// Entries are hydrated in place, never replaced: a format store the
|
|
@@ -231,6 +428,8 @@ export function createSheetDocument(init = {}) {
|
|
|
231
428
|
entries.delete(name);
|
|
232
429
|
for (const name of workbook.sheets)
|
|
233
430
|
hydrateEntry(get(name), state.sheets?.[name] ?? {});
|
|
431
|
+
for (const name of workbook.sheets)
|
|
432
|
+
releaseFilteredRows(document, name);
|
|
234
433
|
});
|
|
235
434
|
changed({ kind: 'restore' });
|
|
236
435
|
},
|
|
@@ -258,6 +457,8 @@ export function createSheetDocument(init = {}) {
|
|
|
258
457
|
workbook.setActive(init.state.workbook.active);
|
|
259
458
|
for (const [name, entry] of Object.entries(init.state.sheets ?? {}))
|
|
260
459
|
hydrateEntry(get(name), entry);
|
|
460
|
+
for (const name of workbook.sheets)
|
|
461
|
+
releaseFilteredRows(document, name);
|
|
261
462
|
});
|
|
262
463
|
}
|
|
263
464
|
return document;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The seam between the workbook and whatever works a formula out.
|
|
3
|
+
*
|
|
4
|
+
* The built-in engine (the tokenizer, parser and evaluator beside this
|
|
5
|
+
* file) is the one the sheet ships with and the one it is tested against.
|
|
6
|
+
* The seam is here for an application that has its own evaluator to put
|
|
7
|
+
* behind the same sheet: `createWorkbook(sheets, { engine: mine })`.
|
|
8
|
+
*
|
|
9
|
+
* What an engine is asked for is narrow on purpose: a formula's value in
|
|
10
|
+
* a cell, and the grid it spills when it has one. The workbook keeps
|
|
11
|
+
* everything else, because none of it is the engine's to decide. The
|
|
12
|
+
* dependency graph, the volatile set, the value cache, cycle detection
|
|
13
|
+
* and the spill ranges are all read off the reference grammar, which is
|
|
14
|
+
* Excel's whatever evaluates it, so they stay correct for any engine and
|
|
15
|
+
* an engine cannot get them wrong.
|
|
16
|
+
*
|
|
17
|
+
* `load` and `write` are the lifecycle an engine with a copy of the cells
|
|
18
|
+
* needs: `load` when the workbook is built and whenever its cells change
|
|
19
|
+
* wholesale (a structural edit, a sheet added or renamed, a restore),
|
|
20
|
+
* `write` on a single cell. An engine that reads through `host` on demand,
|
|
21
|
+
* as the built-in does, leaves both off.
|
|
22
|
+
*/
|
|
23
|
+
import type { CellValue, Node } from './ast.js';
|
|
24
|
+
import type { EvalContext } from './evaluate.js';
|
|
25
|
+
import type { SheetData } from './workbook.js';
|
|
26
|
+
/** Where a formula sits. */
|
|
27
|
+
export type SheetEngineCell = {
|
|
28
|
+
sheet: string;
|
|
29
|
+
row: number;
|
|
30
|
+
col: number;
|
|
31
|
+
};
|
|
32
|
+
export type SheetEngineHost = {
|
|
33
|
+
/**
|
|
34
|
+
* The context the built-in evaluator uses for this cell: `resolve` reads
|
|
35
|
+
* through the workbook's cache and cycle detection, so an engine that
|
|
36
|
+
* wants a precedent's value asks here rather than reading raw text.
|
|
37
|
+
*/
|
|
38
|
+
context: EvalContext;
|
|
39
|
+
/** The workbook's parse cache: one parse per distinct formula text, null when it does not parse. */
|
|
40
|
+
parse(text: string): Node | null;
|
|
41
|
+
};
|
|
42
|
+
export type SheetEngineResult = {
|
|
43
|
+
value: CellValue;
|
|
44
|
+
/**
|
|
45
|
+
* The grid the formula spills, or null / absent for a plain value. The
|
|
46
|
+
* workbook lays it over the cells below and to the right, refuses it
|
|
47
|
+
* with `#SPILL!` where something is in the way, and moves it with an
|
|
48
|
+
* insert or delete.
|
|
49
|
+
*/
|
|
50
|
+
spill?: CellValue[][] | null;
|
|
51
|
+
};
|
|
52
|
+
export type SheetEngine = {
|
|
53
|
+
/** For the docs and an error message; the built-in is `'builtin'`. */
|
|
54
|
+
name?: string;
|
|
55
|
+
/** Every sheet's raw text, at creation and after a wholesale change. */
|
|
56
|
+
load?(sheets: ReadonlyArray<SheetData>): void;
|
|
57
|
+
/** One cell's raw text changed. */
|
|
58
|
+
write?(sheet: string, row: number, col: number, text: string): void;
|
|
59
|
+
/** What the formula is worth here. `text` keeps its leading `=`. */
|
|
60
|
+
evaluate(text: string, at: SheetEngineCell, host: SheetEngineHost): SheetEngineResult;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* The engine the sheet ships with: the parser and evaluator in this
|
|
64
|
+
* folder, which read the workbook's own cells through the host's context
|
|
65
|
+
* and so need no copy of anything.
|
|
66
|
+
*/
|
|
67
|
+
export declare function builtinEngine(): SheetEngine;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { evaluate, evaluateSpill } from './evaluate.js';
|
|
2
|
+
/**
|
|
3
|
+
* The engine the sheet ships with: the parser and evaluator in this
|
|
4
|
+
* folder, which read the workbook's own cells through the host's context
|
|
5
|
+
* and so need no copy of anything.
|
|
6
|
+
*/
|
|
7
|
+
export function builtinEngine() {
|
|
8
|
+
return {
|
|
9
|
+
name: 'builtin',
|
|
10
|
+
evaluate(text, _at, host) {
|
|
11
|
+
const ast = host.parse(text);
|
|
12
|
+
if (!ast)
|
|
13
|
+
return { value: { error: '#PARSE!' } };
|
|
14
|
+
const value = evaluate(ast, host.context);
|
|
15
|
+
const spill = typeof value === 'object' && value !== null && 'error' in value ? null : evaluateSpill(ast, host.context);
|
|
16
|
+
return { value, spill };
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|