@svgrid/enterprise 3.0.1 → 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 +680 -0
- package/dist/SvFormulaBar.svelte.d.ts +69 -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 +263 -54
- package/dist/SvPivotDesigner.svelte.d.ts +27 -20
- package/dist/SvRibbonIcon.svelte +46 -0
- package/dist/SvRibbonIcon.svelte.d.ts +17 -0
- package/dist/SvSchemaChart.svelte +4 -2
- package/dist/SvSheet.svelte +7914 -0
- package/dist/SvSheet.svelte.d.ts +215 -0
- package/dist/SvSheetChartSetup.svelte +151 -0
- package/dist/SvSheetChartSetup.svelte.d.ts +18 -0
- package/dist/SvSheetComment.svelte +283 -0
- package/dist/SvSheetComment.svelte.d.ts +22 -0
- package/dist/SvSheetConditionalFormat.svelte +159 -0
- package/dist/SvSheetConditionalFormat.svelte.d.ts +14 -0
- package/dist/SvSheetDataValidation.svelte +273 -0
- package/dist/SvSheetDataValidation.svelte.d.ts +14 -0
- 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 +320 -0
- package/dist/SvSheetFilterMenu.svelte.d.ts +22 -0
- package/dist/SvSheetFindReplace.svelte +132 -0
- package/dist/SvSheetFindReplace.svelte.d.ts +10 -0
- package/dist/SvSheetFormatCells.svelte +465 -0
- package/dist/SvSheetFormatCells.svelte.d.ts +17 -0
- package/dist/SvSheetGoalSeek.svelte +145 -0
- package/dist/SvSheetGoalSeek.svelte.d.ts +12 -0
- package/dist/SvSheetInsertFunction.svelte +149 -0
- package/dist/SvSheetInsertFunction.svelte.d.ts +8 -0
- 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 +91 -0
- package/dist/SvSheetListPicker.svelte.d.ts +10 -0
- package/dist/SvSheetManageRules.svelte +187 -0
- package/dist/SvSheetManageRules.svelte.d.ts +16 -0
- package/dist/SvSheetNameManager.svelte +227 -0
- package/dist/SvSheetNameManager.svelte.d.ts +11 -0
- package/dist/SvSheetPageSetup.svelte +159 -0
- package/dist/SvSheetPageSetup.svelte.d.ts +13 -0
- package/dist/SvSheetPasteSpecial.svelte +107 -0
- package/dist/SvSheetPasteSpecial.svelte.d.ts +12 -0
- 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 +152 -0
- package/dist/SvSheetRemoveDuplicates.svelte.d.ts +12 -0
- package/dist/SvSheetRibbon.svelte +1254 -0
- package/dist/SvSheetRibbon.svelte.d.ts +34 -0
- package/dist/SvSheetSizeDialog.svelte +60 -0
- package/dist/SvSheetSizeDialog.svelte.d.ts +11 -0
- 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 +571 -0
- package/dist/SvSheetTabs.svelte.d.ts +50 -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 +85 -0
- package/dist/SvSheetValidationAlert.svelte.d.ts +15 -0
- 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 +43538 -6539
- package/dist/designer/assets/GridMenus-8gTNssgV.js +8 -0
- package/dist/designer/assets/SvChartMenu-BDoeqGz6.js +1 -0
- package/dist/designer/assets/SvChartMenu-BYO9cYdy.css +1 -0
- package/dist/designer/assets/SvDateRangeInput-BBRzrQeg.js +1 -0
- package/dist/designer/assets/SvDateTimePicker-DCPg7WGN.js +1 -0
- package/dist/designer/assets/SvGridCellEditor-DMoWJjEI.js +4 -0
- package/dist/designer/assets/SvGridChart-BgLuPO7I.css +1 -0
- package/dist/designer/assets/SvGridChart-Cy1ATrWh.js +3 -0
- package/dist/designer/assets/SvGridChartBuilder-08YWWeqY.css +1 -0
- package/dist/designer/assets/SvGridChartBuilder-eQ3mn0L9.js +1 -0
- package/dist/designer/assets/SvGridChartPanel-4Pc8y5yO.css +1 -0
- package/dist/designer/assets/SvGridChartPanel-CATdVc9X.js +4 -0
- package/dist/designer/assets/{SvGridChartView-DUc-1RUf.css → SvGridChartView-7msfnWZT.css} +1 -1
- package/dist/designer/assets/SvGridChartView-CmsZtCED.js +1 -0
- package/dist/designer/assets/SvGridDropdown-Cjz0H-fI.js +1 -0
- package/dist/designer/assets/SvListBox-BDS66lmZ.js +110 -0
- package/dist/designer/assets/SvMenuList-DJ47ba1h.css +1 -0
- package/dist/designer/assets/SvMenuList-Dgq2D5VN.js +1 -0
- package/dist/designer/assets/SvTabs-2mHC6oaz.js +1 -0
- package/dist/designer/assets/SvTabs-DKmwb5p1.css +1 -0
- package/dist/designer/assets/cell-formatting-BbubJTVz.js +1 -0
- package/dist/designer/assets/chart-Cn7MnNqA.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-Dz7PTIqT.js +1 -0
- package/dist/designer/assets/chart-summary-BD1qYB2R.js +1 -0
- package/dist/designer/assets/chart-trend-B8xr5LuD.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/{dismissable-BO547MH9.js → dismissable-ChWRPkoa.js} +1 -1
- package/dist/designer/assets/editor-contract-Bpoa7A5g.js +1 -0
- package/dist/designer/assets/{export-format-D-eP4b2l.js → export-format-DGckmgKr.js} +1 -1
- package/dist/designer/assets/focus-trap-V2-6Fy9I.js +1 -0
- package/dist/designer/assets/{index-C_a9Cj8Y.js → index-D5bVbuzI.js} +318 -315
- package/dist/designer/assets/index-_JVFxt02.css +1 -0
- package/dist/designer/assets/list-option-BP_dWS66.js +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-CITpcm6b.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 +29 -19
- package/dist/export-pdf.d.ts +164 -0
- package/dist/export-pdf.js +346 -15
- package/dist/export.js +25 -10
- 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 +93 -3
- package/dist/index.js +107 -3
- package/dist/install.js +13 -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 +203 -9
- package/dist/pivot-chart.d.ts +25 -1
- package/dist/pivot-chart.js +25 -69
- 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/address.d.ts +43 -0
- package/dist/sheet/address.js +81 -0
- package/dist/sheet/ast.d.ts +138 -0
- package/dist/sheet/ast.js +70 -0
- package/dist/sheet/auto-filter.d.ts +120 -0
- package/dist/sheet/auto-filter.js +295 -0
- package/dist/sheet/autocomplete.d.ts +51 -0
- package/dist/sheet/autocomplete.js +248 -0
- 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 +71 -0
- package/dist/sheet/coerce.js +289 -0
- package/dist/sheet/commands.d.ts +89 -0
- package/dist/sheet/commands.js +230 -0
- package/dist/sheet/comments.d.ts +63 -0
- package/dist/sheet/comments.js +131 -0
- package/dist/sheet/conditional-formats.d.ts +167 -0
- package/dist/sheet/conditional-formats.js +341 -0
- 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 +104 -0
- package/dist/sheet/deps.js +274 -0
- package/dist/sheet/document.d.ts +252 -0
- package/dist/sheet/document.js +465 -0
- package/dist/sheet/edit-keys.d.ts +14 -0
- package/dist/sheet/edit-keys.js +40 -0
- package/dist/sheet/engine.d.ts +67 -0
- package/dist/sheet/engine.js +19 -0
- package/dist/sheet/entry.d.ts +35 -0
- package/dist/sheet/entry.js +226 -0
- 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 +128 -0
- package/dist/sheet/evaluate.js +1049 -0
- package/dist/sheet/filter-files.d.ts +37 -0
- package/dist/sheet/filter-files.js +465 -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 +114 -0
- package/dist/sheet/format-store.js +243 -0
- package/dist/sheet/freeze.d.ts +54 -0
- package/dist/sheet/freeze.js +58 -0
- package/dist/sheet/from-rows.d.ts +14 -0
- package/dist/sheet/from-rows.js +50 -0
- package/dist/sheet/function-catalog.d.ts +10 -0
- package/dist/sheet/function-catalog.js +385 -0
- package/dist/sheet/functions.d.ts +28 -0
- package/dist/sheet/functions.js +634 -0
- package/dist/sheet/goal-seek.d.ts +73 -0
- package/dist/sheet/goal-seek.js +153 -0
- package/dist/sheet/index.d.ts +80 -0
- package/dist/sheet/index.js +80 -0
- package/dist/sheet/links.d.ts +57 -0
- package/dist/sheet/links.js +174 -0
- package/dist/sheet/merges.d.ts +71 -0
- package/dist/sheet/merges.js +137 -0
- package/dist/sheet/messages.d.ts +778 -0
- package/dist/sheet/messages.js +806 -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 +110 -0
- package/dist/sheet/number-format.js +905 -0
- 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/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 +140 -0
- package/dist/sheet/paste-special.d.ts +186 -0
- package/dist/sheet/paste-special.js +601 -0
- 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 +75 -0
- package/dist/sheet/protection.js +101 -0
- package/dist/sheet/rects.d.ts +45 -0
- package/dist/sheet/rects.js +112 -0
- package/dist/sheet/refs.d.ts +130 -0
- package/dist/sheet/refs.js +413 -0
- package/dist/sheet/ribbon-icons.d.ts +31 -0
- package/dist/sheet/ribbon-icons.js +536 -0
- package/dist/sheet/ribbon.d.ts +173 -0
- package/dist/sheet/ribbon.js +1054 -0
- package/dist/sheet/sheet-kinds.d.ts +74 -0
- package/dist/sheet/sheet-kinds.js +91 -0
- package/dist/sheet/shortcuts.d.ts +174 -0
- package/dist/sheet/shortcuts.js +674 -0
- 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/structure.d.ts +87 -0
- package/dist/sheet/structure.js +166 -0
- package/dist/sheet/table-styles.d.ts +74 -0
- package/dist/sheet/table-styles.js +152 -0
- package/dist/sheet/tables.d.ts +89 -0
- package/dist/sheet/tables.js +178 -0
- package/dist/sheet/tokenize.d.ts +71 -0
- package/dist/sheet/tokenize.js +355 -0
- package/dist/sheet/transforms.d.ts +76 -0
- package/dist/sheet/transforms.js +154 -0
- package/dist/sheet/validation.d.ts +108 -0
- package/dist/sheet/validation.js +278 -0
- package/dist/sheet/workbook.d.ts +217 -0
- package/dist/sheet/workbook.js +1120 -0
- 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.d.ts +6 -0
- package/dist/sheet-enable.js +45 -0
- 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 +170 -3
- 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 +36 -6
- package/dist/designer/assets/GridMenus-B1JtIN21.js +0 -8
- package/dist/designer/assets/SvDateRangeInput-CjO7nn_x.js +0 -1
- package/dist/designer/assets/SvDateTimePicker-ByBD_ov6.js +0 -1
- package/dist/designer/assets/SvField-YDLipR6O.css +0 -1
- package/dist/designer/assets/SvField-cj1PFNgZ.js +0 -1
- package/dist/designer/assets/SvGridCellEditor-0W1L2hJ1.js +0 -2
- package/dist/designer/assets/SvGridChart-DBOR4xcz.js +0 -2
- package/dist/designer/assets/SvGridChart-fkMWeh1J.css +0 -1
- package/dist/designer/assets/SvGridChartPanel-symrhNnR.js +0 -11
- package/dist/designer/assets/SvGridChartView-BmRxq6mU.js +0 -1
- package/dist/designer/assets/SvGridDropdown-Bb3HH2Aj.js +0 -1
- package/dist/designer/assets/SvListBox-1oUF6Iav.js +0 -110
- package/dist/designer/assets/cell-formatting-wr5wm7US.js +0 -1
- package/dist/designer/assets/chart-DXFganU8.js +0 -1
- package/dist/designer/assets/column-resize-C_inr5zT.js +0 -1
- package/dist/designer/assets/date-format-DGagAqRc.css +0 -1
- package/dist/designer/assets/date-format-onlYDsrY.js +0 -1
- package/dist/designer/assets/easing-zaypKrr0.js +0 -3
- package/dist/designer/assets/index-k2stW6L8.css +0 -1
- package/dist/designer/assets/row-resize-B0FWHcNr.js +0 -1
- package/dist/designer/assets/src-D9p27OGC.js +0 -58
- package/dist/designer/assets/validate-h-aslRV9.js +0 -1
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Excel's `IMAGE` function: a picture IN a cell rather than floating over
|
|
3
|
+
* it.
|
|
4
|
+
*
|
|
5
|
+
* The difference is the whole point. A picture object hangs from a cell and
|
|
6
|
+
* covers whatever is under it; an `IMAGE` cell IS the picture, so it sorts
|
|
7
|
+
* with its row, filters with it, copies as a formula and moves when the
|
|
8
|
+
* cells move, with nothing to keep in step. A catalogue with a thumbnail
|
|
9
|
+
* column wants this one.
|
|
10
|
+
*
|
|
11
|
+
* The function answers with the source, which is what makes `=IMAGE(A2)`
|
|
12
|
+
* read like any other formula: the value is text, `ISTEXT` says so, and a
|
|
13
|
+
* cell that reads it gets the address rather than a picture it cannot use.
|
|
14
|
+
* Drawing it is the shell's part, and this is what the shell reads to know
|
|
15
|
+
* a cell is one.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* The call's arguments when a formula IS one `IMAGE(...)` call, or null.
|
|
19
|
+
*
|
|
20
|
+
* Read off the text rather than the parsed tree on purpose: this runs for
|
|
21
|
+
* every cell that paints, and a scan is cheaper than a parse. A formula
|
|
22
|
+
* that merely CONTAINS an IMAGE call (`=IF(A1, IMAGE(B1), "")`) is not one,
|
|
23
|
+
* because its value is not a picture in every case.
|
|
24
|
+
*/
|
|
25
|
+
export function imageCall(text) {
|
|
26
|
+
const trimmed = text.trim();
|
|
27
|
+
const head = /^=\s*IMAGE\s*\(/i.exec(trimmed);
|
|
28
|
+
if (!head)
|
|
29
|
+
return null;
|
|
30
|
+
const inside = trimmed.slice(head[0].length);
|
|
31
|
+
const args = [];
|
|
32
|
+
let depth = 0;
|
|
33
|
+
let quoted = false;
|
|
34
|
+
let start = 0;
|
|
35
|
+
let closed = -1;
|
|
36
|
+
for (let i = 0; i < inside.length; i += 1) {
|
|
37
|
+
const ch = inside[i];
|
|
38
|
+
if (quoted) {
|
|
39
|
+
if (ch === '"') {
|
|
40
|
+
if (inside[i + 1] === '"')
|
|
41
|
+
i += 1;
|
|
42
|
+
else
|
|
43
|
+
quoted = false;
|
|
44
|
+
}
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (ch === '"') {
|
|
48
|
+
quoted = true;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (ch === '(') {
|
|
52
|
+
depth += 1;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (ch === ')') {
|
|
56
|
+
if (depth === 0) {
|
|
57
|
+
args.push(inside.slice(start, i));
|
|
58
|
+
closed = i;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
depth -= 1;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (ch === ',' && depth === 0) {
|
|
65
|
+
args.push(inside.slice(start, i));
|
|
66
|
+
start = i + 1;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Anything after the closing bracket means the call is part of a larger
|
|
70
|
+
// formula, so the cell is not simply a picture.
|
|
71
|
+
if (closed < 0 || inside.slice(closed + 1).trim() !== '')
|
|
72
|
+
return null;
|
|
73
|
+
const source = (args[0] ?? '').trim();
|
|
74
|
+
if (!source)
|
|
75
|
+
return null;
|
|
76
|
+
const alt = (args[1] ?? '').trim();
|
|
77
|
+
return { source, ...(alt ? { alt } : {}) };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Whether a source is one a browser will load. A `data:` URL and an
|
|
81
|
+
* ordinary web address are; anything else (a file path, a `javascript:`
|
|
82
|
+
* scheme) is not, and a cell showing it as text says more than a broken
|
|
83
|
+
* image would.
|
|
84
|
+
*/
|
|
85
|
+
export function isDrawableImageSource(source) {
|
|
86
|
+
const value = source.trim();
|
|
87
|
+
if (/^data:image\//i.test(value))
|
|
88
|
+
return true;
|
|
89
|
+
return /^https?:\/\/\S+$/i.test(value);
|
|
90
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { StructuralEdit } from './refs.js';
|
|
2
|
+
import { type Rect } from './rects.js';
|
|
3
|
+
/** Excel writes a ticked box as TRUE and an unticked one as FALSE. */
|
|
4
|
+
export declare const CHECKED = "TRUE";
|
|
5
|
+
export declare const UNCHECKED = "FALSE";
|
|
6
|
+
export type CellTypeKind = 'checkbox' | 'button' | 'radio';
|
|
7
|
+
export type CellTypeRegion = {
|
|
8
|
+
id: string;
|
|
9
|
+
rects: ReadonlyArray<Rect>;
|
|
10
|
+
kind: CellTypeKind;
|
|
11
|
+
/**
|
|
12
|
+
* A checkbox's two values, when the sheet wants something other than
|
|
13
|
+
* Excel's TRUE and FALSE (a Yes / No column, say). Compared as text,
|
|
14
|
+
* ignoring case, the way the engine compares a boolean typed by hand.
|
|
15
|
+
*/
|
|
16
|
+
checked?: string;
|
|
17
|
+
unchecked?: string;
|
|
18
|
+
/** A button's face. The cell's own text when this is absent. */
|
|
19
|
+
label?: string;
|
|
20
|
+
/** What a button press reports through `onCellAction`. */
|
|
21
|
+
action?: string;
|
|
22
|
+
/** A radio group's choices, in order. */
|
|
23
|
+
choices?: ReadonlyArray<string>;
|
|
24
|
+
};
|
|
25
|
+
export declare const newCellTypeId: () => string;
|
|
26
|
+
/** The region that applies at a cell, or null. The last one wins. */
|
|
27
|
+
export declare function cellTypeAt(regions: ReadonlyArray<CellTypeRegion>, row: number, col: number): CellTypeRegion | null;
|
|
28
|
+
/** The two texts a checkbox toggles between, Excel's by default. */
|
|
29
|
+
export declare const checkboxValues: (region: CellTypeRegion) => {
|
|
30
|
+
on: string;
|
|
31
|
+
off: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Is the cell ticked?
|
|
35
|
+
*
|
|
36
|
+
* Read off the cell's own text so a formula, a paste or a typed TRUE all
|
|
37
|
+
* show the same way. Anything that is not the ticked value reads as
|
|
38
|
+
* unticked, which is what Excel does with a stray entry.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isChecked(region: CellTypeRegion, raw: string): boolean;
|
|
41
|
+
/** What clicking a checkbox should write into its cell. */
|
|
42
|
+
export declare function toggledValue(region: CellTypeRegion, raw: string): string;
|
|
43
|
+
/** Which radio choice a cell holds, or -1. Compared ignoring case. */
|
|
44
|
+
export declare function radioIndex(region: CellTypeRegion, raw: string): number;
|
|
45
|
+
/** The regions after an insert or delete, moved the way the rules move. */
|
|
46
|
+
export declare function shiftCellTypes(regions: ReadonlyArray<CellTypeRegion>, edit: StructuralEdit): CellTypeRegion[];
|
|
47
|
+
/** The regions with the rectangles cut out: what Clear All removes. */
|
|
48
|
+
export declare function removeCellTypes(regions: ReadonlyArray<CellTypeRegion>, rects: ReadonlyArray<Rect>): CellTypeRegion[];
|
|
49
|
+
/**
|
|
50
|
+
* Lay a region over some cells, taking those cells out of any region that
|
|
51
|
+
* already claimed them.
|
|
52
|
+
*
|
|
53
|
+
* Without the cut, two regions would overlap and the later one would win
|
|
54
|
+
* silently; cutting makes the model say what the screen shows.
|
|
55
|
+
*/
|
|
56
|
+
export declare function applyCellType(regions: ReadonlyArray<CellTypeRegion>, region: CellTypeRegion): CellTypeRegion[];
|
|
57
|
+
/** A deep-enough copy for the document's snapshot. */
|
|
58
|
+
export declare const copyCellType: (region: CellTypeRegion) => CellTypeRegion;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a cell IS, rather than what it holds: a checkbox, a button or a
|
|
3
|
+
* group of radio choices drawn in the cell and driven from it.
|
|
4
|
+
*
|
|
5
|
+
* Excel has one of these, the checkbox its Insert tab puts in a cell, and
|
|
6
|
+
* it is deliberately thin: the cell's value is still `TRUE` or `FALSE`, so
|
|
7
|
+
* every formula over it keeps working and the file carries an ordinary
|
|
8
|
+
* boolean. That is the model here, widened to the two other controls a
|
|
9
|
+
* data-entry sheet actually asks for.
|
|
10
|
+
*
|
|
11
|
+
* The rule that keeps this honest: **a cell type is a rendering, never a
|
|
12
|
+
* second source of truth.** A checkbox is ticked because its cell reads
|
|
13
|
+
* TRUE, not because the checkbox remembers being clicked; a radio is on
|
|
14
|
+
* because the cell holds its choice. Clicking one writes the cell and
|
|
15
|
+
* nothing else, so undo, the formula engine, a paste and the file all keep
|
|
16
|
+
* working without knowing this module exists.
|
|
17
|
+
*
|
|
18
|
+
* Regions are kept and moved the way validation rules are, and the LAST
|
|
19
|
+
* region covering a cell wins, so a narrower one laid over a wider one
|
|
20
|
+
* overrides it.
|
|
21
|
+
*/
|
|
22
|
+
import { toText } from './coerce.js';
|
|
23
|
+
import { rectContains, shiftRects, subtractRect } from './rects.js';
|
|
24
|
+
/** Excel writes a ticked box as TRUE and an unticked one as FALSE. */
|
|
25
|
+
export const CHECKED = 'TRUE';
|
|
26
|
+
export const UNCHECKED = 'FALSE';
|
|
27
|
+
let counter = 0;
|
|
28
|
+
export const newCellTypeId = () => `ct${(counter += 1)}`;
|
|
29
|
+
/** The region that applies at a cell, or null. The last one wins. */
|
|
30
|
+
export function cellTypeAt(regions, row, col) {
|
|
31
|
+
for (let i = regions.length - 1; i >= 0; i -= 1) {
|
|
32
|
+
const region = regions[i];
|
|
33
|
+
if (region.rects.some((rect) => rectContains(rect, row, col)))
|
|
34
|
+
return region;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
/** The two texts a checkbox toggles between, Excel's by default. */
|
|
39
|
+
export const checkboxValues = (region) => ({
|
|
40
|
+
on: region.checked ?? CHECKED,
|
|
41
|
+
off: region.unchecked ?? UNCHECKED,
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* Is the cell ticked?
|
|
45
|
+
*
|
|
46
|
+
* Read off the cell's own text so a formula, a paste or a typed TRUE all
|
|
47
|
+
* show the same way. Anything that is not the ticked value reads as
|
|
48
|
+
* unticked, which is what Excel does with a stray entry.
|
|
49
|
+
*/
|
|
50
|
+
export function isChecked(region, raw) {
|
|
51
|
+
const { on } = checkboxValues(region);
|
|
52
|
+
return toText(raw).trim().toLowerCase() === on.trim().toLowerCase();
|
|
53
|
+
}
|
|
54
|
+
/** What clicking a checkbox should write into its cell. */
|
|
55
|
+
export function toggledValue(region, raw) {
|
|
56
|
+
const { on, off } = checkboxValues(region);
|
|
57
|
+
return isChecked(region, raw) ? off : on;
|
|
58
|
+
}
|
|
59
|
+
/** Which radio choice a cell holds, or -1. Compared ignoring case. */
|
|
60
|
+
export function radioIndex(region, raw) {
|
|
61
|
+
const choices = region.choices ?? [];
|
|
62
|
+
const value = toText(raw).trim().toLowerCase();
|
|
63
|
+
return choices.findIndex((choice) => choice.trim().toLowerCase() === value);
|
|
64
|
+
}
|
|
65
|
+
/** The regions after an insert or delete, moved the way the rules move. */
|
|
66
|
+
export function shiftCellTypes(regions, edit) {
|
|
67
|
+
return shiftRects(regions, edit);
|
|
68
|
+
}
|
|
69
|
+
/** The regions with the rectangles cut out: what Clear All removes. */
|
|
70
|
+
export function removeCellTypes(regions, rects) {
|
|
71
|
+
const out = [];
|
|
72
|
+
for (const region of regions) {
|
|
73
|
+
let kept = [...region.rects];
|
|
74
|
+
for (const hole of rects)
|
|
75
|
+
kept = kept.flatMap((rect) => subtractRect(rect, hole));
|
|
76
|
+
if (kept.length)
|
|
77
|
+
out.push({ ...region, rects: kept });
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Lay a region over some cells, taking those cells out of any region that
|
|
83
|
+
* already claimed them.
|
|
84
|
+
*
|
|
85
|
+
* Without the cut, two regions would overlap and the later one would win
|
|
86
|
+
* silently; cutting makes the model say what the screen shows.
|
|
87
|
+
*/
|
|
88
|
+
export function applyCellType(regions, region) {
|
|
89
|
+
return [...removeCellTypes(regions, region.rects), region];
|
|
90
|
+
}
|
|
91
|
+
/** A deep-enough copy for the document's snapshot. */
|
|
92
|
+
export const copyCellType = (region) => ({
|
|
93
|
+
...region,
|
|
94
|
+
rects: region.rects.map((rect) => [...rect]),
|
|
95
|
+
...(region.choices ? { choices: [...region.choices] } : {}),
|
|
96
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Value coercions, shared by the evaluator and the function table.
|
|
3
|
+
*
|
|
4
|
+
* Excel's rules, not JavaScript's. The differences that matter:
|
|
5
|
+
* - An empty cell is 0 in arithmetic but is NOT counted by COUNT or averaged
|
|
6
|
+
* by AVERAGE, so "coerce to number" and "is a number" are separate tests.
|
|
7
|
+
* - Text that does not parse as a number is `#VALUE!`, not NaN. Returning NaN
|
|
8
|
+
* would let a bad cell poison a total silently.
|
|
9
|
+
* - Text comparison is case-insensitive: `="a"="A"` is TRUE.
|
|
10
|
+
* - Booleans are 1 and 0 in arithmetic but are skipped by numeric aggregates.
|
|
11
|
+
*/
|
|
12
|
+
import { type CellValue } from './ast.js';
|
|
13
|
+
/** A date from a cell: a serial number, or text `new Date` can read
|
|
14
|
+
* (`2024-03-09`, `2024-03-09 13:45`). Anything else is `#VALUE!`. */
|
|
15
|
+
export declare function toDate(v: CellValue): Date;
|
|
16
|
+
/** The `yyyy-mm-dd` the date functions hand back. */
|
|
17
|
+
export declare const isoDate: (d: Date) => string;
|
|
18
|
+
/** Excel's serial for a date, fractional when it carries a time. */
|
|
19
|
+
export declare function dateSerial(d: Date): number;
|
|
20
|
+
/**
|
|
21
|
+
* The serial a date or a time written as text is worth in arithmetic, or
|
|
22
|
+
* null when the text is neither. Dates are `yyyy-mm-dd` text in a sheet
|
|
23
|
+
* (see `toDate`), so `=A1+1` under one has to read it as Excel reads a
|
|
24
|
+
* date cell: as its day number, so the sum is the next day rather than
|
|
25
|
+
* `#VALUE!`. A clock time is the fraction of a day it is, `="10:30"*2` being
|
|
26
|
+
* 0.875, and `m/d/yyyy` is read the way `new Date` reads it, as toDate does.
|
|
27
|
+
*/
|
|
28
|
+
export declare function dateTextSerial(text: string): number | null;
|
|
29
|
+
export declare function toNumber(v: CellValue): number;
|
|
30
|
+
export declare function toBool(v: CellValue): boolean;
|
|
31
|
+
export declare function toText(v: CellValue): string;
|
|
32
|
+
/** Excel's `=` between two values. Text compares case-insensitively; a number
|
|
33
|
+
* never equals the text that looks like it. */
|
|
34
|
+
export declare function looseEquals(a: CellValue, b: CellValue): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Excel's wildcards, which every text criterion and exact lookup speaks:
|
|
37
|
+
* `*` stands for any run of characters, `?` for exactly one, and `~` asks
|
|
38
|
+
* for the next character itself, so `"~*"` is a literal asterisk.
|
|
39
|
+
*/
|
|
40
|
+
export declare function hasWildcards(pattern: string): boolean;
|
|
41
|
+
/** The pattern as a regular expression, anchored at both ends and
|
|
42
|
+
* case-insensitive, which is how Excel compares text. */
|
|
43
|
+
export declare function wildcardRegExp(pattern: string): RegExp;
|
|
44
|
+
/** The pattern with its `~` escapes taken off, which is the text a plain
|
|
45
|
+
* comparison should look for: `"~*"` means a literal asterisk. */
|
|
46
|
+
export declare function unescapeWildcards(pattern: string): string;
|
|
47
|
+
/** Does this cell match a wildcard pattern? Only text takes part: Excel
|
|
48
|
+
* never turns a number into text to match `"1*"`. */
|
|
49
|
+
export declare function wildcardMatches(value: CellValue, pattern: string): boolean;
|
|
50
|
+
/** Equality as a criterion or an exact lookup reads it: a pattern carrying
|
|
51
|
+
* wildcards matches, anything else compares as `=` does. */
|
|
52
|
+
export declare function patternEquals(value: CellValue, operand: CellValue): boolean;
|
|
53
|
+
/** Ordering for `<` and friends. Excel orders number < text < boolean. */
|
|
54
|
+
export declare function compare(a: CellValue, b: CellValue): number;
|
|
55
|
+
/** The numeric members of a flattened argument list. Blanks, text and booleans
|
|
56
|
+
* are skipped, which is what makes AVERAGE of a column with a header work. */
|
|
57
|
+
export declare function numericOnly(values: ReadonlyArray<CellValue>): number[];
|
|
58
|
+
/** Is this cell empty for COUNTA / COUNTBLANK purposes. */
|
|
59
|
+
export declare function isBlank(v: CellValue): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* An Excel criterion: a bare value matches by equality, a string starting with
|
|
62
|
+
* an operator compares (`">100"`, `"<>x"`). Used by SUMIF / COUNTIF / their
|
|
63
|
+
* plural forms, which all share this grammar.
|
|
64
|
+
*/
|
|
65
|
+
export declare function matchesCriterion(value: CellValue, criterion: CellValue): boolean;
|
|
66
|
+
/** The indexes in `range` that meet `criterion`, for the IF family. */
|
|
67
|
+
export declare function criteriaHits(range: ReadonlyArray<CellValue>, criterion: CellValue): number[];
|
|
68
|
+
/** SUMIFS and its family: every (range, criterion) pair must match at an index. */
|
|
69
|
+
export declare function multiCriteriaHits(pairs: Array<[ReadonlyArray<CellValue>, CellValue]>): number[];
|
|
70
|
+
/** The (range, criterion) pairs of a *IFS call, starting at argument `from`. */
|
|
71
|
+
export declare function criteriaPairs(args: ReadonlyArray<ReadonlyArray<CellValue>>, from: number): Array<[ReadonlyArray<CellValue>, CellValue]>;
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Value coercions, shared by the evaluator and the function table.
|
|
3
|
+
*
|
|
4
|
+
* Excel's rules, not JavaScript's. The differences that matter:
|
|
5
|
+
* - An empty cell is 0 in arithmetic but is NOT counted by COUNT or averaged
|
|
6
|
+
* by AVERAGE, so "coerce to number" and "is a number" are separate tests.
|
|
7
|
+
* - Text that does not parse as a number is `#VALUE!`, not NaN. Returning NaN
|
|
8
|
+
* would let a bad cell poison a total silently.
|
|
9
|
+
* - Text comparison is case-insensitive: `="a"="A"` is TRUE.
|
|
10
|
+
* - Booleans are 1 and 0 in arithmetic but are skipped by numeric aggregates.
|
|
11
|
+
*/
|
|
12
|
+
import { FormulaError, isError } from './ast.js';
|
|
13
|
+
/** The epoch Excel's date serials count from: serial 1 is 1900-01-01. Day 60
|
|
14
|
+
* is Excel's phantom 1900-02-29, so every date from 1900-03-01 on is right
|
|
15
|
+
* and the two months before it are a day out, which no sheet has cared
|
|
16
|
+
* about. */
|
|
17
|
+
const EXCEL_EPOCH_MS = Date.UTC(1899, 11, 30);
|
|
18
|
+
/** A date from a cell: a serial number, or text `new Date` can read
|
|
19
|
+
* (`2024-03-09`, `2024-03-09 13:45`). Anything else is `#VALUE!`. */
|
|
20
|
+
export function toDate(v) {
|
|
21
|
+
if (typeof v === 'number')
|
|
22
|
+
return new Date(EXCEL_EPOCH_MS + v * 86400000);
|
|
23
|
+
const d = new Date(toText(v));
|
|
24
|
+
if (Number.isNaN(d.getTime()))
|
|
25
|
+
throw new FormulaError('#VALUE!');
|
|
26
|
+
return d;
|
|
27
|
+
}
|
|
28
|
+
/** The `yyyy-mm-dd` the date functions hand back. */
|
|
29
|
+
export const isoDate = (d) => d.toISOString().slice(0, 10);
|
|
30
|
+
/** Excel's serial for a date, fractional when it carries a time. */
|
|
31
|
+
export function dateSerial(d) {
|
|
32
|
+
return (d.getTime() - EXCEL_EPOCH_MS) / 86400000;
|
|
33
|
+
}
|
|
34
|
+
const ISO_DATE_TEXT = /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{1,2}):(\d{2})(?::(\d{2}))?)?$/;
|
|
35
|
+
const SLASH_DATE_TEXT = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/;
|
|
36
|
+
const CLOCK_TEXT = /^(\d{1,2}):(\d{2})(?::(\d{2}))?$/;
|
|
37
|
+
/**
|
|
38
|
+
* The serial a date or a time written as text is worth in arithmetic, or
|
|
39
|
+
* null when the text is neither. Dates are `yyyy-mm-dd` text in a sheet
|
|
40
|
+
* (see `toDate`), so `=A1+1` under one has to read it as Excel reads a
|
|
41
|
+
* date cell: as its day number, so the sum is the next day rather than
|
|
42
|
+
* `#VALUE!`. A clock time is the fraction of a day it is, `="10:30"*2` being
|
|
43
|
+
* 0.875, and `m/d/yyyy` is read the way `new Date` reads it, as toDate does.
|
|
44
|
+
*/
|
|
45
|
+
export function dateTextSerial(text) {
|
|
46
|
+
const t = text.trim();
|
|
47
|
+
let m = ISO_DATE_TEXT.exec(t);
|
|
48
|
+
if (m) {
|
|
49
|
+
const month = Number(m[2]), day = Number(m[3]), hours = Number(m[4] ?? 0), minutes = Number(m[5] ?? 0);
|
|
50
|
+
if (month < 1 || month > 12 || day < 1 || day > 31 || hours > 23 || minutes > 59)
|
|
51
|
+
return null;
|
|
52
|
+
const ms = Date.UTC(Number(m[1]), month - 1, day, hours, minutes, Number(m[6] ?? 0));
|
|
53
|
+
return (ms - EXCEL_EPOCH_MS) / 86400000;
|
|
54
|
+
}
|
|
55
|
+
m = SLASH_DATE_TEXT.exec(t);
|
|
56
|
+
if (m) {
|
|
57
|
+
const month = Number(m[1]), day = Number(m[2]);
|
|
58
|
+
if (month < 1 || month > 12 || day < 1 || day > 31)
|
|
59
|
+
return null;
|
|
60
|
+
return (Date.UTC(Number(m[3]), month - 1, day) - EXCEL_EPOCH_MS) / 86400000;
|
|
61
|
+
}
|
|
62
|
+
m = CLOCK_TEXT.exec(t);
|
|
63
|
+
if (m) {
|
|
64
|
+
const hours = Number(m[1]), minutes = Number(m[2]), seconds = Number(m[3] ?? 0);
|
|
65
|
+
if (hours > 23 || minutes > 59 || seconds > 59)
|
|
66
|
+
return null;
|
|
67
|
+
return (hours * 3600 + minutes * 60 + seconds) / 86400;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
export function toNumber(v) {
|
|
72
|
+
if (typeof v === 'number')
|
|
73
|
+
return v;
|
|
74
|
+
if (typeof v === 'boolean')
|
|
75
|
+
return v ? 1 : 0;
|
|
76
|
+
if (typeof v === 'string') {
|
|
77
|
+
if (v.trim() === '')
|
|
78
|
+
return 0;
|
|
79
|
+
const n = Number(v);
|
|
80
|
+
if (Number.isFinite(n))
|
|
81
|
+
return n;
|
|
82
|
+
const serial = dateTextSerial(v);
|
|
83
|
+
if (serial !== null)
|
|
84
|
+
return serial;
|
|
85
|
+
throw new FormulaError('#VALUE!');
|
|
86
|
+
}
|
|
87
|
+
if (isError(v))
|
|
88
|
+
throw new FormulaError(v.error);
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
export function toBool(v) {
|
|
92
|
+
if (typeof v === 'boolean')
|
|
93
|
+
return v;
|
|
94
|
+
if (typeof v === 'number')
|
|
95
|
+
return v !== 0;
|
|
96
|
+
if (typeof v === 'string') {
|
|
97
|
+
const upper = v.trim().toUpperCase();
|
|
98
|
+
if (upper === 'TRUE')
|
|
99
|
+
return true;
|
|
100
|
+
if (upper === 'FALSE')
|
|
101
|
+
return false;
|
|
102
|
+
return v.length > 0;
|
|
103
|
+
}
|
|
104
|
+
if (isError(v))
|
|
105
|
+
throw new FormulaError(v.error);
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
export function toText(v) {
|
|
109
|
+
if (typeof v === 'string')
|
|
110
|
+
return v;
|
|
111
|
+
if (typeof v === 'boolean')
|
|
112
|
+
return v ? 'TRUE' : 'FALSE';
|
|
113
|
+
if (typeof v === 'number')
|
|
114
|
+
return String(v);
|
|
115
|
+
if (isError(v))
|
|
116
|
+
throw new FormulaError(v.error);
|
|
117
|
+
return '';
|
|
118
|
+
}
|
|
119
|
+
/** Excel's `=` between two values. Text compares case-insensitively; a number
|
|
120
|
+
* never equals the text that looks like it. */
|
|
121
|
+
export function looseEquals(a, b) {
|
|
122
|
+
if (typeof a === 'number' && typeof b === 'number')
|
|
123
|
+
return a === b;
|
|
124
|
+
if (typeof a === 'string' && typeof b === 'string') {
|
|
125
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
126
|
+
}
|
|
127
|
+
if (typeof a === 'boolean' && typeof b === 'boolean')
|
|
128
|
+
return a === b;
|
|
129
|
+
if (isError(a) || isError(b))
|
|
130
|
+
return false;
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Excel's wildcards, which every text criterion and exact lookup speaks:
|
|
135
|
+
* `*` stands for any run of characters, `?` for exactly one, and `~` asks
|
|
136
|
+
* for the next character itself, so `"~*"` is a literal asterisk.
|
|
137
|
+
*/
|
|
138
|
+
export function hasWildcards(pattern) {
|
|
139
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
140
|
+
const ch = pattern[i];
|
|
141
|
+
if (ch === '~') {
|
|
142
|
+
i += 1;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (ch === '*' || ch === '?')
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
const LITERAL = /[\\^$.*+?()[\]{}|]/g;
|
|
151
|
+
/** The pattern as a regular expression, anchored at both ends and
|
|
152
|
+
* case-insensitive, which is how Excel compares text. */
|
|
153
|
+
export function wildcardRegExp(pattern) {
|
|
154
|
+
let out = '';
|
|
155
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
156
|
+
const ch = pattern[i];
|
|
157
|
+
if (ch === '~' && i + 1 < pattern.length) {
|
|
158
|
+
out += pattern[i + 1].replace(LITERAL, '\\$&');
|
|
159
|
+
i += 1;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (ch === '*') {
|
|
163
|
+
out += '[\\s\\S]*';
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (ch === '?') {
|
|
167
|
+
out += '[\\s\\S]';
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
out += ch.replace(LITERAL, '\\$&');
|
|
171
|
+
}
|
|
172
|
+
return new RegExp(`^${out}$`, 'i');
|
|
173
|
+
}
|
|
174
|
+
/** The pattern with its `~` escapes taken off, which is the text a plain
|
|
175
|
+
* comparison should look for: `"~*"` means a literal asterisk. */
|
|
176
|
+
export function unescapeWildcards(pattern) {
|
|
177
|
+
if (!pattern.includes('~'))
|
|
178
|
+
return pattern;
|
|
179
|
+
let out = '';
|
|
180
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
181
|
+
const ch = pattern[i];
|
|
182
|
+
if (ch === '~' && i + 1 < pattern.length) {
|
|
183
|
+
out += pattern[i + 1];
|
|
184
|
+
i += 1;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
out += ch;
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
/** Does this cell match a wildcard pattern? Only text takes part: Excel
|
|
192
|
+
* never turns a number into text to match `"1*"`. */
|
|
193
|
+
export function wildcardMatches(value, pattern) {
|
|
194
|
+
if (typeof value !== 'string')
|
|
195
|
+
return false;
|
|
196
|
+
return wildcardRegExp(pattern).test(value);
|
|
197
|
+
}
|
|
198
|
+
/** Equality as a criterion or an exact lookup reads it: a pattern carrying
|
|
199
|
+
* wildcards matches, anything else compares as `=` does. */
|
|
200
|
+
export function patternEquals(value, operand) {
|
|
201
|
+
if (typeof operand !== 'string')
|
|
202
|
+
return looseEquals(value, operand);
|
|
203
|
+
if (hasWildcards(operand))
|
|
204
|
+
return wildcardMatches(value, operand);
|
|
205
|
+
return looseEquals(value, unescapeWildcards(operand));
|
|
206
|
+
}
|
|
207
|
+
/** Ordering for `<` and friends. Excel orders number < text < boolean. */
|
|
208
|
+
export function compare(a, b) {
|
|
209
|
+
if (typeof a === 'number' && typeof b === 'number')
|
|
210
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
211
|
+
if (typeof a === 'string' && typeof b === 'string') {
|
|
212
|
+
const x = a.toLowerCase();
|
|
213
|
+
const y = b.toLowerCase();
|
|
214
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
215
|
+
}
|
|
216
|
+
return toNumber(a) < toNumber(b) ? -1 : toNumber(a) > toNumber(b) ? 1 : 0;
|
|
217
|
+
}
|
|
218
|
+
/** The numeric members of a flattened argument list. Blanks, text and booleans
|
|
219
|
+
* are skipped, which is what makes AVERAGE of a column with a header work. */
|
|
220
|
+
export function numericOnly(values) {
|
|
221
|
+
const out = [];
|
|
222
|
+
for (const v of values) {
|
|
223
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
224
|
+
out.push(v);
|
|
225
|
+
}
|
|
226
|
+
return out;
|
|
227
|
+
}
|
|
228
|
+
/** Is this cell empty for COUNTA / COUNTBLANK purposes. */
|
|
229
|
+
export function isBlank(v) {
|
|
230
|
+
return v === '' || v === null || v === undefined;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* An Excel criterion: a bare value matches by equality, a string starting with
|
|
234
|
+
* an operator compares (`">100"`, `"<>x"`). Used by SUMIF / COUNTIF / their
|
|
235
|
+
* plural forms, which all share this grammar.
|
|
236
|
+
*/
|
|
237
|
+
export function matchesCriterion(value, criterion) {
|
|
238
|
+
if (typeof criterion === 'string') {
|
|
239
|
+
const m = /^(<=|>=|<>|<|>|=)(.*)$/.exec(criterion.trim());
|
|
240
|
+
if (m) {
|
|
241
|
+
const opText = m[1];
|
|
242
|
+
const rest = m[2].trim();
|
|
243
|
+
const n = Number(rest);
|
|
244
|
+
const operand = rest !== '' && Number.isFinite(n) ? n : rest;
|
|
245
|
+
switch (opText) {
|
|
246
|
+
case '=': return patternEquals(value, operand);
|
|
247
|
+
case '<>': return !patternEquals(value, operand);
|
|
248
|
+
case '<': return compare(value, operand) < 0;
|
|
249
|
+
case '>': return compare(value, operand) > 0;
|
|
250
|
+
case '<=': return compare(value, operand) <= 0;
|
|
251
|
+
case '>=': return compare(value, operand) >= 0;
|
|
252
|
+
default: break;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return patternEquals(value, criterion);
|
|
257
|
+
}
|
|
258
|
+
/** The indexes in `range` that meet `criterion`, for the IF family. */
|
|
259
|
+
export function criteriaHits(range, criterion) {
|
|
260
|
+
const out = [];
|
|
261
|
+
for (let i = 0; i < range.length; i += 1) {
|
|
262
|
+
if (matchesCriterion(range[i], criterion))
|
|
263
|
+
out.push(i);
|
|
264
|
+
}
|
|
265
|
+
return out;
|
|
266
|
+
}
|
|
267
|
+
/** SUMIFS and its family: every (range, criterion) pair must match at an index. */
|
|
268
|
+
export function multiCriteriaHits(pairs) {
|
|
269
|
+
const firstPair = pairs[0];
|
|
270
|
+
if (!firstPair)
|
|
271
|
+
return [];
|
|
272
|
+
const out = [];
|
|
273
|
+
for (let i = 0; i < firstPair[0].length; i += 1) {
|
|
274
|
+
if (pairs.every(([range, crit]) => matchesCriterion(range[i] ?? '', crit)))
|
|
275
|
+
out.push(i);
|
|
276
|
+
}
|
|
277
|
+
return out;
|
|
278
|
+
}
|
|
279
|
+
/** The (range, criterion) pairs of a *IFS call, starting at argument `from`. */
|
|
280
|
+
export function criteriaPairs(args, from) {
|
|
281
|
+
const pairs = [];
|
|
282
|
+
for (let i = from; i < args.length; i += 2) {
|
|
283
|
+
const range = args[i];
|
|
284
|
+
if (!range)
|
|
285
|
+
break;
|
|
286
|
+
pairs.push([range, args[i + 1]?.[0] ?? '']);
|
|
287
|
+
}
|
|
288
|
+
return pairs;
|
|
289
|
+
}
|