@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,421 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Excel's Format Cells, the six tabs that have something behind them in
|
|
4
|
+
* the sheet: Number, Alignment, Font, Border, Fill, Protection. It opens on the active
|
|
5
|
+
* cell's format and, on OK, applies only what was changed to the whole
|
|
6
|
+
* selection, so setting a fill on a block with mixed fonts leaves the
|
|
7
|
+
* fonts as they were. One undo, through `applyFormat`.
|
|
8
|
+
*
|
|
9
|
+
* The shell opens it for Ctrl+1, the group launchers on the ribbon, the
|
|
10
|
+
* cell menu's Format Cells... and the `format-cells` action.
|
|
11
|
+
*/
|
|
12
|
+
import { SvModal } from '@svgrid/grid'
|
|
13
|
+
import type { CellFormatEntry } from './sheet/format-store'
|
|
14
|
+
import { compileNumberFormat, FORMAT_PRESETS, formatCategory } from './sheet/number-format'
|
|
15
|
+
import { FONT_FAMILIES, FONT_SIZES, type BorderPreset } from './sheet/ribbon'
|
|
16
|
+
import { ALL_COLOURS } from './sheet/palette'
|
|
17
|
+
|
|
18
|
+
type Props = {
|
|
19
|
+
open?: boolean
|
|
20
|
+
/** The active cell's format, what the dialog opens on. */
|
|
21
|
+
entry: CellFormatEntry | undefined
|
|
22
|
+
/** The active cell's value, for the Number tab's sample. */
|
|
23
|
+
sample: unknown
|
|
24
|
+
/** The selection holds locked and unlocked cells both: the Protection
|
|
25
|
+
* tab's box opens indeterminate and, left alone, changes nothing. */
|
|
26
|
+
mixedLocked?: boolean
|
|
27
|
+
onApply: (patch: CellFormatEntry, border: BorderPreset | null) => void
|
|
28
|
+
onClose?: () => void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let { open = $bindable(false), entry, sample, mixedLocked = false, onApply, onClose }: Props = $props()
|
|
32
|
+
|
|
33
|
+
type Tab = 'number' | 'alignment' | 'font' | 'border' | 'fill' | 'protection'
|
|
34
|
+
const TABS: ReadonlyArray<{ id: Tab; label: string }> = [
|
|
35
|
+
{ id: 'number', label: 'Number' },
|
|
36
|
+
{ id: 'alignment', label: 'Alignment' },
|
|
37
|
+
{ id: 'font', label: 'Font' },
|
|
38
|
+
{ id: 'border', label: 'Border' },
|
|
39
|
+
{ id: 'fill', label: 'Fill' },
|
|
40
|
+
{ id: 'protection', label: 'Protection' },
|
|
41
|
+
]
|
|
42
|
+
let tab = $state<Tab>('number')
|
|
43
|
+
|
|
44
|
+
type Category = 'general' | 'number' | 'currency' | 'percent' | 'date' | 'time' | 'scientific' | 'custom'
|
|
45
|
+
const CATEGORIES: ReadonlyArray<{ id: Category; label: string }> = [
|
|
46
|
+
{ id: 'general', label: 'General' },
|
|
47
|
+
{ id: 'number', label: 'Number' },
|
|
48
|
+
{ id: 'currency', label: 'Currency' },
|
|
49
|
+
{ id: 'percent', label: 'Percentage' },
|
|
50
|
+
{ id: 'date', label: 'Date' },
|
|
51
|
+
{ id: 'time', label: 'Time' },
|
|
52
|
+
{ id: 'scientific', label: 'Scientific' },
|
|
53
|
+
{ id: 'custom', label: 'Custom' },
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
// Number
|
|
57
|
+
let category = $state<Category>('general')
|
|
58
|
+
let decimals = $state(2)
|
|
59
|
+
let thousands = $state(true)
|
|
60
|
+
let custom = $state('')
|
|
61
|
+
// Alignment
|
|
62
|
+
let align = $state<'' | 'left' | 'center' | 'right'>('')
|
|
63
|
+
let wrap = $state(false)
|
|
64
|
+
let indent = $state(0)
|
|
65
|
+
// Font
|
|
66
|
+
let fontFamily = $state('')
|
|
67
|
+
let fontSize = $state('')
|
|
68
|
+
let bold = $state(false)
|
|
69
|
+
let italic = $state(false)
|
|
70
|
+
let underline = $state(false)
|
|
71
|
+
let strike = $state(false)
|
|
72
|
+
let colorAuto = $state(true)
|
|
73
|
+
let color = $state('#000000')
|
|
74
|
+
// Border
|
|
75
|
+
let border = $state<BorderPreset | ''>('')
|
|
76
|
+
// Fill
|
|
77
|
+
let fill = $state<string | null>(null)
|
|
78
|
+
// Protection: null is the indeterminate box of a mixed selection.
|
|
79
|
+
let locked = $state<boolean | null>(true)
|
|
80
|
+
|
|
81
|
+
let initial: CellFormatEntry = {}
|
|
82
|
+
/** What the colour input opened on, so an untouched picker keeps a colour
|
|
83
|
+
* the input cannot show (a CSS name, an rgb()) rather than replacing it. */
|
|
84
|
+
let initialColor = '#000000'
|
|
85
|
+
|
|
86
|
+
/** Which category a pattern belongs to, so the dialog opens on it. */
|
|
87
|
+
const categoryOf = (fmt: string | undefined): { category: Category; decimals: number; thousands: boolean } =>
|
|
88
|
+
formatCategory(fmt)
|
|
89
|
+
|
|
90
|
+
const zeros = (n: number) => (n > 0 ? '.' + '0'.repeat(n) : '')
|
|
91
|
+
|
|
92
|
+
/** The pattern the Number tab's choices spell. */
|
|
93
|
+
const pattern = $derived.by<string | undefined>(() => {
|
|
94
|
+
switch (category) {
|
|
95
|
+
case 'general': return undefined
|
|
96
|
+
case 'number': return `${thousands ? '#,##' : ''}0${zeros(decimals)}`
|
|
97
|
+
case 'currency': return `$#,##0${zeros(decimals)};($#,##0${zeros(decimals)})`
|
|
98
|
+
case 'percent': return `0${zeros(decimals)}%`
|
|
99
|
+
case 'date': return FORMAT_PRESETS.date
|
|
100
|
+
case 'time': return FORMAT_PRESETS.time
|
|
101
|
+
case 'scientific': return `0${zeros(decimals)}E+00`
|
|
102
|
+
case 'custom': return custom || undefined
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const preview = $derived.by(() => {
|
|
107
|
+
if (sample === '' || sample == null) return ''
|
|
108
|
+
if (!pattern) return String(sample)
|
|
109
|
+
try { return compileNumberFormat(pattern).format(sample).text } catch { return String(sample) }
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// Open on the active cell's format.
|
|
113
|
+
$effect(() => {
|
|
114
|
+
if (!open) return
|
|
115
|
+
initial = { ...(entry ?? {}) }
|
|
116
|
+
const num = categoryOf(initial.numFmt)
|
|
117
|
+
category = num.category
|
|
118
|
+
decimals = num.decimals
|
|
119
|
+
thousands = num.thousands
|
|
120
|
+
custom = initial.numFmt ?? ''
|
|
121
|
+
align = initial.align ?? ''
|
|
122
|
+
wrap = initial.wrap ?? false
|
|
123
|
+
indent = initial.indent ?? 0
|
|
124
|
+
fontFamily = initial.fontFamily ?? ''
|
|
125
|
+
fontSize = initial.fontSize ? String(initial.fontSize) : ''
|
|
126
|
+
bold = !!initial.bold
|
|
127
|
+
italic = !!initial.italic
|
|
128
|
+
underline = !!initial.underline
|
|
129
|
+
strike = !!initial.strike
|
|
130
|
+
colorAuto = !initial.color
|
|
131
|
+
color = /^#[0-9a-f]{6}$/i.test(initial.color ?? '') ? initial.color! : '#000000'
|
|
132
|
+
initialColor = color
|
|
133
|
+
border = ''
|
|
134
|
+
fill = initial.fill ?? null
|
|
135
|
+
locked = mixedLocked ? null : initial.locked !== false
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
function ok() {
|
|
139
|
+
// Only what changed goes into the patch; `undefined` clears a field.
|
|
140
|
+
const patch: CellFormatEntry = {}
|
|
141
|
+
const set = <K extends keyof CellFormatEntry>(key: K, next: CellFormatEntry[K]) => {
|
|
142
|
+
if (initial[key] !== next) patch[key] = next
|
|
143
|
+
}
|
|
144
|
+
set('numFmt', pattern)
|
|
145
|
+
set('align', align || undefined)
|
|
146
|
+
set('wrap', wrap || undefined)
|
|
147
|
+
set('indent', indent > 0 ? indent : undefined)
|
|
148
|
+
set('fontFamily', fontFamily || undefined)
|
|
149
|
+
set('fontSize', fontSize ? Number(fontSize) : undefined)
|
|
150
|
+
set('bold', bold || undefined)
|
|
151
|
+
set('italic', italic || undefined)
|
|
152
|
+
set('underline', underline || undefined)
|
|
153
|
+
set('strike', strike || undefined)
|
|
154
|
+
set('color', colorAuto ? undefined : color === initialColor ? initial.color : color)
|
|
155
|
+
set('fill', fill ?? undefined)
|
|
156
|
+
// Locked is the default, so only "unlocked" is ever stored; a mixed
|
|
157
|
+
// selection left indeterminate stays as it was.
|
|
158
|
+
if (locked !== null) {
|
|
159
|
+
const next = locked ? undefined : false
|
|
160
|
+
if (mixedLocked || initial.locked !== next) patch.locked = next
|
|
161
|
+
}
|
|
162
|
+
onApply(patch, border || null)
|
|
163
|
+
open = false
|
|
164
|
+
onClose?.()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function close() {
|
|
168
|
+
open = false
|
|
169
|
+
onClose?.()
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const BORDERS: ReadonlyArray<{ value: BorderPreset; label: string }> = [
|
|
173
|
+
{ value: 'none', label: 'None' },
|
|
174
|
+
{ value: 'outside', label: 'Outline' },
|
|
175
|
+
{ value: 'all', label: 'All borders' },
|
|
176
|
+
{ value: 'top', label: 'Top' },
|
|
177
|
+
{ value: 'bottom', label: 'Bottom' },
|
|
178
|
+
{ value: 'left', label: 'Left' },
|
|
179
|
+
{ value: 'right', label: 'Right' },
|
|
180
|
+
{ value: 'thick-bottom', label: 'Thick bottom' },
|
|
181
|
+
]
|
|
182
|
+
</script>
|
|
183
|
+
|
|
184
|
+
<SvModal bind:open onClose={onClose} title="Format Cells" size="md">
|
|
185
|
+
<div class="sv-sheet-dialog format" role="group" aria-label="Format Cells">
|
|
186
|
+
<div class="tabs" role="tablist" aria-label="Format Cells tabs">
|
|
187
|
+
{#each TABS as t (t.id)}
|
|
188
|
+
<button
|
|
189
|
+
type="button"
|
|
190
|
+
role="tab"
|
|
191
|
+
class="tab"
|
|
192
|
+
class:on={tab === t.id}
|
|
193
|
+
aria-selected={tab === t.id}
|
|
194
|
+
onclick={() => (tab = t.id)}
|
|
195
|
+
>{t.label}</button>
|
|
196
|
+
{/each}
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<div class="panel" role="tabpanel">
|
|
200
|
+
{#if tab === 'number'}
|
|
201
|
+
<div class="number">
|
|
202
|
+
<div class="categories">
|
|
203
|
+
<div class="label">Category:</div>
|
|
204
|
+
<ul role="listbox" aria-label="Category">
|
|
205
|
+
{#each CATEGORIES as c (c.id)}
|
|
206
|
+
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_noninteractive_element_interactions -->
|
|
207
|
+
<li role="option" aria-selected={category === c.id} class:selected={category === c.id} onclick={() => (category = c.id)}>{c.label}</li>
|
|
208
|
+
{/each}
|
|
209
|
+
</ul>
|
|
210
|
+
</div>
|
|
211
|
+
<div class="settings">
|
|
212
|
+
<div class="sample">
|
|
213
|
+
<div class="label">Sample</div>
|
|
214
|
+
<div class="sample-text">{preview}</div>
|
|
215
|
+
</div>
|
|
216
|
+
{#if category === 'number' || category === 'currency' || category === 'percent' || category === 'scientific'}
|
|
217
|
+
<label class="field auto">
|
|
218
|
+
<span>Decimal places:</span>
|
|
219
|
+
<input type="number" min="0" max="10" bind:value={decimals} />
|
|
220
|
+
</label>
|
|
221
|
+
{/if}
|
|
222
|
+
{#if category === 'number'}
|
|
223
|
+
<label class="check"><input type="checkbox" bind:checked={thousands} /> Use 1000 separator (,)</label>
|
|
224
|
+
{/if}
|
|
225
|
+
{#if category === 'custom'}
|
|
226
|
+
<label class="field auto">
|
|
227
|
+
<span>Type:</span>
|
|
228
|
+
<input type="text" bind:value={custom} spellcheck="false" placeholder="#,##0.00" />
|
|
229
|
+
</label>
|
|
230
|
+
{/if}
|
|
231
|
+
<p class="hint">
|
|
232
|
+
{#if category === 'general'}General format cells have no specific number format.
|
|
233
|
+
{:else if category === 'number'}Number is used for general display of numbers.
|
|
234
|
+
{:else if category === 'currency'}Currency formats are used for general monetary values.
|
|
235
|
+
{:else if category === 'percent'}Percentage formats multiply the cell value by 100 and display the result with a percent symbol.
|
|
236
|
+
{:else if category === 'date'}Date formats display date serial numbers as dates.
|
|
237
|
+
{:else if category === 'time'}Time formats display date serial numbers as times.
|
|
238
|
+
{:else if category === 'scientific'}Scientific formats display numbers in exponential notation.
|
|
239
|
+
{:else}Type the number format code, using one of the existing codes as a starting point.{/if}
|
|
240
|
+
</p>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
{:else if tab === 'alignment'}
|
|
244
|
+
<label class="field">
|
|
245
|
+
<span>Horizontal:</span>
|
|
246
|
+
<select bind:value={align}>
|
|
247
|
+
<option value="">General</option>
|
|
248
|
+
<option value="left">Left (Indent)</option>
|
|
249
|
+
<option value="center">Center</option>
|
|
250
|
+
<option value="right">Right (Indent)</option>
|
|
251
|
+
</select>
|
|
252
|
+
</label>
|
|
253
|
+
<label class="field">
|
|
254
|
+
<span>Indent:</span>
|
|
255
|
+
<input type="number" min="0" max="15" bind:value={indent} />
|
|
256
|
+
</label>
|
|
257
|
+
<div class="label">Text control</div>
|
|
258
|
+
<label class="check"><input type="checkbox" bind:checked={wrap} /> Wrap text</label>
|
|
259
|
+
{:else if tab === 'font'}
|
|
260
|
+
<label class="field">
|
|
261
|
+
<span>Font:</span>
|
|
262
|
+
<select bind:value={fontFamily}>
|
|
263
|
+
{#each FONT_FAMILIES as f (f.value)}
|
|
264
|
+
<option value={f.value}>{f.label}</option>
|
|
265
|
+
{/each}
|
|
266
|
+
</select>
|
|
267
|
+
</label>
|
|
268
|
+
<label class="field">
|
|
269
|
+
<span>Size:</span>
|
|
270
|
+
<select bind:value={fontSize}>
|
|
271
|
+
<option value="">Default</option>
|
|
272
|
+
{#each FONT_SIZES as s (s)}
|
|
273
|
+
<option value={String(s)}>{s}</option>
|
|
274
|
+
{/each}
|
|
275
|
+
</select>
|
|
276
|
+
</label>
|
|
277
|
+
<div class="label">Font style</div>
|
|
278
|
+
<div class="checks">
|
|
279
|
+
<label class="check"><input type="checkbox" bind:checked={bold} /> Bold</label>
|
|
280
|
+
<label class="check"><input type="checkbox" bind:checked={italic} /> Italic</label>
|
|
281
|
+
<label class="check"><input type="checkbox" bind:checked={underline} /> Underline</label>
|
|
282
|
+
<label class="check"><input type="checkbox" bind:checked={strike} /> Strikethrough</label>
|
|
283
|
+
</div>
|
|
284
|
+
<div class="label">Color</div>
|
|
285
|
+
<div class="checks">
|
|
286
|
+
<label class="check"><input type="checkbox" bind:checked={colorAuto} /> Automatic</label>
|
|
287
|
+
<input type="color" bind:value={color} disabled={colorAuto} aria-label="Font colour" />
|
|
288
|
+
</div>
|
|
289
|
+
<div class="font-preview" style:font-family={fontFamily || undefined} style:font-size={fontSize ? `${fontSize}px` : undefined} style:font-weight={bold ? 700 : 400} style:font-style={italic ? 'italic' : 'normal'} style:text-decoration={[underline ? 'underline' : '', strike ? 'line-through' : ''].join(' ').trim() || 'none'} style:color={colorAuto ? undefined : color}>AaBbCcYyZz</div>
|
|
290
|
+
{:else if tab === 'border'}
|
|
291
|
+
<div class="label">Presets</div>
|
|
292
|
+
<div class="borders" role="radiogroup" aria-label="Border">
|
|
293
|
+
<label class="check"><input type="radio" name="sheet-border" value="" bind:group={border} /> Keep as is</label>
|
|
294
|
+
{#each BORDERS as b (b.value)}
|
|
295
|
+
<label class="check"><input type="radio" name="sheet-border" value={b.value} bind:group={border} /> {b.label}</label>
|
|
296
|
+
{/each}
|
|
297
|
+
</div>
|
|
298
|
+
<p class="hint">Bottom, top, left and right go on the edge of the selection; All borders lines every cell; Outline frames the block.</p>
|
|
299
|
+
{:else if tab === 'fill'}
|
|
300
|
+
<div class="label">Background Color</div>
|
|
301
|
+
<div class="no-fill">
|
|
302
|
+
<button type="button" class="swatch none" class:on={fill === null} aria-label="No Color" title="No Color" onclick={() => (fill = null)}></button>
|
|
303
|
+
<span>No Color</span>
|
|
304
|
+
</div>
|
|
305
|
+
<div class="swatches" role="radiogroup" aria-label="Fill colour">
|
|
306
|
+
{#each ALL_COLOURS as c, i (i)}
|
|
307
|
+
<button type="button" class="swatch" class:on={fill === c.value} style:background={c.value} aria-label={c.label} title={c.label} onclick={() => (fill = c.value)}></button>
|
|
308
|
+
{/each}
|
|
309
|
+
</div>
|
|
310
|
+
<div class="sample">
|
|
311
|
+
<div class="label">Sample</div>
|
|
312
|
+
<div class="fill-sample" style:background={fill ?? 'transparent'}></div>
|
|
313
|
+
</div>
|
|
314
|
+
{:else if tab === 'protection'}
|
|
315
|
+
<label class="check">
|
|
316
|
+
<input
|
|
317
|
+
type="checkbox"
|
|
318
|
+
checked={locked === true}
|
|
319
|
+
indeterminate={locked === null}
|
|
320
|
+
onchange={(e) => (locked = (e.currentTarget as HTMLInputElement).checked)}
|
|
321
|
+
/>
|
|
322
|
+
Locked
|
|
323
|
+
</label>
|
|
324
|
+
<p class="hint">Locking cells has no effect until you protect the sheet (Review tab, Protect Sheet). Every cell is locked to begin with; unlock the ones that may change, then protect the sheet.</p>
|
|
325
|
+
{/if}
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
{#snippet footer()}
|
|
329
|
+
<div class="sv-sheet-dialog-buttons">
|
|
330
|
+
<button type="button" class="btn primary" onclick={ok}>OK</button>
|
|
331
|
+
<button type="button" class="btn" onclick={close}>Cancel</button>
|
|
332
|
+
</div>
|
|
333
|
+
{/snippet}
|
|
334
|
+
</SvModal>
|
|
335
|
+
|
|
336
|
+
<style>
|
|
337
|
+
.tabs {
|
|
338
|
+
display: flex;
|
|
339
|
+
gap: 2px;
|
|
340
|
+
border-bottom: 1px solid var(--sg-border, #d1d1d1);
|
|
341
|
+
}
|
|
342
|
+
.tab {
|
|
343
|
+
padding: 5px 12px;
|
|
344
|
+
font: inherit;
|
|
345
|
+
font-size: 13px;
|
|
346
|
+
color: var(--sg-muted, #616161);
|
|
347
|
+
background: transparent;
|
|
348
|
+
border: 1px solid transparent;
|
|
349
|
+
border-bottom: 0;
|
|
350
|
+
border-radius: var(--sg-radius, 3px) var(--sg-radius, 3px) 0 0;
|
|
351
|
+
cursor: pointer;
|
|
352
|
+
}
|
|
353
|
+
.tab:hover { color: var(--sg-fg, #242424); }
|
|
354
|
+
.tab.on {
|
|
355
|
+
color: var(--sg-fg, #242424);
|
|
356
|
+
background: var(--sg-bg, #fff);
|
|
357
|
+
border-color: var(--sg-border, #d1d1d1);
|
|
358
|
+
margin-bottom: -1px;
|
|
359
|
+
}
|
|
360
|
+
.panel {
|
|
361
|
+
display: flex;
|
|
362
|
+
flex-direction: column;
|
|
363
|
+
gap: 10px;
|
|
364
|
+
min-height: 220px;
|
|
365
|
+
padding-top: 4px;
|
|
366
|
+
}
|
|
367
|
+
.label { font-weight: 600; }
|
|
368
|
+
.number {
|
|
369
|
+
display: grid;
|
|
370
|
+
grid-template-columns: 140px 1fr;
|
|
371
|
+
gap: 14px;
|
|
372
|
+
}
|
|
373
|
+
.categories ul {
|
|
374
|
+
height: 200px;
|
|
375
|
+
margin: 4px 0 0;
|
|
376
|
+
padding: 2px 0;
|
|
377
|
+
overflow-y: auto;
|
|
378
|
+
list-style: none;
|
|
379
|
+
background: var(--sg-bg, #fff);
|
|
380
|
+
border: 1px solid var(--sg-border, #d1d1d1);
|
|
381
|
+
border-radius: var(--sg-radius, 3px);
|
|
382
|
+
}
|
|
383
|
+
.categories li { padding: 2px 8px; cursor: default; }
|
|
384
|
+
.categories li:hover { background: var(--sg-row-hover-bg, #f5f5f5); }
|
|
385
|
+
.categories li.selected { color: var(--sg-on-accent, #fff); background: var(--sg-accent, #217346); }
|
|
386
|
+
.settings { display: flex; flex-direction: column; gap: 10px; }
|
|
387
|
+
.sample { display: flex; flex-direction: column; gap: 4px; }
|
|
388
|
+
.sample-text,
|
|
389
|
+
.font-preview,
|
|
390
|
+
.fill-sample {
|
|
391
|
+
min-height: 28px;
|
|
392
|
+
padding: 4px 8px;
|
|
393
|
+
background: var(--sg-bg, #fff);
|
|
394
|
+
border: 1px solid var(--sg-border, #d1d1d1);
|
|
395
|
+
border-radius: var(--sg-radius, 3px);
|
|
396
|
+
}
|
|
397
|
+
.font-preview { min-height: 44px; display: flex; align-items: center; }
|
|
398
|
+
.fill-sample { min-height: 44px; }
|
|
399
|
+
.hint { margin: 0; color: var(--sg-muted, #616161); }
|
|
400
|
+
.borders { display: grid; grid-template-columns: repeat(3, auto); gap: 6px 16px; justify-content: start; }
|
|
401
|
+
.no-fill { display: flex; align-items: center; gap: 8px; }
|
|
402
|
+
.swatches {
|
|
403
|
+
display: grid;
|
|
404
|
+
grid-template-columns: repeat(10, 22px);
|
|
405
|
+
gap: 3px;
|
|
406
|
+
}
|
|
407
|
+
.swatch {
|
|
408
|
+
width: 22px;
|
|
409
|
+
height: 22px;
|
|
410
|
+
padding: 0;
|
|
411
|
+
border: 1px solid var(--sg-border, #d1d1d1);
|
|
412
|
+
border-radius: 2px;
|
|
413
|
+
cursor: pointer;
|
|
414
|
+
}
|
|
415
|
+
.swatch.none {
|
|
416
|
+
background:
|
|
417
|
+
linear-gradient(to top left, transparent calc(50% - 1px), var(--sg-danger, #c00) calc(50% - 1px), var(--sg-danger, #c00) calc(50% + 1px), transparent calc(50% + 1px)),
|
|
418
|
+
var(--sg-bg, #fff);
|
|
419
|
+
}
|
|
420
|
+
.swatch.on { outline: 2px solid var(--sg-accent, #217346); outline-offset: 1px; }
|
|
421
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CellFormatEntry } from './sheet/format-store.js';
|
|
2
|
+
import { type BorderPreset } from './sheet/ribbon.js';
|
|
3
|
+
type Props = {
|
|
4
|
+
open?: boolean;
|
|
5
|
+
/** The active cell's format, what the dialog opens on. */
|
|
6
|
+
entry: CellFormatEntry | undefined;
|
|
7
|
+
/** The active cell's value, for the Number tab's sample. */
|
|
8
|
+
sample: unknown;
|
|
9
|
+
/** The selection holds locked and unlocked cells both: the Protection
|
|
10
|
+
* tab's box opens indeterminate and, left alone, changes nothing. */
|
|
11
|
+
mixedLocked?: boolean;
|
|
12
|
+
onApply: (patch: CellFormatEntry, border: BorderPreset | null) => void;
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
};
|
|
15
|
+
declare const SvSheetFormatCells: import("svelte").Component<Props, {}, "open">;
|
|
16
|
+
type SvSheetFormatCells = ReturnType<typeof SvSheetFormatCells>;
|
|
17
|
+
export default SvSheetFormatCells;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Excel's Goal Seek: set a formula cell to a value by changing one input
|
|
4
|
+
* cell. The solver restores the input while it searches and the status
|
|
5
|
+
* page shows what it found; OK keeps the answer through the command
|
|
6
|
+
* context, so it lands in the grid's history like a typed number.
|
|
7
|
+
*/
|
|
8
|
+
import { untrack } from 'svelte'
|
|
9
|
+
import { SvModal } from '@svgrid/grid'
|
|
10
|
+
import type { GridCommandContext } from '@svgrid/grid/shortcuts'
|
|
11
|
+
import type { Workbook } from './sheet/workbook'
|
|
12
|
+
import { goalSeekCell, type GoalSeekResult } from './sheet/goal-seek'
|
|
13
|
+
import { parseA1, colToLetters } from './sheet/address'
|
|
14
|
+
|
|
15
|
+
type Props = {
|
|
16
|
+
open?: boolean
|
|
17
|
+
workbook: Workbook
|
|
18
|
+
/** The command context the dialog was opened with. */
|
|
19
|
+
cmd: () => GridCommandContext | null
|
|
20
|
+
onClose?: () => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let { open = $bindable(false), workbook, cmd, onClose }: Props = $props()
|
|
24
|
+
|
|
25
|
+
let step = $state<'ask' | 'done'>('ask')
|
|
26
|
+
let setCell = $state('')
|
|
27
|
+
let toValue = $state('')
|
|
28
|
+
let byCell = $state('')
|
|
29
|
+
let problem = $state<string | null>(null)
|
|
30
|
+
let found = $state<GoalSeekResult | null>(null)
|
|
31
|
+
let firstInput = $state<HTMLInputElement | null>(null)
|
|
32
|
+
|
|
33
|
+
// The active cell is the natural "Set cell", as it is in Excel.
|
|
34
|
+
$effect(() => {
|
|
35
|
+
if (!open) return
|
|
36
|
+
untrack(prepare)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
function prepare() {
|
|
40
|
+
const at = cmd()?.activeCell
|
|
41
|
+
setCell = at ? `${colToLetters(at.colIndex)}${at.rowIndex + 1}` : ''
|
|
42
|
+
toValue = ''
|
|
43
|
+
byCell = ''
|
|
44
|
+
step = 'ask'
|
|
45
|
+
problem = null
|
|
46
|
+
found = null
|
|
47
|
+
queueMicrotask(() => firstInput?.focus())
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function address(text: string): { row: number; col: number } | null {
|
|
51
|
+
const ref = parseA1(text.trim().toUpperCase())
|
|
52
|
+
return ref && ref.row !== null ? { row: ref.row, col: ref.col } : null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function solve() {
|
|
56
|
+
const formula = address(setCell)
|
|
57
|
+
const input = address(byCell)
|
|
58
|
+
const target = Number(toValue)
|
|
59
|
+
if (!formula) { problem = `"${setCell}" is not a cell address`; return }
|
|
60
|
+
if (!input) { problem = `"${byCell}" is not a cell address`; return }
|
|
61
|
+
if (toValue.trim() === '' || !Number.isFinite(target)) { problem = 'To value must be a number'; return }
|
|
62
|
+
const sheet = workbook.active
|
|
63
|
+
if (!workbook.getRaw(sheet, formula.row, formula.col).startsWith('=')) {
|
|
64
|
+
problem = `${setCell.toUpperCase()} must contain a formula`
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
if (workbook.getRaw(sheet, input.row, input.col).startsWith('=')) {
|
|
68
|
+
problem = `${byCell.toUpperCase()} must contain a value, not a formula`
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
found = goalSeekCell(workbook, { sheet, ...formula }, { sheet, ...input }, target, { maxIterations: 100 })
|
|
72
|
+
problem = null
|
|
73
|
+
step = 'done'
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function keep() {
|
|
77
|
+
const input = address(byCell)
|
|
78
|
+
const c = cmd()
|
|
79
|
+
if (!input || !found || !c) return
|
|
80
|
+
c.setCellValue(input.row, input.col, String(round(found.value)))
|
|
81
|
+
c.setActiveCell(input.row, input.col)
|
|
82
|
+
close()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function close() {
|
|
86
|
+
open = false
|
|
87
|
+
onClose?.()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const round = (n: number) => Number(n.toFixed(4))
|
|
91
|
+
const money = (n: number) => n.toLocaleString('en-US', { maximumFractionDigits: 2 })
|
|
92
|
+
</script>
|
|
93
|
+
|
|
94
|
+
<SvModal bind:open onClose={onClose} title={step === 'ask' ? 'Goal Seek' : 'Goal Seek Status'} size="sm">
|
|
95
|
+
{#if step === 'ask'}
|
|
96
|
+
<form class="sv-sheet-dialog" onsubmit={(e) => { e.preventDefault(); solve() }}>
|
|
97
|
+
<label class="field">
|
|
98
|
+
<span>Set cell:</span>
|
|
99
|
+
<input bind:this={firstInput} type="text" bind:value={setCell} spellcheck="false" />
|
|
100
|
+
</label>
|
|
101
|
+
<label class="field">
|
|
102
|
+
<span>To value:</span>
|
|
103
|
+
<input type="text" bind:value={toValue} inputmode="decimal" />
|
|
104
|
+
</label>
|
|
105
|
+
<label class="field">
|
|
106
|
+
<span>By changing cell:</span>
|
|
107
|
+
<input type="text" bind:value={byCell} spellcheck="false" />
|
|
108
|
+
</label>
|
|
109
|
+
{#if problem}<p class="status problem" role="alert">{problem}</p>{/if}
|
|
110
|
+
</form>
|
|
111
|
+
{:else if found}
|
|
112
|
+
<div class="sv-sheet-dialog">
|
|
113
|
+
<p class="lead">
|
|
114
|
+
Goal Seeking with Cell <strong>{setCell.toUpperCase()}</strong>
|
|
115
|
+
{found.converged ? 'found a solution.' : 'may not have found a solution.'}
|
|
116
|
+
</p>
|
|
117
|
+
<dl class="facts">
|
|
118
|
+
<dt>Target value:</dt><dd>{money(Number(toValue))}</dd>
|
|
119
|
+
<dt>Current value:</dt><dd>{money(found.result)}</dd>
|
|
120
|
+
<dt>{byCell.toUpperCase()} becomes:</dt><dd>{money(round(found.value))}</dd>
|
|
121
|
+
</dl>
|
|
122
|
+
<p class="status">{found.iterations} iterations.</p>
|
|
123
|
+
</div>
|
|
124
|
+
{/if}
|
|
125
|
+
{#snippet footer()}
|
|
126
|
+
<div class="sv-sheet-dialog-buttons">
|
|
127
|
+
<button type="button" class="btn primary" onclick={step === 'ask' ? solve : keep}>OK</button>
|
|
128
|
+
<button type="button" class="btn" onclick={close}>Cancel</button>
|
|
129
|
+
</div>
|
|
130
|
+
{/snippet}
|
|
131
|
+
</SvModal>
|
|
132
|
+
|
|
133
|
+
<style>
|
|
134
|
+
.lead { margin: 0; }
|
|
135
|
+
.facts {
|
|
136
|
+
display: grid;
|
|
137
|
+
grid-template-columns: auto 1fr;
|
|
138
|
+
gap: 4px 12px;
|
|
139
|
+
margin: 0;
|
|
140
|
+
}
|
|
141
|
+
.facts dt { color: var(--sg-muted, #616161); }
|
|
142
|
+
.facts dd { margin: 0; font-variant-numeric: tabular-nums; }
|
|
143
|
+
.problem { color: var(--sg-danger, #dc2626); }
|
|
144
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { GridCommandContext } from '@svgrid/grid/shortcuts';
|
|
2
|
+
import type { Workbook } from './sheet/workbook.js';
|
|
3
|
+
type Props = {
|
|
4
|
+
open?: boolean;
|
|
5
|
+
workbook: Workbook;
|
|
6
|
+
/** The command context the dialog was opened with. */
|
|
7
|
+
cmd: () => GridCommandContext | null;
|
|
8
|
+
onClose?: () => void;
|
|
9
|
+
};
|
|
10
|
+
declare const SvSheetGoalSeek: import("svelte").Component<Props, {}, "open">;
|
|
11
|
+
type SvSheetGoalSeek = ReturnType<typeof SvSheetGoalSeek>;
|
|
12
|
+
export default SvSheetGoalSeek;
|