@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.
- package/README.md +95 -95
- package/dist/ExpressionEditorHarness.svelte.d.ts +2 -2
- package/dist/SvAdvancedFilter.svelte.d.ts +2 -2
- package/dist/SvAlertRuleEditor.svelte.d.ts +2 -2
- package/dist/SvAlertsManager.svelte.d.ts +3 -3
- package/dist/SvAlertsPanel.svelte.d.ts +1 -1
- package/dist/SvAuthGate.svelte +115 -115
- package/dist/SvAuthGate.svelte.d.ts +1 -1
- package/dist/SvBoard.svelte.d.ts +1 -1
- package/dist/SvExportMenu.svelte +553 -553
- package/dist/SvExportMenu.svelte.d.ts +2 -2
- package/dist/SvExpressionEditor.svelte.d.ts +2 -2
- package/dist/SvFileInput.svelte +113 -113
- package/dist/SvFormulaBar.svelte +606 -0
- package/dist/SvFormulaBar.svelte.d.ts +62 -0
- package/dist/SvGridAlerts.svelte.d.ts +2 -2
- package/dist/SvGridBoard.svelte +2358 -2358
- package/dist/SvGridBulkEditDrawer.svelte.d.ts +1 -1
- package/dist/SvGridEditPanel.svelte +1157 -1157
- package/dist/SvGridEditPanel.svelte.d.ts +3 -3
- package/dist/SvGridMasterDetail.svelte +116 -116
- package/dist/SvGridMasterDetail.svelte.d.ts +1 -1
- package/dist/SvGridScheduler.svelte +5358 -5358
- package/dist/SvImportDialog.svelte +1020 -1020
- package/dist/SvImportDialog.svelte.d.ts +2 -2
- package/dist/SvLookupInput.svelte +180 -180
- package/dist/SvLookupInput.svelte.d.ts +1 -1
- package/dist/SvPivotDesigner.svelte +2041 -1990
- package/dist/SvPivotDesigner.svelte.d.ts +2 -2
- package/dist/SvRecordDetail.svelte.d.ts +1 -1
- package/dist/SvRibbonIcon.svelte +46 -0
- package/dist/SvRibbonIcon.svelte.d.ts +17 -0
- package/dist/SvSchedule.svelte.d.ts +1 -1
- package/dist/SvSchemaChart.svelte +236 -234
- package/dist/SvSchemaChart.svelte.d.ts +2 -2
- package/dist/SvSchemaDashboard.svelte +130 -130
- package/dist/SvSchemaDashboard.svelte.d.ts +3 -3
- package/dist/SvSheet.svelte +4114 -0
- package/dist/SvSheet.svelte.d.ts +142 -0
- package/dist/SvSheetComment.svelte +98 -0
- package/dist/SvSheetComment.svelte.d.ts +22 -0
- package/dist/SvSheetConditionalFormat.svelte +162 -0
- package/dist/SvSheetConditionalFormat.svelte.d.ts +14 -0
- package/dist/SvSheetDataValidation.svelte +249 -0
- package/dist/SvSheetDataValidation.svelte.d.ts +14 -0
- package/dist/SvSheetFilterMenu.svelte +217 -0
- package/dist/SvSheetFilterMenu.svelte.d.ts +17 -0
- package/dist/SvSheetFindReplace.svelte +132 -0
- package/dist/SvSheetFindReplace.svelte.d.ts +10 -0
- package/dist/SvSheetFormatCells.svelte +421 -0
- package/dist/SvSheetFormatCells.svelte.d.ts +17 -0
- package/dist/SvSheetGoalSeek.svelte +144 -0
- package/dist/SvSheetGoalSeek.svelte.d.ts +12 -0
- package/dist/SvSheetInsertFunction.svelte +147 -0
- package/dist/SvSheetInsertFunction.svelte.d.ts +8 -0
- package/dist/SvSheetListPicker.svelte +89 -0
- package/dist/SvSheetListPicker.svelte.d.ts +16 -0
- package/dist/SvSheetManageRules.svelte +185 -0
- package/dist/SvSheetManageRules.svelte.d.ts +16 -0
- package/dist/SvSheetNameManager.svelte +225 -0
- package/dist/SvSheetNameManager.svelte.d.ts +11 -0
- package/dist/SvSheetPasteSpecial.svelte +105 -0
- package/dist/SvSheetPasteSpecial.svelte.d.ts +12 -0
- package/dist/SvSheetRemoveDuplicates.svelte +149 -0
- package/dist/SvSheetRemoveDuplicates.svelte.d.ts +12 -0
- package/dist/SvSheetRibbon.svelte +1201 -0
- package/dist/SvSheetRibbon.svelte.d.ts +34 -0
- package/dist/SvSheetSizeDialog.svelte +58 -0
- package/dist/SvSheetSizeDialog.svelte.d.ts +11 -0
- package/dist/SvSheetTabs.svelte +441 -0
- package/dist/SvSheetTabs.svelte.d.ts +36 -0
- package/dist/SvSheetTabs.test-harness.svelte.d.ts +17 -0
- package/dist/SvSheetTabs.test-harness.svelte.js +22 -0
- package/dist/SvSheetTextToColumns.svelte +172 -0
- package/dist/SvSheetTextToColumns.svelte.d.ts +13 -0
- package/dist/SvSheetValidationAlert.svelte +83 -0
- package/dist/SvSheetValidationAlert.svelte.d.ts +15 -0
- package/dist/advanced-filter/expr-columns-from-grid.d.ts +1 -1
- package/dist/advanced-filter-enable.js +3 -3
- package/dist/alerts/alert-engine-attach.d.ts +2 -2
- package/dist/alerts/alert-engine-attach.js +3 -3
- package/dist/alerts/alert-engine.d.ts +1 -1
- package/dist/alerts/alert-engine.js +2 -2
- package/dist/alerts/alert-formats.d.ts +1 -1
- package/dist/alerts/alert-formats.js +1 -1
- package/dist/alerts/alert-observer.d.ts +3 -3
- package/dist/alerts/alert-observer.js +1 -1
- package/dist/alerts/alert-storage.d.ts +1 -1
- package/dist/alerts/alert-store.svelte.d.ts +1 -1
- package/dist/alerts/alert-types.d.ts +2 -2
- package/dist/alerts.js +2 -2
- package/dist/board.js +2 -2
- package/dist/cdn/svgrid-enterprise.svelte-external.js +19046 -5428
- package/dist/designer/assets/GridMenus-BlsvL_aU.js +8 -0
- package/dist/designer/assets/SvChartMenu-BYO9cYdy.css +1 -0
- package/dist/designer/assets/SvChartMenu-D9hEeHar.js +1 -0
- package/dist/designer/assets/SvDateRangeInput-BBRzrQeg.js +1 -0
- package/dist/designer/assets/SvDateRangeInput-C0iCCZ8o.css +1 -0
- package/dist/designer/assets/SvDateTimePicker-DARvKUL2.js +1 -0
- package/dist/designer/assets/SvDateTimePicker-DPv09DIT.css +1 -0
- package/dist/designer/assets/{preload-helper-CG0n22O7.js → SvGrid.helpers-BgT-gnCo.js} +1 -1
- package/dist/designer/assets/SvGridCellEditor-C7uQXYds.js +4 -0
- package/dist/designer/assets/SvGridChart-B8j1SSy3.js +3 -0
- package/dist/designer/assets/SvGridChart-BgLuPO7I.css +1 -0
- package/dist/designer/assets/SvGridChartBuilder-08YWWeqY.css +1 -0
- package/dist/designer/assets/SvGridChartBuilder-kvyIU_Rl.js +1 -0
- package/dist/designer/assets/SvGridChartPanel-4Pc8y5yO.css +1 -0
- package/dist/designer/assets/SvGridChartPanel-pT6ITc2P.js +4 -0
- package/dist/designer/assets/SvGridChartView-7msfnWZT.css +1 -0
- package/dist/designer/assets/SvGridChartView-bg281UA1.js +1 -0
- package/dist/designer/assets/SvGridDropdown-Bb3HH2Aj.js +1 -0
- package/dist/designer/assets/SvGridDropdown-CcidB3rm.css +1 -0
- package/dist/designer/assets/SvListBox-BDS66lmZ.js +110 -0
- package/dist/designer/assets/SvListBox-BXfyqy4a.css +1 -0
- package/dist/designer/assets/SvMenuList-DJ47ba1h.css +1 -0
- package/dist/designer/assets/SvMenuList-Dgq2D5VN.js +1 -0
- package/dist/designer/assets/SvTabs-DKmwb5p1.css +1 -0
- package/dist/designer/assets/SvTabs-UFCMTHXS.js +1 -0
- package/dist/designer/assets/cell-formatting-wr5wm7US.js +1 -0
- package/dist/designer/assets/chart-cIPUsbM5.js +1 -0
- package/dist/designer/assets/chart-export-B6bkQ3X8.js +11 -0
- package/dist/designer/assets/chart-export-pdf-BbA28-gt.js +11 -0
- package/dist/designer/assets/chart-panel-messages-DtTxpBUU.js +1 -0
- package/dist/designer/assets/chart-summary-Czu_5epb.js +1 -0
- package/dist/designer/assets/chart-trend-D5I5VEe8.js +1 -0
- package/dist/designer/assets/chart-validate-BMqM-qkF.js +1 -0
- package/dist/designer/assets/column-resize-BYDzR1Ve.js +1 -0
- package/dist/designer/assets/date-format-B8JbEtIG.js +1 -0
- package/dist/designer/assets/date-format-DKS-z0xS.css +1 -0
- package/dist/designer/assets/editor-contract-Bpoa7A5g.js +1 -0
- package/dist/designer/assets/export-format-D-eP4b2l.js +6 -0
- package/dist/designer/assets/focus-trap-CAreAhlU.js +1 -0
- package/dist/designer/assets/index-CMFgAoVV.css +1 -0
- package/dist/designer/assets/{index-zUBix-JQ.js → index-DwU7CAMm.js} +2985 -141
- package/dist/designer/assets/list-option-BP_dWS66.js +1 -0
- package/dist/designer/assets/preload-helper-HclGiUj8.js +1 -0
- package/dist/designer/assets/row-resize-DLktcqUK.js +1 -0
- package/dist/designer/assets/src-CITpcm6b.js +1 -0
- package/dist/designer/assets/src-EdI3Xqds.js +58 -0
- package/dist/designer/index.html +32 -23
- package/dist/export-conditional.d.ts +1 -1
- package/dist/export-pdf.d.ts +89 -0
- package/dist/export-pdf.js +130 -0
- package/dist/export-print.js +19 -19
- package/dist/export-xls.d.ts +2 -2
- package/dist/export.d.ts +2 -2
- package/dist/export.js +23 -16
- package/dist/expressions/builder-tree.d.ts +2 -2
- package/dist/expressions/builder-tree.js +1 -1
- package/dist/expressions/compile.d.ts +1 -1
- package/dist/import.js +1 -1
- package/dist/index.d.ts +116 -53
- package/dist/index.js +117 -50
- package/dist/install.d.ts +4 -4
- package/dist/install.js +16 -11
- package/dist/license.d.ts +3 -2
- package/dist/license.js +9 -4
- package/dist/node/studio.js +187 -116
- package/dist/pivot-chart.d.ts +26 -2
- package/dist/pivot-chart.js +25 -69
- package/dist/pivot-designer.d.ts +1 -1
- package/dist/pivot-enable.js +3 -3
- package/dist/print.d.ts +1 -1
- package/dist/print.js +4 -4
- package/dist/scheduler-config.d.ts +5 -5
- package/dist/scheduler-freebusy.d.ts +1 -1
- package/dist/scheduler-freebusy.js +1 -1
- package/dist/scheduler.js +2 -2
- package/dist/schema-designer.d.ts +1 -1
- package/dist/schema-designer.js +2 -2
- package/dist/selection-bar.js +2 -2
- package/dist/sheet/address.d.ts +43 -0
- package/dist/sheet/address.js +81 -0
- package/dist/sheet/ast.d.ts +94 -0
- package/dist/sheet/ast.js +56 -0
- package/dist/sheet/auto-filter.d.ts +66 -0
- package/dist/sheet/auto-filter.js +147 -0
- package/dist/sheet/autocomplete.d.ts +42 -0
- package/dist/sheet/autocomplete.js +162 -0
- package/dist/sheet/coerce.d.ts +31 -0
- package/dist/sheet/coerce.js +122 -0
- package/dist/sheet/commands.d.ts +89 -0
- package/dist/sheet/commands.js +230 -0
- package/dist/sheet/comments.d.ts +29 -0
- package/dist/sheet/comments.js +73 -0
- package/dist/sheet/conditional-formats.d.ts +144 -0
- package/dist/sheet/conditional-formats.js +316 -0
- package/dist/sheet/deps.d.ts +60 -0
- package/dist/sheet/deps.js +199 -0
- package/dist/sheet/document.d.ts +150 -0
- package/dist/sheet/document.js +264 -0
- package/dist/sheet/edit-keys.d.ts +14 -0
- package/dist/sheet/edit-keys.js +40 -0
- package/dist/sheet/entry.d.ts +31 -0
- package/dist/sheet/entry.js +76 -0
- package/dist/sheet/evaluate.d.ts +61 -0
- package/dist/sheet/evaluate.js +337 -0
- package/dist/sheet/find-replace.d.ts +62 -0
- package/dist/sheet/find-replace.js +152 -0
- package/dist/sheet/format-store.d.ts +99 -0
- package/dist/sheet/format-store.js +233 -0
- package/dist/sheet/freeze.d.ts +54 -0
- package/dist/sheet/freeze.js +58 -0
- package/dist/sheet/function-catalog.d.ts +10 -0
- package/dist/sheet/function-catalog.js +94 -0
- package/dist/sheet/functions.d.ts +28 -0
- package/dist/sheet/functions.js +362 -0
- package/dist/sheet/goal-seek.d.ts +73 -0
- package/dist/sheet/goal-seek.js +153 -0
- package/dist/sheet/index.d.ts +53 -0
- package/dist/sheet/index.js +53 -0
- package/dist/sheet/merges.d.ts +71 -0
- package/dist/sheet/merges.js +137 -0
- package/dist/sheet/names.d.ts +31 -0
- package/dist/sheet/names.js +87 -0
- package/dist/sheet/navigate.d.ts +52 -0
- package/dist/sheet/navigate.js +135 -0
- package/dist/sheet/number-format.d.ts +63 -0
- package/dist/sheet/number-format.js +508 -0
- package/dist/sheet/palette.d.ts +19 -0
- package/dist/sheet/palette.js +84 -0
- package/dist/sheet/parse.d.ts +13 -0
- package/dist/sheet/parse.js +108 -0
- package/dist/sheet/paste-special.d.ts +164 -0
- package/dist/sheet/paste-special.js +592 -0
- package/dist/sheet/protection.d.ts +21 -0
- package/dist/sheet/protection.js +48 -0
- package/dist/sheet/rects.d.ts +45 -0
- package/dist/sheet/rects.js +112 -0
- package/dist/sheet/refs.d.ts +82 -0
- package/dist/sheet/refs.js +266 -0
- package/dist/sheet/ribbon-icons.d.ts +31 -0
- package/dist/sheet/ribbon-icons.js +350 -0
- package/dist/sheet/ribbon.d.ts +173 -0
- package/dist/sheet/ribbon.js +753 -0
- package/dist/sheet/shortcuts.d.ts +164 -0
- package/dist/sheet/shortcuts.js +623 -0
- package/dist/sheet/structure.d.ts +87 -0
- package/dist/sheet/structure.js +166 -0
- package/dist/sheet/tables.d.ts +70 -0
- package/dist/sheet/tables.js +147 -0
- package/dist/sheet/tokenize.d.ts +54 -0
- package/dist/sheet/tokenize.js +304 -0
- package/dist/sheet/transforms.d.ts +76 -0
- package/dist/sheet/transforms.js +154 -0
- package/dist/sheet/validation.d.ts +92 -0
- package/dist/sheet/validation.js +241 -0
- package/dist/sheet/workbook.d.ts +72 -0
- package/dist/sheet/workbook.js +409 -0
- package/dist/sheet-enable.d.ts +6 -0
- package/dist/sheet-enable.js +46 -0
- package/dist/sources/aggregate.d.ts +1 -1
- package/dist/sources/auth-supabase.js +1 -1
- package/dist/sources/dashboard.d.ts +2 -2
- package/dist/sources/dashboard.js +1 -1
- package/dist/sources/index.d.ts +13 -13
- package/dist/sources/index.js +13 -13
- package/dist/sources/realtime-supabase.js +1 -1
- package/dist/sources/relation-lookup.d.ts +1 -1
- package/dist/sources/relation-lookup.js +1 -1
- package/dist/sources/rest-adapters.d.ts +1 -1
- package/dist/sources/rest-adapters.js +1 -1
- package/dist/sources/rest.d.ts +2 -2
- package/dist/sources/rest.js +3 -3
- package/dist/sources/supabase.d.ts +2 -2
- package/dist/sources/supabase.js +3 -3
- package/dist/sources/with-entity-rules.d.ts +1 -1
- package/dist/sources/with-entity-rules.js +1 -1
- package/dist/sources/with-relation-labels.d.ts +1 -1
- package/dist/studio/emit-project.js +2161 -2127
- package/dist/studio/emit-schema.js +369 -369
- package/dist/studio/index.d.ts +1 -1
- package/dist/studio/index.js +1 -1
- package/dist/studio/introspect-db.js +45 -45
- package/dist/studio/project.d.ts +10 -0
- package/dist/studio/samples/crm.js +6 -6
- package/dist/studio/samples/fleet.js +7 -7
- package/dist/studio/samples/insurance.js +9 -9
- package/dist/studio/samples/inventory.js +12 -12
- package/dist/studio/samples/projects.js +5 -5
- package/dist/studio/samples/support.js +8 -8
- package/dist/studio/scaffold-app.js +104 -104
- package/dist/studio/scaffold.js +151 -151
- package/dist/studio/ui-components.d.ts +7 -0
- package/dist/studio/ui-components.generated.js +63 -1
- package/dist/studio/ui-components.js +35 -0
- package/dist/sveltekit/in-memory.d.ts +3 -3
- package/dist/sveltekit/in-memory.js +4 -4
- package/dist/sveltekit/index.d.ts +6 -6
- package/dist/sveltekit/index.js +5 -5
- package/dist/sveltekit/query-plan.d.ts +1 -1
- package/dist/sveltekit/sql-source.d.ts +4 -4
- package/dist/sveltekit/sql-source.js +4 -4
- package/dist/sveltekit/sql.d.ts +1 -1
- package/dist/sveltekit/transport.d.ts +2 -2
- package/dist/sveltekit/transport.js +1 -1
- package/dist/upgrade-prompt.js +25 -25
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +12 -4
- package/dist/designer/assets/GridMenus-Cgilexpk.js +0 -8
- package/dist/designer/assets/SvDateRangeInput-BV5OXYQ2.css +0 -1
- package/dist/designer/assets/SvDateRangeInput-CVn-yqrQ.js +0 -1
- package/dist/designer/assets/SvDateTimePicker-BdioTrJQ.js +0 -1
- package/dist/designer/assets/SvDateTimePicker-CY8TK4BT.css +0 -1
- package/dist/designer/assets/SvField-BF-9TJSd.css +0 -1
- package/dist/designer/assets/SvField-BsqiA5me.js +0 -1
- package/dist/designer/assets/SvGridCellEditor-dLY7_kk9.js +0 -2
- package/dist/designer/assets/SvGridChart-BEDNTdc5.js +0 -2
- package/dist/designer/assets/SvGridChart-Vu4Nvjiv.css +0 -1
- package/dist/designer/assets/SvGridChartPanel-x3lzSxuf.js +0 -10
- package/dist/designer/assets/SvGridChartView-CAKhPELi.js +0 -1
- package/dist/designer/assets/SvGridChartView-DX9HfkBR.css +0 -1
- package/dist/designer/assets/SvGridDropdown-CAYG7Y-O.js +0 -1
- package/dist/designer/assets/SvGridDropdown-Crwb2P3Q.css +0 -1
- package/dist/designer/assets/SvListBox-CVYQcLX9.js +0 -1
- package/dist/designer/assets/SvListBox-DgN8kvjt.css +0 -1
- package/dist/designer/assets/chart-DHEgt4lN.js +0 -1
- package/dist/designer/assets/column-resize-C_inr5zT.js +0 -1
- package/dist/designer/assets/date-format-4DJvNtG2.js +0 -1
- package/dist/designer/assets/date-format-Dzy4mTGh.css +0 -1
- package/dist/designer/assets/easing-zaypKrr0.js +0 -3
- package/dist/designer/assets/export-format-DwjuTfrQ.js +0 -6
- package/dist/designer/assets/index-Cp7fDJ3b.css +0 -1
- package/dist/designer/assets/js-scroller.svelte-Bhxqb3-c.js +0 -110
- package/dist/designer/assets/row-resize-B0FWHcNr.js +0 -1
- package/dist/designer/assets/src-B7DNcoQK.css +0 -1
- package/dist/designer/assets/src-BoYyigAC.js +0 -2896
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/_svelte_metadata.json +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/_metadata.json +0 -178
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-BOv1rBKp.js +0 -3875
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/attachments-BOv1rBKp.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-B9vgIdCd.js +0 -21
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/constants-B9vgIdCd.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-T1qbW_qD.js +0 -1938
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/dev-T1qbW_qD.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-Bo11SfVK.js +0 -205
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/events-Bo11SfVK.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-X7D4vfrZ.js +0 -18
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/flags-X7D4vfrZ.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-oyUje5i1.js +0 -264
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/hydration-oyUje5i1.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-DeSQgSFm.js +0 -697
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/legacy-client-DeSQgSFm.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/package.json +0 -3
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js +0 -134
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js +0 -55
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_animate.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_attachments.js +0 -2
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js +0 -46843
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_compiler.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js +0 -237
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_easing.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_events.js +0 -2
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js +0 -4
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_client.js +0 -7
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js +0 -4
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_disclose-version.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js +0 -5
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_async.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js +0 -5
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_legacy.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js +0 -5
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_flags_tracing.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_internal_server.js +0 -6
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js +0 -83
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_legacy.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js +0 -559
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_motion.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js +0 -24
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js +0 -122
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_reactivity_window.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_server.js +0 -2
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js +0 -89
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_store.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js +0 -241
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/svelte_transition.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-BbWyXNk1.js +0 -4938
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-BbWyXNk1.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DI_fC7vt.js +0 -495
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/utils-DI_fC7vt.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-Dyr3lQv9.js +0 -190
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/validate-Dyr3lQv9.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-_9FHH-LF.js +0 -8
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/version-_9FHH-LF.js.map +0 -1
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-CUbSPnyP.js +0 -138
- package/dist/studio/node_modules/.vite/vitest/be65d27ae088a0e03fd8e1331d90b01649464cb6/deps___vitest__/warnings-CUbSPnyP.js.map +0 -1
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paste Special, and the HTML clipboard round-trip that makes it worth having.
|
|
3
|
+
*
|
|
4
|
+
* The grid's clipboard is TSV only: `writeText` out, `readText` in. That is
|
|
5
|
+
* fine for values and loses everything else, so a trip through Excel drops
|
|
6
|
+
* every format, every formula and every merge. Excel itself writes both
|
|
7
|
+
* `text/plain` and `text/html`, and reads the HTML back when it is there.
|
|
8
|
+
* Matching that is what makes the grid part of someone's workflow rather than
|
|
9
|
+
* an island.
|
|
10
|
+
*
|
|
11
|
+
* The HTML is a plain `<table>`, which is what Excel, Sheets, Numbers and
|
|
12
|
+
* every web app already understand. Formats ride on inline styles they all
|
|
13
|
+
* read (with Excel's `mso-number-format` beside them so Excel keeps the
|
|
14
|
+
* number format too), the number behind a formatted display rides in
|
|
15
|
+
* Excel's `x:num`, and the formula travels in a `data-formula` attribute
|
|
16
|
+
* they all ignore, so a paste into Excel keeps the look while a paste back
|
|
17
|
+
* into the grid keeps the formula.
|
|
18
|
+
*
|
|
19
|
+
* Reading goes the other way: Excel's `<style>` classes, `x:fmla` and
|
|
20
|
+
* `x:num`, and Sheets' `data-sheets-*` attributes all come through, so a
|
|
21
|
+
* block copied from either arrives with its values, formulas and formats.
|
|
22
|
+
*/
|
|
23
|
+
import { translateFormula } from './refs.js';
|
|
24
|
+
import { parseFormula } from './parse.js';
|
|
25
|
+
import { visit } from './ast.js';
|
|
26
|
+
import { entryToStyle } from './format-store.js';
|
|
27
|
+
const esc = (s) => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
28
|
+
/**
|
|
29
|
+
* A number format the way Excel writes it in `mso-number-format`: quoted,
|
|
30
|
+
* every literal escaped with a backslash and a double quote as `\0022`.
|
|
31
|
+
* Excel reads the property back from inline styles, which is how a paste
|
|
32
|
+
* into it keeps `#,##0.00` rather than guessing a format from the text.
|
|
33
|
+
*/
|
|
34
|
+
export function msoNumberFormat(code) {
|
|
35
|
+
const body = code
|
|
36
|
+
.replace(/\\/g, '\\\\')
|
|
37
|
+
.replace(/"/g, '\\0022')
|
|
38
|
+
.replace(/([^A-Za-z0-9 \\])/g, '\\$1');
|
|
39
|
+
return `"${body}"`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Serialise a grid to the two clipboard flavours.
|
|
43
|
+
*
|
|
44
|
+
* The marker class is how `parseClipboardHtml` knows a paste came from a grid
|
|
45
|
+
* and can trust the `data-formula` attributes; HTML from anywhere else is
|
|
46
|
+
* read for text and styles only.
|
|
47
|
+
*/
|
|
48
|
+
export function buildClipboardPayload(grid,
|
|
49
|
+
/** Where the copy came from, so a pasted formula knows how far it moved.
|
|
50
|
+
* Omit for a synthetic payload; references then paste unshifted. */
|
|
51
|
+
origin) {
|
|
52
|
+
const text = grid.map((row) => row.map((cell) => cell.text).join('\t')).join('\n');
|
|
53
|
+
const rows = grid.map((row) => {
|
|
54
|
+
const cells = row.map((cell) => {
|
|
55
|
+
const numFmt = cell.format?.numFmt;
|
|
56
|
+
const style = [entryToStyle(cell.format), numFmt ? `mso-number-format:${msoNumberFormat(numFmt)}` : '']
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
.join(';');
|
|
59
|
+
const numeric = cell.value !== undefined && cell.value !== '' && Number.isFinite(Number(cell.value));
|
|
60
|
+
const attrs = [
|
|
61
|
+
style ? ` style="${esc(style)}"` : '',
|
|
62
|
+
numeric ? ` x:num="${esc(cell.value)}"` : '',
|
|
63
|
+
cell.formula ? ` data-formula="${esc(cell.formula)}"` : '',
|
|
64
|
+
numFmt ? ` data-numfmt="${esc(numFmt)}"` : '',
|
|
65
|
+
].join('');
|
|
66
|
+
return `<td${attrs}>${esc(cell.text)}</td>`;
|
|
67
|
+
});
|
|
68
|
+
return `<tr>${cells.join('')}</tr>`;
|
|
69
|
+
});
|
|
70
|
+
const originAttr = origin
|
|
71
|
+
? ` data-origin="${origin.row} ${origin.col}"`
|
|
72
|
+
: '';
|
|
73
|
+
// The x: namespace is Excel's; declaring it is what makes Excel read x:num.
|
|
74
|
+
const html = `<table class="svgrid-clipboard" xmlns:x="urn:schemas-microsoft-com:office:excel"${originAttr}><tbody>` +
|
|
75
|
+
rows.join('') + '</tbody></table>';
|
|
76
|
+
return { text, html };
|
|
77
|
+
}
|
|
78
|
+
const R1C1_REF = /\bR(?:\[(-?\d+)\]|(\d+))?C(?:\[(-?\d+)\]|(\d+))?(?![A-Za-z0-9_(])/g;
|
|
79
|
+
/** Whether a formula is written in R1C1, as Google Sheets writes them. */
|
|
80
|
+
export function isR1C1(formula) {
|
|
81
|
+
R1C1_REF.lastIndex = 0;
|
|
82
|
+
const outside = formula.replace(/"[^"]*"|'[^']*'/g, (m) => ' '.repeat(m.length));
|
|
83
|
+
return R1C1_REF.test(outside);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* An R1C1 formula as A1, for the cell it lands in. `R[-1]C` is the cell
|
|
87
|
+
* above wherever the formula sits, `R2C3` is $C$2 anywhere, and a bare
|
|
88
|
+
* `RC` is the cell itself. Quoted strings and sheet names pass through.
|
|
89
|
+
*/
|
|
90
|
+
export function r1c1ToA1(formula, row, col) {
|
|
91
|
+
const letters = (index) => {
|
|
92
|
+
let n = index + 1;
|
|
93
|
+
let out = '';
|
|
94
|
+
while (n > 0) {
|
|
95
|
+
const rem = (n - 1) % 26;
|
|
96
|
+
out = String.fromCharCode(65 + rem) + out;
|
|
97
|
+
n = Math.floor((n - 1) / 26);
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
};
|
|
101
|
+
const convert = (chunk) => chunk.replace(R1C1_REF, (m, rRel, rAbs, cRel, cAbs) => {
|
|
102
|
+
const r = rAbs !== undefined ? Number(rAbs) - 1 : row + Number(rRel ?? 0);
|
|
103
|
+
const c = cAbs !== undefined ? Number(cAbs) - 1 : col + Number(cRel ?? 0);
|
|
104
|
+
if (r < 0 || c < 0)
|
|
105
|
+
return m;
|
|
106
|
+
return `${cAbs !== undefined ? '$' : ''}${letters(c)}${rAbs !== undefined ? '$' : ''}${r + 1}`;
|
|
107
|
+
});
|
|
108
|
+
// Convert only the text between quotes.
|
|
109
|
+
let out = '';
|
|
110
|
+
let start = 0;
|
|
111
|
+
const quoted = /"[^"]*"|'[^']*'/g;
|
|
112
|
+
let m;
|
|
113
|
+
while ((m = quoted.exec(formula))) {
|
|
114
|
+
out += convert(formula.slice(start, m.index)) + m[0];
|
|
115
|
+
start = m.index + m[0].length;
|
|
116
|
+
}
|
|
117
|
+
return out + convert(formula.slice(start));
|
|
118
|
+
}
|
|
119
|
+
/** Parse a TSV clipboard into a grid of text-only cells. */
|
|
120
|
+
export function parseClipboardText(text) {
|
|
121
|
+
const lines = text.replace(/\r\n/g, '\n').split('\n');
|
|
122
|
+
if (lines.length > 0 && lines[lines.length - 1] === '')
|
|
123
|
+
lines.pop();
|
|
124
|
+
return lines.map((line) => line.split('\t').map((cellText) => ({ text: cellText })));
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The declarations of a style string, last one wins as in CSS, with quoted
|
|
128
|
+
* values kept whole (a number format carries ';' between its sections).
|
|
129
|
+
* `background-color` folds into `background` so the two spellings override
|
|
130
|
+
* each other in order.
|
|
131
|
+
*/
|
|
132
|
+
function declarationsOf(style) {
|
|
133
|
+
const out = new Map();
|
|
134
|
+
let quote = null;
|
|
135
|
+
let start = 0;
|
|
136
|
+
const take = (part) => {
|
|
137
|
+
const i = part.indexOf(':');
|
|
138
|
+
if (i < 0)
|
|
139
|
+
return;
|
|
140
|
+
let prop = part.slice(0, i).trim().toLowerCase();
|
|
141
|
+
if (prop === 'background-color')
|
|
142
|
+
prop = 'background';
|
|
143
|
+
if (prop)
|
|
144
|
+
out.set(prop, part.slice(i + 1).trim());
|
|
145
|
+
};
|
|
146
|
+
for (let i = 0; i < style.length; i += 1) {
|
|
147
|
+
const ch = style[i];
|
|
148
|
+
if (quote) {
|
|
149
|
+
if (ch === quote)
|
|
150
|
+
quote = null;
|
|
151
|
+
}
|
|
152
|
+
else if (ch === '"' || ch === "'") {
|
|
153
|
+
quote = ch;
|
|
154
|
+
}
|
|
155
|
+
else if (ch === ';') {
|
|
156
|
+
take(style.slice(start, i));
|
|
157
|
+
start = i + 1;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
take(style.slice(start));
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
const AUTOMATIC_COLOR = /^(?:windowtext|black|#000|#000000)$/i;
|
|
164
|
+
const STYLE_TO_ENTRY = {
|
|
165
|
+
'font-weight': (v, into) => {
|
|
166
|
+
if (/^(?:bold|bolder|[6-9]00)$/i.test(v))
|
|
167
|
+
into.bold = true;
|
|
168
|
+
else
|
|
169
|
+
delete into.bold;
|
|
170
|
+
},
|
|
171
|
+
'font-style': (v, into) => {
|
|
172
|
+
if (/^(?:italic|oblique)$/i.test(v))
|
|
173
|
+
into.italic = true;
|
|
174
|
+
else
|
|
175
|
+
delete into.italic;
|
|
176
|
+
},
|
|
177
|
+
'text-decoration': (v, into) => {
|
|
178
|
+
if (/underline/i.test(v))
|
|
179
|
+
into.underline = true;
|
|
180
|
+
else
|
|
181
|
+
delete into.underline;
|
|
182
|
+
if (/line-through/i.test(v))
|
|
183
|
+
into.strike = true;
|
|
184
|
+
else
|
|
185
|
+
delete into.strike;
|
|
186
|
+
},
|
|
187
|
+
color: (v, into) => {
|
|
188
|
+
// Excel writes the automatic colour as windowtext (or black in older
|
|
189
|
+
// builds); that is "no colour set", not a black override.
|
|
190
|
+
if (AUTOMATIC_COLOR.test(v))
|
|
191
|
+
delete into.color;
|
|
192
|
+
else
|
|
193
|
+
into.color = v;
|
|
194
|
+
},
|
|
195
|
+
background: (v, into) => {
|
|
196
|
+
if (/^(?:transparent|none|auto)$/i.test(v))
|
|
197
|
+
delete into.fill;
|
|
198
|
+
else
|
|
199
|
+
into.fill = v;
|
|
200
|
+
},
|
|
201
|
+
'text-align': (v, into) => {
|
|
202
|
+
if (/^(?:left|center|right)$/i.test(v))
|
|
203
|
+
into.align = v.toLowerCase();
|
|
204
|
+
else
|
|
205
|
+
delete into.align;
|
|
206
|
+
},
|
|
207
|
+
'font-family': (v, into) => {
|
|
208
|
+
// The first family, unquoted; Excel writes "Aptos Narrow", sans-serif.
|
|
209
|
+
const first = v.split(',')[0].trim().replace(/^["']|["']$/g, '');
|
|
210
|
+
if (first)
|
|
211
|
+
into.fontFamily = first;
|
|
212
|
+
},
|
|
213
|
+
'font-size': (v, into) => {
|
|
214
|
+
const m = /^([\d.]+)(pt|px)$/i.exec(v);
|
|
215
|
+
if (!m)
|
|
216
|
+
return;
|
|
217
|
+
const n = Number(m[1]);
|
|
218
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
219
|
+
return;
|
|
220
|
+
into.fontSize = m[2].toLowerCase() === 'pt' ? Math.round((n * 96) / 72) : Math.round(n);
|
|
221
|
+
},
|
|
222
|
+
'white-space': (v, into) => {
|
|
223
|
+
if (/^(?:pre-wrap|normal|pre-line)$/i.test(v))
|
|
224
|
+
into.wrap = true;
|
|
225
|
+
else
|
|
226
|
+
delete into.wrap;
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Excel's `mso-number-format` as our number format. Excel escapes the
|
|
231
|
+
* literal characters of a code (`0\.00`), and names a few formats rather
|
|
232
|
+
* than spelling them; the names map to the codes Excel shows for them.
|
|
233
|
+
*/
|
|
234
|
+
const MSO_NAMED_FORMATS = {
|
|
235
|
+
general: undefined,
|
|
236
|
+
'general number': undefined,
|
|
237
|
+
standard: '#,##0.00',
|
|
238
|
+
fixed: '0.00',
|
|
239
|
+
percent: '0.00%',
|
|
240
|
+
currency: '$#,##0.00',
|
|
241
|
+
scientific: '0.00E+00',
|
|
242
|
+
'short date': 'm/d/yyyy',
|
|
243
|
+
'medium date': 'd-mmm-yy',
|
|
244
|
+
'long date': 'dddd, mmmm d, yyyy',
|
|
245
|
+
'short time': 'h:mm',
|
|
246
|
+
'medium time': 'h:mm AM/PM',
|
|
247
|
+
'long time': 'h:mm:ss AM/PM',
|
|
248
|
+
'@': '@',
|
|
249
|
+
};
|
|
250
|
+
export function numFmtFromMso(value) {
|
|
251
|
+
const raw = value.trim().replace(/^["']|["']$/g, '');
|
|
252
|
+
if (!raw)
|
|
253
|
+
return undefined;
|
|
254
|
+
const named = MSO_NAMED_FORMATS[raw.toLowerCase()];
|
|
255
|
+
if (raw.toLowerCase() in MSO_NAMED_FORMATS)
|
|
256
|
+
return named;
|
|
257
|
+
// Excel escapes every literal (\# \, \. \@) and writes a double quote as
|
|
258
|
+
// \0022; our codes take the literals plain.
|
|
259
|
+
return raw.replace(/\\0022/g, '"').replace(/\\([^A-Za-z0-9])/g, '$1');
|
|
260
|
+
}
|
|
261
|
+
function entryFromStyle(style, numFmt) {
|
|
262
|
+
const into = {};
|
|
263
|
+
if (style) {
|
|
264
|
+
for (const [prop, value] of declarationsOf(style)) {
|
|
265
|
+
if (prop === 'mso-number-format') {
|
|
266
|
+
if (numFmt !== null)
|
|
267
|
+
continue;
|
|
268
|
+
const code = numFmtFromMso(value);
|
|
269
|
+
if (code)
|
|
270
|
+
into.numFmt = code;
|
|
271
|
+
else
|
|
272
|
+
delete into.numFmt;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
STYLE_TO_ENTRY[prop]?.(value, into);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (numFmt)
|
|
280
|
+
into.numFmt = numFmt;
|
|
281
|
+
return Object.keys(into).length > 0 ? into : undefined;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* The class rules of a clipboard document. Excel puts every cell's format in
|
|
285
|
+
* a `<style>` block keyed by `class="xl65"`, one rule per class, and only
|
|
286
|
+
* the odd override inline; the declarations are merged under the inline
|
|
287
|
+
* style so the inline one wins where both speak.
|
|
288
|
+
*/
|
|
289
|
+
function classStyles(doc) {
|
|
290
|
+
const out = new Map();
|
|
291
|
+
for (const styleEl of doc.querySelectorAll('style')) {
|
|
292
|
+
const css = styleEl.textContent ?? '';
|
|
293
|
+
const rule = /([^{}]+)\{([^{}]*)\}/g;
|
|
294
|
+
let m;
|
|
295
|
+
while ((m = rule.exec(css))) {
|
|
296
|
+
const declarations = m[2].replace(/\s+/g, ' ').trim();
|
|
297
|
+
for (const selector of m[1].split(',')) {
|
|
298
|
+
const cls = /\.([\w-]+)\s*$/.exec(selector.trim());
|
|
299
|
+
if (cls)
|
|
300
|
+
out.set(cls[1], (out.get(cls[1]) ? out.get(cls[1]) + ';' : '') + declarations);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return out;
|
|
305
|
+
}
|
|
306
|
+
/** The formula a cell carries, whichever spreadsheet wrote the HTML. */
|
|
307
|
+
function formulaOf(td) {
|
|
308
|
+
const own = td.getAttribute('data-formula');
|
|
309
|
+
if (own)
|
|
310
|
+
return own;
|
|
311
|
+
const excel = td.getAttribute('x:fmla');
|
|
312
|
+
if (excel)
|
|
313
|
+
return excel.startsWith('=') ? excel : `=${excel}`;
|
|
314
|
+
const sheets = td.getAttribute('data-sheets-formula');
|
|
315
|
+
if (sheets)
|
|
316
|
+
return sheets.startsWith('=') ? sheets : `=${sheets}`;
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
/** The raw value behind a formatted display, when the source wrote one. */
|
|
320
|
+
function rawValueOf(td) {
|
|
321
|
+
const excel = td.getAttribute('x:num');
|
|
322
|
+
if (excel !== null && excel !== '' && Number.isFinite(Number(excel)))
|
|
323
|
+
return excel;
|
|
324
|
+
const sheets = td.getAttribute('data-sheets-value');
|
|
325
|
+
if (sheets) {
|
|
326
|
+
try {
|
|
327
|
+
const parsed = JSON.parse(sheets);
|
|
328
|
+
if (typeof parsed['3'] === 'number')
|
|
329
|
+
return String(parsed['3']);
|
|
330
|
+
if (typeof parsed['2'] === 'string')
|
|
331
|
+
return parsed['2'];
|
|
332
|
+
if (typeof parsed['4'] === 'boolean')
|
|
333
|
+
return parsed['4'] ? 'TRUE' : 'FALSE';
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
// Not JSON: the display text stands.
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return undefined;
|
|
340
|
+
}
|
|
341
|
+
/** Google Sheets' number format, when the cell carries one. */
|
|
342
|
+
function sheetsNumFmt(td) {
|
|
343
|
+
const raw = td.getAttribute('data-sheets-numberformat');
|
|
344
|
+
if (!raw)
|
|
345
|
+
return null;
|
|
346
|
+
try {
|
|
347
|
+
const parsed = JSON.parse(raw);
|
|
348
|
+
return typeof parsed['2'] === 'string' ? parsed['2'] : null;
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Parse clipboard HTML into a grid.
|
|
356
|
+
*
|
|
357
|
+
* Uses DOMParser rather than a regex: clipboard HTML from Excel is full of
|
|
358
|
+
* conditional comments, namespaced tags and unclosed elements, and a parser
|
|
359
|
+
* that already handles all of that ships in the browser.
|
|
360
|
+
*
|
|
361
|
+
* Returns null when the HTML holds no table, so the caller falls back to TSV.
|
|
362
|
+
*/
|
|
363
|
+
export function readClipboardOrigin(html) {
|
|
364
|
+
if (typeof DOMParser === 'undefined')
|
|
365
|
+
return null;
|
|
366
|
+
try {
|
|
367
|
+
const table = new DOMParser().parseFromString(html, 'text/html').querySelector('table');
|
|
368
|
+
const raw = table?.getAttribute('data-origin');
|
|
369
|
+
if (!raw)
|
|
370
|
+
return null;
|
|
371
|
+
const [row, col] = raw.split(' ').map(Number);
|
|
372
|
+
return Number.isFinite(row) && Number.isFinite(col)
|
|
373
|
+
? { row: row, col: col }
|
|
374
|
+
: null;
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
export function parseClipboardHtml(html) {
|
|
381
|
+
if (typeof DOMParser === 'undefined')
|
|
382
|
+
return null;
|
|
383
|
+
let doc;
|
|
384
|
+
try {
|
|
385
|
+
doc = new DOMParser().parseFromString(html, 'text/html');
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
const table = doc.querySelector('table');
|
|
391
|
+
if (!table)
|
|
392
|
+
return null;
|
|
393
|
+
const classes = classStyles(doc);
|
|
394
|
+
const grid = [];
|
|
395
|
+
for (const tr of table.querySelectorAll('tr')) {
|
|
396
|
+
const row = [];
|
|
397
|
+
for (const td of tr.querySelectorAll('td, th')) {
|
|
398
|
+
const formula = formulaOf(td);
|
|
399
|
+
const fromClasses = (td.getAttribute('class') ?? '')
|
|
400
|
+
.split(/\s+/)
|
|
401
|
+
.map((c) => classes.get(c))
|
|
402
|
+
.filter((c) => !!c);
|
|
403
|
+
const style = [...fromClasses, td.getAttribute('style') ?? ''].filter(Boolean).join(';');
|
|
404
|
+
const raw = rawValueOf(td);
|
|
405
|
+
row.push({
|
|
406
|
+
// textContent rather than innerText: this document is never rendered,
|
|
407
|
+
// so innerText would be empty. A source that wrote the raw value
|
|
408
|
+
// beside a formatted display (Excel's x:num, Sheets' data-sheets-value)
|
|
409
|
+
// pastes the value; the format carries the look.
|
|
410
|
+
text: raw ?? (td.textContent ?? '').replace(/ /g, ' ').trim(),
|
|
411
|
+
...(formula ? { formula } : {}),
|
|
412
|
+
...(() => {
|
|
413
|
+
const entry = entryFromStyle(style || null, td.getAttribute('data-numfmt') ?? sheetsNumFmt(td));
|
|
414
|
+
return entry ? { format: entry } : {};
|
|
415
|
+
})(),
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
if (row.length > 0)
|
|
419
|
+
grid.push(row);
|
|
420
|
+
}
|
|
421
|
+
return grid.length > 0 ? grid : null;
|
|
422
|
+
}
|
|
423
|
+
/** Read whichever flavour is richer. */
|
|
424
|
+
export function parseClipboard(payload) {
|
|
425
|
+
if (payload.html) {
|
|
426
|
+
const fromHtml = parseClipboardHtml(payload.html);
|
|
427
|
+
if (fromHtml)
|
|
428
|
+
return fromHtml;
|
|
429
|
+
}
|
|
430
|
+
return parseClipboardText(payload.text ?? '');
|
|
431
|
+
}
|
|
432
|
+
function transposeGrid(grid) {
|
|
433
|
+
const rows = grid.length;
|
|
434
|
+
const cols = Math.max(0, ...grid.map((r) => r.length));
|
|
435
|
+
const out = [];
|
|
436
|
+
for (let c = 0; c < cols; c += 1) {
|
|
437
|
+
const row = [];
|
|
438
|
+
for (let r = 0; r < rows; r += 1)
|
|
439
|
+
row.push(grid[r]?.[c] ?? { text: '' });
|
|
440
|
+
out.push(row);
|
|
441
|
+
}
|
|
442
|
+
return out;
|
|
443
|
+
}
|
|
444
|
+
function arithmetic(existing, incoming, op) {
|
|
445
|
+
const a = Number(existing);
|
|
446
|
+
const b = Number(incoming);
|
|
447
|
+
if (!Number.isFinite(a) || !Number.isFinite(b))
|
|
448
|
+
return null;
|
|
449
|
+
switch (op) {
|
|
450
|
+
case 'add': return a + b;
|
|
451
|
+
case 'subtract': return a - b;
|
|
452
|
+
case 'multiply': return a * b;
|
|
453
|
+
// Excel gives #DIV/0! here; the caller writes the error, so report null
|
|
454
|
+
// and let it decide rather than inventing a zero.
|
|
455
|
+
case 'divide': return b === 0 ? null : a / b;
|
|
456
|
+
default: return null;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Decide what lands in one cell. Pure, so the whole option matrix is testable
|
|
461
|
+
* without a clipboard or a grid.
|
|
462
|
+
*
|
|
463
|
+
* `offset` is how far the destination sits from where the source was copied,
|
|
464
|
+
* which is what lets a pasted formula shift its relative references. `at`
|
|
465
|
+
* is the destination itself, which an R1C1 formula (Google Sheets writes
|
|
466
|
+
* them so) needs to become A1; it then needs no offset, being relative to
|
|
467
|
+
* wherever it lands.
|
|
468
|
+
*/
|
|
469
|
+
export function resolvePasteCell(source, existing, opts, offset = { rows: 0, cols: 0 }, at) {
|
|
470
|
+
if (!source)
|
|
471
|
+
return { kind: 'skip' };
|
|
472
|
+
const what = opts.what ?? 'all';
|
|
473
|
+
const operation = opts.operation ?? 'none';
|
|
474
|
+
if (opts.skipBlanks && source.text === '' && !source.formula)
|
|
475
|
+
return { kind: 'skip' };
|
|
476
|
+
if (what === 'formats')
|
|
477
|
+
return { kind: 'format', format: source.format };
|
|
478
|
+
// Arithmetic ignores formats and formulas: Excel operates on values.
|
|
479
|
+
if (operation !== 'none') {
|
|
480
|
+
const result = arithmetic(existing, source.text, operation);
|
|
481
|
+
return result === null ? { kind: 'skip' } : { kind: 'value', value: String(result) };
|
|
482
|
+
}
|
|
483
|
+
const wantsFormula = what === 'all' || what === 'formulas';
|
|
484
|
+
const value = wantsFormula && source.formula
|
|
485
|
+
? at && isR1C1(source.formula)
|
|
486
|
+
? r1c1ToA1(source.formula, at.row, at.col)
|
|
487
|
+
: String(translateFormula(source.formula, offset.rows, offset.cols))
|
|
488
|
+
: source.text;
|
|
489
|
+
if (what === 'values' || what === 'formulas')
|
|
490
|
+
return { kind: 'value', value };
|
|
491
|
+
return { kind: 'both', value, format: source.format };
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* A block from another application says nothing about where it was copied
|
|
495
|
+
* from, and Excel's formulas come in A1 as written: `=B2*C2` beside a
|
|
496
|
+
* price and a quantity. Pasted anywhere but A1 with no shift, that formula
|
|
497
|
+
* reads the wrong cells. What CAN be known is whether the block is
|
|
498
|
+
* self-contained: with the block read as if copied from A1, a formula whose
|
|
499
|
+
* every reference falls inside the block (a totals column, a running sum,
|
|
500
|
+
* the blocks people copy) is kept and moves with the paste from that A1;
|
|
501
|
+
* one that reaches outside is pasted as its value, which is right wherever
|
|
502
|
+
* the block lands. R1C1 formulas (Google Sheets) are left alone: they are
|
|
503
|
+
* resolved against the cell they land in.
|
|
504
|
+
*/
|
|
505
|
+
export function anchorForeignFormulas(grid) {
|
|
506
|
+
const rows = grid.length;
|
|
507
|
+
const cols = Math.max(0, ...grid.map((r) => r.length));
|
|
508
|
+
let anchored = false;
|
|
509
|
+
const out = grid.map((row) => row.map((cell) => {
|
|
510
|
+
if (!cell.formula || isR1C1(cell.formula))
|
|
511
|
+
return cell;
|
|
512
|
+
let inside = true;
|
|
513
|
+
try {
|
|
514
|
+
visit(parseFormula(cell.formula), (n) => {
|
|
515
|
+
// A defined name or a table reference belongs to the source
|
|
516
|
+
// workbook; a sheet-qualified reference is outside by definition.
|
|
517
|
+
if (n.k === 'name' || n.k === 'table')
|
|
518
|
+
inside = false;
|
|
519
|
+
if (n.k === 'ref') {
|
|
520
|
+
if (n.ref.sheet || n.ref.row === null || n.ref.row >= rows || n.ref.col >= cols)
|
|
521
|
+
inside = false;
|
|
522
|
+
}
|
|
523
|
+
if (n.k === 'range') {
|
|
524
|
+
if (n.from.sheet || n.to.sheet)
|
|
525
|
+
inside = false;
|
|
526
|
+
const r2 = Math.max(n.from.row ?? rows, n.to.row ?? rows);
|
|
527
|
+
if (r2 >= rows || Math.max(n.from.col, n.to.col) >= cols)
|
|
528
|
+
inside = false;
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
catch {
|
|
533
|
+
inside = false;
|
|
534
|
+
}
|
|
535
|
+
if (!inside) {
|
|
536
|
+
const { formula: _dropped, ...rest } = cell;
|
|
537
|
+
return rest;
|
|
538
|
+
}
|
|
539
|
+
anchored = true;
|
|
540
|
+
return cell;
|
|
541
|
+
}));
|
|
542
|
+
return { grid: out, origin: anchored ? { row: 0, col: 0 } : null };
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Where each source cell lands.
|
|
546
|
+
*
|
|
547
|
+
* The reference offset is the same for every cell, not per-cell: source and
|
|
548
|
+
* destination both advance together as the grid is walked, so the shift is
|
|
549
|
+
* just `destination - origin`. Computing it per cell is how you end up
|
|
550
|
+
* translating by the destination's absolute position, which is wrong
|
|
551
|
+
* everywhere except the top-left corner.
|
|
552
|
+
*
|
|
553
|
+
* With no `origin` the offset is zero. That is right rather than lazy: a
|
|
554
|
+
* formula pasted in from another application has no position in this sheet to
|
|
555
|
+
* have moved from.
|
|
556
|
+
*
|
|
557
|
+
* `fill` is the selection's size. A block that fits it a whole number of
|
|
558
|
+
* times is repeated over it, as Excel repeats a copied cell across a
|
|
559
|
+
* selected range (or two copied rows over six selected ones); each repeat
|
|
560
|
+
* gets its own offset, so a repeated formula points where a hand-copied one
|
|
561
|
+
* would. Otherwise the block lands at the destination and keeps its shape.
|
|
562
|
+
*/
|
|
563
|
+
export function planPaste(grid, destination, opts = {}, origin, fill) {
|
|
564
|
+
const shaped = opts.transpose ? transposeGrid(grid) : grid;
|
|
565
|
+
const height = shaped.length;
|
|
566
|
+
const width = shaped.reduce((max, row) => Math.max(max, row.length), 0);
|
|
567
|
+
const repeats = fill && height > 0 && width > 0
|
|
568
|
+
&& fill.rows % height === 0 && fill.cols % width === 0
|
|
569
|
+
&& (fill.rows > height || fill.cols > width)
|
|
570
|
+
? { rows: fill.rows / height, cols: fill.cols / width }
|
|
571
|
+
: { rows: 1, cols: 1 };
|
|
572
|
+
const out = [];
|
|
573
|
+
for (let tr = 0; tr < repeats.rows; tr += 1) {
|
|
574
|
+
for (let tc = 0; tc < repeats.cols; tc += 1) {
|
|
575
|
+
const corner = { row: destination.row + tr * height, col: destination.col + tc * width };
|
|
576
|
+
// A transposed paste changes the shape, so Excel does not translate either.
|
|
577
|
+
const offset = origin && !opts.transpose
|
|
578
|
+
? { rows: corner.row - origin.row, cols: corner.col - origin.col }
|
|
579
|
+
: { rows: 0, cols: 0 };
|
|
580
|
+
for (let r = 0; r < shaped.length; r += 1) {
|
|
581
|
+
const row = shaped[r] ?? [];
|
|
582
|
+
for (let c = 0; c < row.length; c += 1) {
|
|
583
|
+
const source = row[c];
|
|
584
|
+
if (!source)
|
|
585
|
+
continue;
|
|
586
|
+
out.push({ row: corner.row + r, col: corner.col + c, source, offset });
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return out;
|
|
592
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sheet protection, the way Excel has it: every cell is locked by default,
|
|
3
|
+
* Format Cells > Protection unlocks the ones that may change, and Protect
|
|
4
|
+
* Sheet turns the flags on. Until then a locked cell is an ordinary cell.
|
|
5
|
+
*
|
|
6
|
+
* The rules live here so the shell, the ribbon and the commands agree on
|
|
7
|
+
* them without each reading the format entry its own way.
|
|
8
|
+
*/
|
|
9
|
+
import type { CellAddressLookup, CellFormatEntry, Rect, SheetFormatStore } from './format-store.js';
|
|
10
|
+
/** What the sheet says when a protected cell is asked to change. */
|
|
11
|
+
export declare const PROTECTED_MESSAGE = "The cell you're trying to change is on a protected sheet. To make a change, unprotect the sheet.";
|
|
12
|
+
/** A cell is locked unless its format says otherwise. */
|
|
13
|
+
export declare function isLocked(entry: CellFormatEntry | undefined): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Whether any cell of the rectangles is locked. A protected sheet refuses
|
|
16
|
+
* a change that touches one locked cell rather than doing the rest, which
|
|
17
|
+
* is what Excel does and what keeps an undo step whole.
|
|
18
|
+
*/
|
|
19
|
+
export declare function rectsHaveLocked(store: SheetFormatStore, lookup: CellAddressLookup, rects: ReadonlyArray<Rect>): boolean;
|
|
20
|
+
/** Whether the rectangles hold both locked and unlocked cells. */
|
|
21
|
+
export declare function rectsMixLocked(store: SheetFormatStore, lookup: CellAddressLookup, rects: ReadonlyArray<Rect>): boolean;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** What the sheet says when a protected cell is asked to change. */
|
|
2
|
+
export const PROTECTED_MESSAGE = "The cell you're trying to change is on a protected sheet. To make a change, unprotect the sheet.";
|
|
3
|
+
/** A cell is locked unless its format says otherwise. */
|
|
4
|
+
export function isLocked(entry) {
|
|
5
|
+
return entry?.locked !== false;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Whether any cell of the rectangles is locked. A protected sheet refuses
|
|
9
|
+
* a change that touches one locked cell rather than doing the rest, which
|
|
10
|
+
* is what Excel does and what keeps an undo step whole.
|
|
11
|
+
*/
|
|
12
|
+
export function rectsHaveLocked(store, lookup, rects) {
|
|
13
|
+
for (const [minRow, minCol, maxRow, maxCol] of rects) {
|
|
14
|
+
for (let r = minRow; r <= maxRow; r += 1) {
|
|
15
|
+
for (let c = minCol; c <= maxCol; c += 1) {
|
|
16
|
+
const rowId = lookup.rowIdAt(r);
|
|
17
|
+
const columnId = lookup.columnIdAt(c);
|
|
18
|
+
if (rowId == null || columnId == null)
|
|
19
|
+
continue;
|
|
20
|
+
if (isLocked(store.get(rowId, columnId)))
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
/** Whether the rectangles hold both locked and unlocked cells. */
|
|
28
|
+
export function rectsMixLocked(store, lookup, rects) {
|
|
29
|
+
let locked = false;
|
|
30
|
+
let unlocked = false;
|
|
31
|
+
for (const [minRow, minCol, maxRow, maxCol] of rects) {
|
|
32
|
+
for (let r = minRow; r <= maxRow; r += 1) {
|
|
33
|
+
for (let c = minCol; c <= maxCol; c += 1) {
|
|
34
|
+
const rowId = lookup.rowIdAt(r);
|
|
35
|
+
const columnId = lookup.columnIdAt(c);
|
|
36
|
+
if (rowId == null || columnId == null)
|
|
37
|
+
continue;
|
|
38
|
+
if (isLocked(store.get(rowId, columnId)))
|
|
39
|
+
locked = true;
|
|
40
|
+
else
|
|
41
|
+
unlocked = true;
|
|
42
|
+
if (locked && unlocked)
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|