@svgrid/enterprise 3.0.2 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +94 -24
- package/README.md +36 -4
- package/dist/SvAdvancedFilter.svelte +1 -1
- package/dist/SvAlertsManager.svelte +2 -1
- package/dist/SvBoard.svelte +2 -1
- package/dist/SvExportMenu.svelte +4 -1
- package/dist/SvExportMenu.svelte.d.ts +0 -13
- package/dist/SvExpressionEditor.svelte +3 -3
- package/dist/SvFormulaBar.svelte +94 -20
- package/dist/SvFormulaBar.svelte.d.ts +7 -0
- package/dist/SvGridAlerts.svelte +49 -9
- package/dist/SvGridBoard.svelte +13 -8
- package/dist/SvGridBulkEditDrawer.svelte +26 -2
- package/dist/SvGridEditPanel.svelte +3 -0
- package/dist/SvGridScheduler.svelte +69 -40
- package/dist/SvGridSelectionBar.svelte +10 -3
- package/dist/SvPivotDesigner.svelte +198 -40
- package/dist/SvPivotDesigner.svelte.d.ts +27 -20
- package/dist/SvSheet.svelte +4043 -243
- package/dist/SvSheet.svelte.d.ts +76 -3
- package/dist/SvSheetChartSetup.svelte +151 -0
- package/dist/SvSheetChartSetup.svelte.d.ts +18 -0
- package/dist/SvSheetComment.svelte +216 -31
- package/dist/SvSheetComment.svelte.d.ts +11 -11
- package/dist/SvSheetConditionalFormat.svelte +28 -31
- package/dist/SvSheetDataValidation.svelte +66 -42
- package/dist/SvSheetEditRanges.svelte +217 -0
- package/dist/SvSheetEditRanges.svelte.d.ts +15 -0
- package/dist/SvSheetErrors.svelte +125 -0
- package/dist/SvSheetErrors.svelte.d.ts +20 -0
- package/dist/SvSheetEvaluate.svelte +133 -0
- package/dist/SvSheetEvaluate.svelte.d.ts +15 -0
- package/dist/SvSheetFilterMenu.svelte +137 -34
- package/dist/SvSheetFilterMenu.svelte.d.ts +5 -0
- package/dist/SvSheetFindReplace.svelte +19 -19
- package/dist/SvSheetFormatCells.svelte +125 -81
- package/dist/SvSheetGoalSeek.svelte +17 -16
- package/dist/SvSheetInsertFunction.svelte +15 -13
- package/dist/SvSheetIteration.svelte +81 -0
- package/dist/SvSheetIteration.svelte.d.ts +10 -0
- package/dist/SvSheetLink.svelte +99 -0
- package/dist/SvSheetLink.svelte.d.ts +17 -0
- package/dist/SvSheetListPicker.svelte +4 -2
- package/dist/SvSheetListPicker.svelte.d.ts +0 -6
- package/dist/SvSheetManageRules.svelte +20 -18
- package/dist/SvSheetNameManager.svelte +17 -15
- package/dist/SvSheetPageSetup.svelte +159 -0
- package/dist/SvSheetPageSetup.svelte.d.ts +13 -0
- package/dist/SvSheetPasteSpecial.svelte +22 -20
- package/dist/SvSheetPivot.svelte +220 -0
- package/dist/SvSheetPivot.svelte.d.ts +21 -0
- package/dist/SvSheetProtectSheet.svelte +81 -0
- package/dist/SvSheetProtectSheet.svelte.d.ts +11 -0
- package/dist/SvSheetRemoveDuplicates.svelte +13 -10
- package/dist/SvSheetRibbon.svelte +104 -51
- package/dist/SvSheetSizeDialog.svelte +4 -2
- package/dist/SvSheetSort.svelte +218 -0
- package/dist/SvSheetSort.svelte.d.ts +28 -0
- package/dist/SvSheetSparklines.svelte +135 -0
- package/dist/SvSheetSparklines.svelte.d.ts +14 -0
- package/dist/SvSheetTable.svelte +160 -0
- package/dist/SvSheetTable.svelte.d.ts +24 -0
- package/dist/SvSheetTabs.svelte +161 -31
- package/dist/SvSheetTabs.svelte.d.ts +22 -8
- package/dist/SvSheetTextToColumns.svelte +20 -20
- package/dist/SvSheetValidationAlert.svelte +8 -6
- package/dist/advanced-filter-enable.js +1 -1
- package/dist/alerts/alert-engine.d.ts +6 -0
- package/dist/alerts/alert-engine.js +21 -4
- package/dist/alerts/alert-formats.js +2 -0
- package/dist/alerts/alert-types.d.ts +1 -1
- package/dist/alerts.d.ts +1 -1
- package/dist/alerts.js +2 -2
- package/dist/board.js +2 -2
- package/dist/bulk-edit.d.ts +3 -1
- package/dist/bulk-edit.js +1 -1
- package/dist/cdn/svgrid-enterprise.svelte-external.js +39827 -16429
- package/dist/designer/assets/GridMenus-8gTNssgV.js +8 -0
- package/dist/designer/assets/{SvChartMenu-D9hEeHar.js → SvChartMenu-BDoeqGz6.js} +1 -1
- package/dist/designer/assets/{SvDateTimePicker-DARvKUL2.js → SvDateTimePicker-DCPg7WGN.js} +1 -1
- package/dist/designer/assets/SvGridCellEditor-DMoWJjEI.js +4 -0
- package/dist/designer/assets/{SvGridChart-B8j1SSy3.js → SvGridChart-Cy1ATrWh.js} +2 -2
- package/dist/designer/assets/SvGridChartBuilder-eQ3mn0L9.js +1 -0
- package/dist/designer/assets/{SvGridChartPanel-pT6ITc2P.js → SvGridChartPanel-CATdVc9X.js} +3 -3
- package/dist/designer/assets/{SvGridChartView-bg281UA1.js → SvGridChartView-CmsZtCED.js} +1 -1
- package/dist/designer/assets/SvGridDropdown-Cjz0H-fI.js +1 -0
- package/dist/designer/assets/{SvTabs-UFCMTHXS.js → SvTabs-2mHC6oaz.js} +1 -1
- package/dist/designer/assets/cell-formatting-BbubJTVz.js +1 -0
- package/dist/designer/assets/{chart-cIPUsbM5.js → chart-Cn7MnNqA.js} +1 -1
- package/dist/designer/assets/{chart-panel-messages-DtTxpBUU.js → chart-panel-messages-Dz7PTIqT.js} +1 -1
- package/dist/designer/assets/{chart-summary-Czu_5epb.js → chart-summary-BD1qYB2R.js} +1 -1
- package/dist/designer/assets/{chart-trend-D5I5VEe8.js → chart-trend-B8xr5LuD.js} +1 -1
- package/dist/designer/assets/{dismissable-BO547MH9.js → dismissable-ChWRPkoa.js} +1 -1
- package/dist/designer/assets/{export-format-D-eP4b2l.js → export-format-DGckmgKr.js} +1 -1
- package/dist/designer/assets/{focus-trap-CAreAhlU.js → focus-trap-V2-6Fy9I.js} +1 -1
- package/dist/designer/assets/{index-DwU7CAMm.js → index-BSjv6Qec.js} +317 -315
- package/dist/designer/assets/index-_JVFxt02.css +1 -0
- package/dist/designer/assets/row-resize-BInFWCpr.js +1 -0
- package/dist/designer/assets/server-block-cache-CXJKkJpy.js +1 -0
- package/dist/designer/assets/src-DUQ4xE3x.js +58 -0
- package/dist/designer/assets/validate-C3B8QKsM.js +1 -0
- package/dist/designer/index.html +17 -16
- package/dist/export-pdf.d.ts +75 -0
- package/dist/export-pdf.js +216 -15
- package/dist/export.js +10 -2
- package/dist/gantt/SvGridGantt.svelte +2890 -0
- package/dist/gantt/SvGridGantt.svelte.d.ts +30 -0
- package/dist/gantt/gantt-config.d.ts +73 -0
- package/dist/gantt/gantt-config.js +1 -0
- package/dist/gantt/gantt-critical-path.d.ts +67 -0
- package/dist/gantt/gantt-critical-path.js +207 -0
- package/dist/gantt/gantt-model.d.ts +257 -0
- package/dist/gantt/gantt-model.js +651 -0
- package/dist/gantt/gantt-resources.d.ts +59 -0
- package/dist/gantt/gantt-resources.js +71 -0
- package/dist/gantt/gantt.d.ts +7 -0
- package/dist/gantt/gantt.js +36 -0
- package/dist/gantt/index.d.ts +15 -0
- package/dist/gantt/index.js +22 -0
- package/dist/gantt/timeline-arrows.d.ts +102 -0
- package/dist/gantt/timeline-arrows.js +181 -0
- package/dist/import.d.ts +2 -2
- package/dist/import.js +1 -1
- package/dist/index.d.ts +34 -7
- package/dist/index.js +44 -7
- package/dist/install.js +8 -1
- package/dist/license-core.d.ts +17 -1
- package/dist/license-core.js +16 -5
- package/dist/license.d.ts +18 -2
- package/dist/license.js +71 -6
- package/dist/node/studio.js +140 -8
- package/dist/pivot-enable.js +2 -2
- package/dist/scheduler-dependencies.d.ts +35 -0
- package/dist/scheduler-dependencies.js +36 -1
- package/dist/scheduler.js +2 -2
- package/dist/selection-bar.js +2 -2
- package/dist/server/SvGroupCell.svelte +213 -0
- package/dist/server/SvGroupCell.svelte.d.ts +62 -0
- package/dist/server/SvRowGroupPanel.svelte +322 -0
- package/dist/server/SvRowGroupPanel.svelte.d.ts +37 -0
- package/dist/server/enable.d.ts +17 -0
- package/dist/server/enable.js +49 -0
- package/dist/server/index.d.ts +22 -0
- package/dist/server/index.js +24 -0
- package/dist/server/messages.d.ts +45 -0
- package/dist/server/messages.js +35 -0
- package/dist/server/server-group-model.d.ts +104 -0
- package/dist/server/server-group-model.js +272 -0
- package/dist/server/server-pivot.d.ts +46 -0
- package/dist/server/server-pivot.js +57 -0
- package/dist/server/server-row-model.d.ts +547 -0
- package/dist/server/server-row-model.js +1551 -0
- package/dist/server/server-selection.d.ts +99 -0
- package/dist/server/server-selection.js +215 -0
- package/dist/server/svgrid-adapter.d.ts +155 -0
- package/dist/server/svgrid-adapter.js +202 -0
- package/dist/sheet/ast.d.ts +45 -1
- package/dist/sheet/ast.js +14 -0
- package/dist/sheet/auto-filter.d.ts +58 -4
- package/dist/sheet/auto-filter.js +159 -11
- package/dist/sheet/autocomplete.d.ts +9 -0
- package/dist/sheet/autocomplete.js +90 -4
- package/dist/sheet/cell-images.d.ts +39 -0
- package/dist/sheet/cell-images.js +90 -0
- package/dist/sheet/cell-types.d.ts +58 -0
- package/dist/sheet/cell-types.js +96 -0
- package/dist/sheet/coerce.d.ts +40 -0
- package/dist/sheet/coerce.js +170 -3
- package/dist/sheet/comments.d.ts +43 -9
- package/dist/sheet/comments.js +85 -27
- package/dist/sheet/conditional-formats.d.ts +29 -6
- package/dist/sheet/conditional-formats.js +37 -12
- package/dist/sheet/csv.d.ts +32 -0
- package/dist/sheet/csv.js +158 -0
- package/dist/sheet/culture.d.ts +87 -0
- package/dist/sheet/culture.js +247 -0
- package/dist/sheet/delta.d.ts +102 -0
- package/dist/sheet/delta.js +203 -0
- package/dist/sheet/deps.d.ts +45 -1
- package/dist/sheet/deps.js +77 -2
- package/dist/sheet/document.d.ts +106 -4
- package/dist/sheet/document.js +204 -3
- package/dist/sheet/engine.d.ts +67 -0
- package/dist/sheet/engine.js +19 -0
- package/dist/sheet/entry.d.ts +8 -4
- package/dist/sheet/entry.js +171 -21
- package/dist/sheet/error-check.d.ts +49 -0
- package/dist/sheet/error-check.js +83 -0
- package/dist/sheet/evaluate-steps.d.ts +48 -0
- package/dist/sheet/evaluate-steps.js +196 -0
- package/dist/sheet/evaluate.d.ts +67 -0
- package/dist/sheet/evaluate.js +725 -13
- package/dist/sheet/filter-files.d.ts +37 -0
- package/dist/sheet/filter-files.js +465 -0
- package/dist/sheet/format-store.d.ts +15 -0
- package/dist/sheet/format-store.js +11 -1
- package/dist/sheet/from-rows.d.ts +14 -0
- package/dist/sheet/from-rows.js +50 -0
- package/dist/sheet/function-catalog.d.ts +1 -1
- package/dist/sheet/function-catalog.js +296 -5
- package/dist/sheet/functions.js +363 -91
- package/dist/sheet/index.d.ts +35 -8
- package/dist/sheet/index.js +35 -8
- package/dist/sheet/links.d.ts +57 -0
- package/dist/sheet/links.js +174 -0
- package/dist/sheet/messages.d.ts +778 -0
- package/dist/sheet/messages.js +806 -0
- package/dist/sheet/number-format.d.ts +52 -5
- package/dist/sheet/number-format.js +465 -68
- package/dist/sheet/objects.d.ts +106 -0
- package/dist/sheet/objects.js +149 -0
- package/dist/sheet/ods-document.d.ts +44 -0
- package/dist/sheet/ods-document.js +1275 -0
- package/dist/sheet/open-file.d.ts +26 -0
- package/dist/sheet/open-file.js +56 -0
- package/dist/sheet/outline.d.ts +82 -0
- package/dist/sheet/outline.js +228 -0
- package/dist/sheet/packs/array.d.ts +16 -0
- package/dist/sheet/packs/array.js +172 -0
- package/dist/sheet/packs/database.d.ts +42 -0
- package/dist/sheet/packs/database.js +142 -0
- package/dist/sheet/packs/engineering.d.ts +2 -0
- package/dist/sheet/packs/engineering.js +296 -0
- package/dist/sheet/packs/financial.d.ts +5 -0
- package/dist/sheet/packs/financial.js +220 -0
- package/dist/sheet/packs/math-stats.d.ts +2 -0
- package/dist/sheet/packs/math-stats.js +372 -0
- package/dist/sheet/packs/special.d.ts +44 -0
- package/dist/sheet/packs/special.js +187 -0
- package/dist/sheet/packs/stats-dist.d.ts +2 -0
- package/dist/sheet/packs/stats-dist.js +785 -0
- package/dist/sheet/packs/text-date.d.ts +2 -0
- package/dist/sheet/packs/text-date.js +332 -0
- package/dist/sheet/packs/trig.d.ts +2 -0
- package/dist/sheet/packs/trig.js +73 -0
- package/dist/sheet/page-setup.d.ts +73 -0
- package/dist/sheet/page-setup.js +73 -0
- package/dist/sheet/parse.js +42 -10
- package/dist/sheet/paste-special.d.ts +22 -0
- package/dist/sheet/paste-special.js +14 -5
- package/dist/sheet/pivot-range.d.ts +160 -0
- package/dist/sheet/pivot-range.js +333 -0
- package/dist/sheet/presence.d.ts +73 -0
- package/dist/sheet/presence.js +79 -0
- package/dist/sheet/print.d.ts +104 -0
- package/dist/sheet/print.js +169 -0
- package/dist/sheet/protection.d.ts +55 -1
- package/dist/sheet/protection.js +55 -2
- package/dist/sheet/rects.d.ts +1 -1
- package/dist/sheet/refs.d.ts +48 -0
- package/dist/sheet/refs.js +155 -8
- package/dist/sheet/ribbon-icons.d.ts +1 -1
- package/dist/sheet/ribbon-icons.js +186 -0
- package/dist/sheet/ribbon.d.ts +1 -1
- package/dist/sheet/ribbon.js +324 -23
- package/dist/sheet/sheet-kinds.d.ts +74 -0
- package/dist/sheet/sheet-kinds.js +91 -0
- package/dist/sheet/shortcuts.d.ts +13 -3
- package/dist/sheet/shortcuts.js +63 -12
- package/dist/sheet/sort.d.ts +51 -0
- package/dist/sheet/sort.js +107 -0
- package/dist/sheet/sparklines.d.ts +111 -0
- package/dist/sheet/sparklines.js +204 -0
- package/dist/sheet/table-styles.d.ts +74 -0
- package/dist/sheet/table-styles.js +152 -0
- package/dist/sheet/tables.d.ts +19 -0
- package/dist/sheet/tables.js +31 -0
- package/dist/sheet/tokenize.d.ts +18 -1
- package/dist/sheet/tokenize.js +60 -9
- package/dist/sheet/validation.d.ts +16 -0
- package/dist/sheet/validation.js +37 -0
- package/dist/sheet/workbook.d.ts +148 -3
- package/dist/sheet/workbook.js +742 -31
- package/dist/sheet/xls-cfb.d.ts +32 -0
- package/dist/sheet/xls-cfb.js +290 -0
- package/dist/sheet/xls-document.d.ts +10 -0
- package/dist/sheet/xls-document.js +1243 -0
- package/dist/sheet/xls-formula.d.ts +40 -0
- package/dist/sheet/xls-formula.js +569 -0
- package/dist/sheet/xlsx-document.d.ts +108 -0
- package/dist/sheet/xlsx-document.js +1849 -0
- package/dist/sheet/xlsx-drawing.d.ts +99 -0
- package/dist/sheet/xlsx-drawing.js +420 -0
- package/dist/sheet-enable.js +6 -7
- package/dist/sheet-text.d.ts +7 -0
- package/dist/sheet-text.js +29 -0
- package/dist/sources/auth-supabase.js +2 -2
- package/dist/sources/realtime-supabase.js +2 -2
- package/dist/sources/rest.d.ts +6 -2
- package/dist/sources/rest.js +42 -7
- package/dist/sources/supabase.d.ts +10 -1
- package/dist/sources/supabase.js +73 -40
- package/dist/studio/emit-project.js +14 -1
- package/dist/studio/index.js +1 -1
- package/dist/studio/project.d.ts +11 -2
- package/dist/studio/project.js +5 -2
- package/dist/studio/ui-components.generated.js +107 -2
- package/dist/sveltekit/in-memory.d.ts +2 -2
- package/dist/sveltekit/in-memory.js +125 -4
- package/dist/sveltekit/index.d.ts +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/dist/sveltekit/query-plan.d.ts +50 -4
- package/dist/sveltekit/query-plan.js +25 -3
- package/dist/sveltekit/sql-source.d.ts +6 -0
- package/dist/sveltekit/sql-source.js +34 -6
- package/dist/sveltekit/sql.d.ts +31 -0
- package/dist/sveltekit/sql.js +135 -25
- package/dist/sveltekit/transport.d.ts +10 -2
- package/dist/sveltekit/transport.js +30 -6
- package/dist/upgrade-prompt.d.ts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/watermark.js +35 -2
- package/dist/wc/GridMenus-By9vPuq0.js +1088 -0
- package/dist/wc/SvChartMenu-CQNrQGT2.js +308 -0
- package/dist/wc/SvDateRangeInput-DR6m7bSM.js +199 -0
- package/dist/wc/SvDateTimePicker-D-vRnaMo.js +771 -0
- package/dist/wc/SvField-B_kurx_P.js +149 -0
- package/dist/wc/SvGrid.helpers-BdVDtjUm.js +135 -0
- package/dist/wc/SvGridCellEditor-Bnf1Kr5C.js +560 -0
- package/dist/wc/SvGridChart-BqUJh2pG.js +3572 -0
- package/dist/wc/SvGridChartBuilder-CGycC5cn.js +988 -0
- package/dist/wc/SvGridChartPanel-CRnizsHD.js +1746 -0
- package/dist/wc/SvGridChartView-D1pa_xMy.js +47 -0
- package/dist/wc/SvGridDropdown-45WsObLL.js +259 -0
- package/dist/wc/SvModal-DrfOYYyX.js +189 -0
- package/dist/wc/cell-formatting-CBfgahv1.js +86 -0
- package/dist/wc/chart-6OXlybVT.js +4341 -0
- package/dist/wc/chart-export-CeSADGfi.js +135 -0
- package/dist/wc/chart-export-pdf-BGko7MER.js +104 -0
- package/dist/wc/chart-summary-2m3ia1-n.js +137 -0
- package/dist/wc/chart-trend-CQOQtTMl.js +50 -0
- package/dist/wc/chart-validate-CD6ptiwg.js +180 -0
- package/dist/wc/client-DQIzjDBG.js +3064 -0
- package/dist/wc/column-resize-DUPgynvc.js +101 -0
- package/dist/wc/date-format-DS-z_h9v.js +1130 -0
- package/dist/wc/dismissable-CQ6XFXsk.js +45 -0
- package/dist/wc/editor-contract-peBDxir_.js +22 -0
- package/dist/wc/editor-registry-DxGKqcvx.js +24 -0
- package/dist/wc/focus-trap-Dbb2tJxb.js +65 -0
- package/dist/wc/list-option-DrRyivWp.js +82 -0
- package/dist/wc/popover-WsGlvtQv.js +69 -0
- package/dist/wc/positioning-BiKLfu1E.js +112 -0
- package/dist/wc/react.d.ts +41 -0
- package/dist/wc/react.js +90 -0
- package/dist/wc/rolldown-runtime-Dy4uBu1J.js +11 -0
- package/dist/wc/row-drag-touch-CycRR65n.js +93 -0
- package/dist/wc/row-resize-limG_N1z.js +111 -0
- package/dist/wc/sv-sheet-element.d.ts +97 -0
- package/dist/wc/sv-sheet-element.js +44213 -0
- package/dist/wc/svelte-virtualizer.svelte-CXtQy2TQ.js +530 -0
- package/dist/wc/validate-BqDthkNr.js +88 -0
- package/dist/wc/vue.d.ts +31 -0
- package/dist/wc/vue.js +75 -0
- package/package.json +30 -5
- package/dist/designer/assets/GridMenus-BlsvL_aU.js +0 -8
- package/dist/designer/assets/SvGridCellEditor-C7uQXYds.js +0 -4
- package/dist/designer/assets/SvGridChartBuilder-kvyIU_Rl.js +0 -1
- package/dist/designer/assets/SvGridDropdown-Bb3HH2Aj.js +0 -1
- package/dist/designer/assets/cell-formatting-wr5wm7US.js +0 -1
- package/dist/designer/assets/index-CMFgAoVV.css +0 -1
- package/dist/designer/assets/row-resize-DLktcqUK.js +0 -1
- package/dist/designer/assets/src-EdI3Xqds.js +0 -58
- package/dist/designer/assets/validate-h-aslRV9.js +0 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Excel's File > Options > Formulas > Calculation options, raised to the
|
|
4
|
+
* Formulas tab because it is the one setting there that changes what a
|
|
5
|
+
* formula is worth: with iteration on a circular reference settles on its
|
|
6
|
+
* fixed point instead of showing #CYCLE!.
|
|
7
|
+
*/
|
|
8
|
+
import { SvModal } from '@svgrid/grid'
|
|
9
|
+
import { useSheetText } from './sheet-text'
|
|
10
|
+
import type { IterationSettings } from './sheet/workbook'
|
|
11
|
+
|
|
12
|
+
type Props = {
|
|
13
|
+
open?: boolean
|
|
14
|
+
iteration: IterationSettings
|
|
15
|
+
onApply: (next: IterationSettings) => void
|
|
16
|
+
onClose?: () => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let { open = $bindable(false), iteration, onApply, onClose }: Props = $props()
|
|
20
|
+
const t = useSheetText()
|
|
21
|
+
|
|
22
|
+
let enabled = $state(false)
|
|
23
|
+
let passes = $state('100')
|
|
24
|
+
let change = $state('0.001')
|
|
25
|
+
let error = $state('')
|
|
26
|
+
let first = $state<HTMLInputElement | null>(null)
|
|
27
|
+
|
|
28
|
+
$effect(() => {
|
|
29
|
+
if (!open) return
|
|
30
|
+
enabled = iteration.enabled
|
|
31
|
+
passes = String(iteration.maxIterations)
|
|
32
|
+
change = String(iteration.maxChange)
|
|
33
|
+
error = ''
|
|
34
|
+
queueMicrotask(() => first?.focus())
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
function ok() {
|
|
38
|
+
const maxIterations = Number(passes)
|
|
39
|
+
const maxChange = Number(change)
|
|
40
|
+
if (!Number.isFinite(maxIterations) || maxIterations < 1 || !Number.isFinite(maxChange) || maxChange < 0) {
|
|
41
|
+
error = t('iteration.badNumbers')
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
open = false
|
|
45
|
+
onApply({ enabled, maxIterations: Math.round(maxIterations), maxChange })
|
|
46
|
+
onClose?.()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function close() {
|
|
50
|
+
open = false
|
|
51
|
+
onClose?.()
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<SvModal bind:open onClose={onClose} title={t('iteration.title')} size="sm">
|
|
56
|
+
<form class="sv-sheet-dialog" onsubmit={(e) => { e.preventDefault(); ok() }}>
|
|
57
|
+
<label class="check"><input type="checkbox" bind:this={first} bind:checked={enabled} /> {t('iteration.enable')}</label>
|
|
58
|
+
<label class="field">
|
|
59
|
+
<span>{t('iteration.maxIterations')}</span>
|
|
60
|
+
<input type="number" min="1" step="1" bind:value={passes} disabled={!enabled} />
|
|
61
|
+
</label>
|
|
62
|
+
<label class="field">
|
|
63
|
+
<span>{t('iteration.maxChange')}</span>
|
|
64
|
+
<input type="number" min="0" step="0.0001" bind:value={change} disabled={!enabled} />
|
|
65
|
+
</label>
|
|
66
|
+
{#if error}<p class="error">{error}</p>{/if}
|
|
67
|
+
<p class="hint">{t('iteration.hint')}</p>
|
|
68
|
+
</form>
|
|
69
|
+
{#snippet footer()}
|
|
70
|
+
<div class="sv-sheet-dialog-buttons">
|
|
71
|
+
<span class="spacer"></span>
|
|
72
|
+
<button type="button" class="btn primary" onclick={ok}>{t('ok')}</button>
|
|
73
|
+
<button type="button" class="btn" onclick={close}>{t('cancel')}</button>
|
|
74
|
+
</div>
|
|
75
|
+
{/snippet}
|
|
76
|
+
</SvModal>
|
|
77
|
+
|
|
78
|
+
<style>
|
|
79
|
+
.spacer { flex: 1; }
|
|
80
|
+
.error { margin: 4px 0 0; color: var(--sg-danger, #c42b1c); font-size: 12px; }
|
|
81
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IterationSettings } from './sheet/workbook.js';
|
|
2
|
+
type Props = {
|
|
3
|
+
open?: boolean;
|
|
4
|
+
iteration: IterationSettings;
|
|
5
|
+
onApply: (next: IterationSettings) => void;
|
|
6
|
+
onClose?: () => void;
|
|
7
|
+
};
|
|
8
|
+
declare const SvSheetIteration: import("svelte").Component<Props, {}, "open">;
|
|
9
|
+
type SvSheetIteration = ReturnType<typeof SvSheetIteration>;
|
|
10
|
+
export default SvSheetIteration;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Excel's Insert Hyperlink dialog, as the three fields that matter: where
|
|
4
|
+
* it goes, what the cell says, and what hovering says. Opened by
|
|
5
|
+
* Insert > Link or Ctrl+K, and again on a cell that already has one,
|
|
6
|
+
* which is how a link is edited.
|
|
7
|
+
*/
|
|
8
|
+
import { SvModal } from '@svgrid/grid'
|
|
9
|
+
import { useSheetText } from './sheet-text'
|
|
10
|
+
import { isSafeLinkTarget, parseLinkTarget, type SheetLink } from './sheet/links'
|
|
11
|
+
|
|
12
|
+
type Props = {
|
|
13
|
+
open?: boolean
|
|
14
|
+
/** The link as it stands, or a blank one for a cell that has none. */
|
|
15
|
+
link: SheetLink
|
|
16
|
+
/** What the cell shows right now, offered as the text. */
|
|
17
|
+
text: string
|
|
18
|
+
/** The cell's address, for the title. */
|
|
19
|
+
where: string
|
|
20
|
+
existing?: boolean
|
|
21
|
+
onApply: (link: SheetLink, text: string) => void
|
|
22
|
+
onRemove?: () => void
|
|
23
|
+
onClose?: () => void
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let { open = $bindable(false), link, text, where, existing = false, onApply, onRemove, onClose }: Props = $props()
|
|
27
|
+
const t = useSheetText()
|
|
28
|
+
|
|
29
|
+
let address = $state('')
|
|
30
|
+
let label = $state('')
|
|
31
|
+
let tip = $state('')
|
|
32
|
+
let error = $state('')
|
|
33
|
+
let first = $state<HTMLInputElement | null>(null)
|
|
34
|
+
|
|
35
|
+
$effect(() => {
|
|
36
|
+
if (!open) return
|
|
37
|
+
address = link.target
|
|
38
|
+
label = text
|
|
39
|
+
tip = link.tip ?? ''
|
|
40
|
+
error = ''
|
|
41
|
+
queueMicrotask(() => first?.focus())
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
function ok() {
|
|
45
|
+
const target = parseLinkTarget(address)
|
|
46
|
+
if (!target) {
|
|
47
|
+
// Two ways to have no target, and they are not the same mistake: an
|
|
48
|
+
// address nobody typed, and one carrying a scheme this shell will not
|
|
49
|
+
// open. Telling the second one it is empty sends the user back to a
|
|
50
|
+
// field that is not.
|
|
51
|
+
error = address.trim() && !isSafeLinkTarget(address) ? t('link.unsafeScheme') : t('link.badAddress')
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
const next: SheetLink = { target: address.trim() }
|
|
55
|
+
if (tip.trim()) next.tip = tip.trim()
|
|
56
|
+
open = false
|
|
57
|
+
onApply(next, label)
|
|
58
|
+
onClose?.()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function close() {
|
|
62
|
+
open = false
|
|
63
|
+
onClose?.()
|
|
64
|
+
}
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<SvModal bind:open onClose={onClose} title={`${t('link.title')} – ${where}`} size="sm">
|
|
68
|
+
<form class="sv-sheet-dialog" onsubmit={(e) => { e.preventDefault(); ok() }}>
|
|
69
|
+
<label class="field">
|
|
70
|
+
<span>{t('link.address')}</span>
|
|
71
|
+
<input type="text" bind:this={first} bind:value={address} spellcheck="false" placeholder={t('link.addressPlaceholder')} />
|
|
72
|
+
</label>
|
|
73
|
+
<label class="field">
|
|
74
|
+
<span>{t('link.text')}</span>
|
|
75
|
+
<input type="text" bind:value={label} placeholder={t('link.textPlaceholder')} />
|
|
76
|
+
</label>
|
|
77
|
+
<label class="field">
|
|
78
|
+
<span>{t('link.tip')}</span>
|
|
79
|
+
<input type="text" bind:value={tip} placeholder={t('link.tipPlaceholder')} />
|
|
80
|
+
</label>
|
|
81
|
+
{#if error}<p class="error">{error}</p>{/if}
|
|
82
|
+
<p class="hint">{t('link.hint')}</p>
|
|
83
|
+
</form>
|
|
84
|
+
{#snippet footer()}
|
|
85
|
+
<div class="sv-sheet-dialog-buttons">
|
|
86
|
+
{#if existing && onRemove}
|
|
87
|
+
<button type="button" class="btn" onclick={() => { open = false; onRemove?.() }}>{t('link.remove')}</button>
|
|
88
|
+
{/if}
|
|
89
|
+
<span class="spacer"></span>
|
|
90
|
+
<button type="button" class="btn primary" onclick={ok}>{t('ok')}</button>
|
|
91
|
+
<button type="button" class="btn" onclick={close}>{t('cancel')}</button>
|
|
92
|
+
</div>
|
|
93
|
+
{/snippet}
|
|
94
|
+
</SvModal>
|
|
95
|
+
|
|
96
|
+
<style>
|
|
97
|
+
.spacer { flex: 1; }
|
|
98
|
+
.error { margin: 4px 0 0; color: var(--sg-danger, #c42b1c); font-size: 12px; }
|
|
99
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type SheetLink } from './sheet/links.js';
|
|
2
|
+
type Props = {
|
|
3
|
+
open?: boolean;
|
|
4
|
+
/** The link as it stands, or a blank one for a cell that has none. */
|
|
5
|
+
link: SheetLink;
|
|
6
|
+
/** What the cell shows right now, offered as the text. */
|
|
7
|
+
text: string;
|
|
8
|
+
/** The cell's address, for the title. */
|
|
9
|
+
where: string;
|
|
10
|
+
existing?: boolean;
|
|
11
|
+
onApply: (link: SheetLink, text: string) => void;
|
|
12
|
+
onRemove?: () => void;
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
};
|
|
15
|
+
declare const SvSheetLink: import("svelte").Component<Props, {}, "open">;
|
|
16
|
+
type SvSheetLink = ReturnType<typeof SvSheetLink>;
|
|
17
|
+
export default SvSheetLink;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* and Enter to pick, Escape to leave the cell as it is. The shell mounts
|
|
6
6
|
* it inside the popover anchored to the cell.
|
|
7
7
|
*/
|
|
8
|
+
import { useSheetText } from './sheet-text'
|
|
8
9
|
type Props = {
|
|
9
10
|
choices: ReadonlyArray<string>
|
|
10
11
|
/** The cell's current text, marked in the list. */
|
|
@@ -14,6 +15,7 @@
|
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
let { choices, value, onPick, onCancel }: Props = $props()
|
|
18
|
+
const t = useSheetText()
|
|
17
19
|
|
|
18
20
|
let list = $state<HTMLDivElement | null>(null)
|
|
19
21
|
let index = $state(0)
|
|
@@ -42,13 +44,13 @@
|
|
|
42
44
|
bind:this={list}
|
|
43
45
|
class="sv-sheet-list-picker"
|
|
44
46
|
role="listbox"
|
|
45
|
-
aria-label=
|
|
47
|
+
aria-label={t('choices')}
|
|
46
48
|
tabindex="0"
|
|
47
49
|
aria-activedescendant={choices.length ? `sv-sheet-choice-${index}` : undefined}
|
|
48
50
|
onkeydown={onKeyDown}
|
|
49
51
|
>
|
|
50
52
|
{#if choices.length === 0}
|
|
51
|
-
<div class="empty">
|
|
53
|
+
<div class="empty">{t('listEmpty')}</div>
|
|
52
54
|
{:else}
|
|
53
55
|
{#each choices as choice, i (i)}
|
|
54
56
|
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_interactive_supports_focus -->
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The list a validated cell drops down: Excel's in-cell dropdown. The
|
|
3
|
-
* choices as the rule lists them, the current value marked, arrow keys
|
|
4
|
-
* and Enter to pick, Escape to leave the cell as it is. The shell mounts
|
|
5
|
-
* it inside the popover anchored to the cell.
|
|
6
|
-
*/
|
|
7
1
|
type Props = {
|
|
8
2
|
choices: ReadonlyArray<string>;
|
|
9
3
|
/** The cell's current text, marked in the list. */
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* list is a working copy: OK hands it back as one change, Cancel drops
|
|
8
8
|
* it.
|
|
9
9
|
*/
|
|
10
|
+
import { useSheetText } from './sheet-text'
|
|
10
11
|
import { SvModal } from '@svgrid/grid'
|
|
11
12
|
import { describeCf, hasStyle, cfIn, type CfRule, type CfStyledRule } from './sheet/conditional-formats'
|
|
12
13
|
import { colToLetters } from './sheet/address'
|
|
@@ -25,6 +26,7 @@
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
let { open = $bindable(false), rules, selection, onApply, onEdit, onClose }: Props = $props()
|
|
29
|
+
const t = useSheetText()
|
|
28
30
|
|
|
29
31
|
let working = $state<CfRule[]>([])
|
|
30
32
|
let scope = $state<'sheet' | 'selection'>('sheet')
|
|
@@ -55,7 +57,7 @@
|
|
|
55
57
|
if (hasStyle(rule)) return { background: rule.style.fill, color: rule.style.color, text: 'AaBbCcYyZz' }
|
|
56
58
|
if (rule.kind === 'dataBar') return { background: `linear-gradient(90deg, ${rule.color} 60%, transparent 60%)`, text: '' }
|
|
57
59
|
if (rule.kind === 'colorScale') return { background: `linear-gradient(90deg, ${rule.colors.join(', ')})`, text: '' }
|
|
58
|
-
return { text: '
|
|
60
|
+
return { text: t('manageRules.iconSet') }
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
function remove() {
|
|
@@ -93,30 +95,30 @@
|
|
|
93
95
|
}
|
|
94
96
|
</script>
|
|
95
97
|
|
|
96
|
-
<SvModal bind:open onClose={onClose} title=
|
|
98
|
+
<SvModal bind:open onClose={onClose} title={t('manageRules.title')} size="md" width={640}>
|
|
97
99
|
<div class="sv-sheet-dialog manage">
|
|
98
100
|
<label class="field auto">
|
|
99
|
-
<span>
|
|
101
|
+
<span>{t('manageRules.showFor')}</span>
|
|
100
102
|
<select bind:value={scope}>
|
|
101
|
-
<option value="sheet">
|
|
102
|
-
<option value="selection">
|
|
103
|
+
<option value="sheet">{t('manageRules.thisSheet')}</option>
|
|
104
|
+
<option value="selection">{t('manageRules.selection')}</option>
|
|
103
105
|
</select>
|
|
104
106
|
</label>
|
|
105
107
|
<div class="toolbar">
|
|
106
|
-
<button type="button" class="btn" onclick={edit} disabled={!current || !hasStyle(current)}>
|
|
107
|
-
<button type="button" class="btn" onclick={remove} disabled={!current}>
|
|
108
|
-
<button type="button" class="btn" onclick={() => move(-1)} disabled={index <= 0} aria-label=
|
|
109
|
-
<button type="button" class="btn" onclick={() => move(1)} disabled={index < 0 || index >= working.length - 1} aria-label=
|
|
108
|
+
<button type="button" class="btn" onclick={edit} disabled={!current || !hasStyle(current)}>{t('manageRules.editRule')}</button>
|
|
109
|
+
<button type="button" class="btn" onclick={remove} disabled={!current}>{t('manageRules.deleteRule')}</button>
|
|
110
|
+
<button type="button" class="btn" onclick={() => move(-1)} disabled={index <= 0} aria-label={t('manageRules.moveUp')} title={t('manageRules.moveUp')}>▲</button>
|
|
111
|
+
<button type="button" class="btn" onclick={() => move(1)} disabled={index < 0 || index >= working.length - 1} aria-label={t('manageRules.moveDown')} title={t('manageRules.moveDown')}>▼</button>
|
|
110
112
|
</div>
|
|
111
|
-
<div class="list" role="grid" aria-label=
|
|
113
|
+
<div class="list" role="grid" aria-label={t('manageRules.rules')}>
|
|
112
114
|
<div class="head" role="row">
|
|
113
|
-
<span role="columnheader">
|
|
114
|
-
<span role="columnheader">
|
|
115
|
-
<span role="columnheader">
|
|
116
|
-
<span role="columnheader">
|
|
115
|
+
<span role="columnheader">{t('manageRules.rule')}</span>
|
|
116
|
+
<span role="columnheader">{t('manageRules.format')}</span>
|
|
117
|
+
<span role="columnheader">{t('manageRules.appliesTo')}</span>
|
|
118
|
+
<span role="columnheader">{t('manageRules.stopIfTrue')}</span>
|
|
117
119
|
</div>
|
|
118
120
|
{#if shown.length === 0}
|
|
119
|
-
<div class="empty">
|
|
121
|
+
<div class="empty">{t(scope === 'sheet' ? 'manageRules.noneOnSheet' : 'manageRules.noneInSelection')}</div>
|
|
120
122
|
{/if}
|
|
121
123
|
{#each shown as rule (rule.id)}
|
|
122
124
|
{@const s = sample(rule)}
|
|
@@ -125,15 +127,15 @@
|
|
|
125
127
|
<span role="gridcell" class="what">{describeCf(rule)}</span>
|
|
126
128
|
<span role="gridcell" class="sample" style:background={s.background ?? 'transparent'} style:color={s.color ?? 'inherit'}>{s.text}</span>
|
|
127
129
|
<span role="gridcell" class="where">{address(rule.rects)}</span>
|
|
128
|
-
<span role="gridcell" class="stop"><input type="checkbox" checked={!!rule.stopIfTrue} aria-label=
|
|
130
|
+
<span role="gridcell" class="stop"><input type="checkbox" checked={!!rule.stopIfTrue} aria-label={t('manageRules.stopIfTrue')} onchange={() => toggleStop(rule)} onclick={(e) => e.stopPropagation()} /></span>
|
|
129
131
|
</div>
|
|
130
132
|
{/each}
|
|
131
133
|
</div>
|
|
132
134
|
</div>
|
|
133
135
|
{#snippet footer()}
|
|
134
136
|
<div class="sv-sheet-dialog-buttons">
|
|
135
|
-
<button type="button" class="btn primary" onclick={ok}>
|
|
136
|
-
<button type="button" class="btn" onclick={close}>
|
|
137
|
+
<button type="button" class="btn primary" onclick={ok}>{t('ok')}</button>
|
|
138
|
+
<button type="button" class="btn" onclick={close}>{t('cancel')}</button>
|
|
137
139
|
</div>
|
|
138
140
|
{/snippet}
|
|
139
141
|
</SvModal>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Writes go to `workbook.names`, and the shell is told afterwards, since
|
|
6
6
|
* no cell was typed into and the sheet would otherwise not repaint.
|
|
7
7
|
*/
|
|
8
|
+
import { useSheetText } from './sheet-text'
|
|
8
9
|
import { SvModal } from '@svgrid/grid'
|
|
9
10
|
import type { Workbook } from './sheet/workbook'
|
|
10
11
|
import type { DefinedName } from './sheet/names'
|
|
@@ -20,6 +21,7 @@
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
let { open = $bindable(false), workbook, onChange, onClose }: Props = $props()
|
|
24
|
+
const t = useSheetText()
|
|
23
25
|
|
|
24
26
|
let names = $state<DefinedName[]>([])
|
|
25
27
|
let newName = $state('')
|
|
@@ -123,11 +125,11 @@
|
|
|
123
125
|
}
|
|
124
126
|
</script>
|
|
125
127
|
|
|
126
|
-
<SvModal bind:open onClose={onClose} title=
|
|
127
|
-
<div class="sv-sheet-dialog manager" role="group" aria-label=
|
|
128
|
+
<SvModal bind:open onClose={onClose} title={t('nameManager.title')} size="md">
|
|
129
|
+
<div class="sv-sheet-dialog manager" role="group" aria-label={t('nameManager.title')}>
|
|
128
130
|
<table class="names">
|
|
129
131
|
<thead>
|
|
130
|
-
<tr><th>
|
|
132
|
+
<tr><th>{t('nameManager.name')}</th><th>{t('nameManager.refersTo')}</th><th>{t('nameManager.value')}</th><th></th></tr>
|
|
131
133
|
</thead>
|
|
132
134
|
<tbody>
|
|
133
135
|
{#each names as entry (entry.name)}
|
|
@@ -138,7 +140,7 @@
|
|
|
138
140
|
<input
|
|
139
141
|
type="text"
|
|
140
142
|
bind:value={editRefersTo}
|
|
141
|
-
aria-label=
|
|
143
|
+
aria-label={t('nameManager.refersTo')}
|
|
142
144
|
spellcheck="false"
|
|
143
145
|
onkeydown={(e) => { if (e.key === 'Enter') { e.preventDefault(); saveEdit() } if (e.key === 'Escape') { e.stopPropagation(); editing = null } }}
|
|
144
146
|
/>
|
|
@@ -149,36 +151,36 @@
|
|
|
149
151
|
<td class="num">{valueOf(entry)}</td>
|
|
150
152
|
<td class="actions">
|
|
151
153
|
{#if editing === entry.name}
|
|
152
|
-
<button type="button" class="link" onclick={saveEdit}>
|
|
153
|
-
<button type="button" class="link" onclick={() => (editing = null)}>
|
|
154
|
+
<button type="button" class="link" onclick={saveEdit}>{t('save')}</button>
|
|
155
|
+
<button type="button" class="link" onclick={() => (editing = null)}>{t('cancel')}</button>
|
|
154
156
|
{:else}
|
|
155
|
-
<button type="button" class="link" onclick={() => startEdit(entry)}>
|
|
156
|
-
<button type="button" class="link" onclick={() => remove(entry.name)}>
|
|
157
|
+
<button type="button" class="link" onclick={() => startEdit(entry)}>{t('nameManager.edit')}</button>
|
|
158
|
+
<button type="button" class="link" onclick={() => remove(entry.name)}>{t('delete')}</button>
|
|
157
159
|
{/if}
|
|
158
160
|
</td>
|
|
159
161
|
</tr>
|
|
160
162
|
{:else}
|
|
161
|
-
<tr><td colspan="4" class="empty">
|
|
163
|
+
<tr><td colspan="4" class="empty">{t('nameManager.empty')}</td></tr>
|
|
162
164
|
{/each}
|
|
163
165
|
</tbody>
|
|
164
166
|
</table>
|
|
165
167
|
|
|
166
168
|
<form class="new" onsubmit={(e) => { e.preventDefault(); add() }}>
|
|
167
169
|
<label>
|
|
168
|
-
<span>
|
|
169
|
-
<input type="text" bind:value={newName} placeholder=
|
|
170
|
+
<span>{t('nameManager.nameField')}</span>
|
|
171
|
+
<input type="text" bind:value={newName} placeholder={t('nameManager.namePlaceholder')} spellcheck="false" />
|
|
170
172
|
</label>
|
|
171
173
|
<label>
|
|
172
|
-
<span>
|
|
173
|
-
<input type="text" bind:value={newRefersTo} placeholder=
|
|
174
|
+
<span>{t('nameManager.refersToField')}</span>
|
|
175
|
+
<input type="text" bind:value={newRefersTo} placeholder={t('nameManager.refersToPlaceholder')} spellcheck="false" />
|
|
174
176
|
</label>
|
|
175
|
-
<button type="submit" class="btn">
|
|
177
|
+
<button type="submit" class="btn">{t('nameManager.new')}</button>
|
|
176
178
|
</form>
|
|
177
179
|
{#if problem}<p class="status problem" role="alert">{problem}</p>{/if}
|
|
178
180
|
</div>
|
|
179
181
|
{#snippet footer()}
|
|
180
182
|
<div class="sv-sheet-dialog-buttons">
|
|
181
|
-
<button type="button" class="btn" onclick={close}>
|
|
183
|
+
<button type="button" class="btn" onclick={close}>{t('close')}</button>
|
|
182
184
|
</div>
|
|
183
185
|
{/snippet}
|
|
184
186
|
</SvModal>
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Excel's Page Setup dialog, the one page of it the sheet prints from:
|
|
4
|
+
* orientation, paper, a margins preset, the scale, the print area, the
|
|
5
|
+
* rows that repeat at the top of every page, and whether gridlines and
|
|
6
|
+
* headings print. Opens on the sheet's setup, hands the whole thing back
|
|
7
|
+
* on OK, and Print... hands it back and prints. Print Titles on the
|
|
8
|
+
* ribbon opens the same dialog, as Excel's opens Page Setup on its
|
|
9
|
+
* Sheet tab.
|
|
10
|
+
*/
|
|
11
|
+
import { useSheetText } from './sheet-text'
|
|
12
|
+
import { SvModal } from '@svgrid/grid'
|
|
13
|
+
import { MARGIN_PRESETS, PAPER_SIZES, marginPresetOf, copyPageSetup, type PageSetup, type PaperSize, type MarginPreset } from './sheet/page-setup'
|
|
14
|
+
import { parseRangeText, rangeText } from './sheet/protection'
|
|
15
|
+
|
|
16
|
+
type Props = {
|
|
17
|
+
open?: boolean
|
|
18
|
+
/** The sheet's setup as it stands. */
|
|
19
|
+
setup: PageSetup
|
|
20
|
+
onApply: (setup: PageSetup) => void
|
|
21
|
+
/** Print...: the shell applies and prints. */
|
|
22
|
+
onPrint: () => void
|
|
23
|
+
onClose?: () => void
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let { open = $bindable(false), setup, onApply, onPrint, onClose }: Props = $props()
|
|
27
|
+
const t = useSheetText()
|
|
28
|
+
|
|
29
|
+
let orientation = $state<PageSetup['orientation']>('portrait')
|
|
30
|
+
let paper = $state<PaperSize>('A4')
|
|
31
|
+
let margins = $state<MarginPreset | 'custom'>('normal')
|
|
32
|
+
let scale = $state('100')
|
|
33
|
+
let area = $state('')
|
|
34
|
+
let titles = $state('')
|
|
35
|
+
let gridlines = $state(false)
|
|
36
|
+
let headings = $state(false)
|
|
37
|
+
let problem = $state<string | null>(null)
|
|
38
|
+
let first = $state<HTMLSelectElement | null>(null)
|
|
39
|
+
|
|
40
|
+
const PAPERS = Object.keys(PAPER_SIZES) as PaperSize[]
|
|
41
|
+
|
|
42
|
+
$effect(() => {
|
|
43
|
+
if (!open) return
|
|
44
|
+
orientation = setup.orientation
|
|
45
|
+
paper = setup.paper
|
|
46
|
+
margins = marginPresetOf(setup.margins) ?? 'custom'
|
|
47
|
+
scale = String(setup.scale)
|
|
48
|
+
area = setup.printArea ? rangeText(setup.printArea) : ''
|
|
49
|
+
titles = setup.printTitleRows ? `${setup.printTitleRows[0] + 1}:${setup.printTitleRows[1] + 1}` : ''
|
|
50
|
+
gridlines = setup.gridlines
|
|
51
|
+
headings = setup.headings
|
|
52
|
+
problem = null
|
|
53
|
+
queueMicrotask(() => first?.focus())
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
/** The setup as the fields say, or null with `problem` set. */
|
|
57
|
+
function read(): PageSetup | null {
|
|
58
|
+
const next = copyPageSetup(setup)
|
|
59
|
+
next.orientation = orientation
|
|
60
|
+
next.paper = paper
|
|
61
|
+
if (margins !== 'custom') next.margins = { ...MARGIN_PRESETS[margins] }
|
|
62
|
+
const pct = Number(scale)
|
|
63
|
+
next.scale = Number.isFinite(pct) && pct >= 10 && pct <= 400 ? Math.round(pct) : 100
|
|
64
|
+
if (area.trim()) {
|
|
65
|
+
const rects = parseRangeText(area)
|
|
66
|
+
if (!rects) { problem = t('pageSetup.invalidArea', { text: area }); return null }
|
|
67
|
+
next.printArea = rects
|
|
68
|
+
} else next.printArea = null
|
|
69
|
+
if (titles.trim()) {
|
|
70
|
+
const m = /^\$?(\d+)\s*:\s*\$?(\d+)$/.exec(titles.trim()) ?? /^\$?(\d+)$/.exec(titles.trim())
|
|
71
|
+
if (!m) { problem = t('pageSetup.invalidRows', { text: titles }); return null }
|
|
72
|
+
const a = Number(m[1]) - 1
|
|
73
|
+
const b = Number(m[2] ?? m[1]) - 1
|
|
74
|
+
if (a < 0 || b < a) { problem = t('pageSetup.invalidRows', { text: titles }); return null }
|
|
75
|
+
next.printTitleRows = [a, b]
|
|
76
|
+
} else next.printTitleRows = null
|
|
77
|
+
next.gridlines = gridlines
|
|
78
|
+
next.headings = headings
|
|
79
|
+
problem = null
|
|
80
|
+
return next
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function ok() {
|
|
84
|
+
const next = read()
|
|
85
|
+
if (!next) return
|
|
86
|
+
open = false
|
|
87
|
+
onApply(next)
|
|
88
|
+
onClose?.()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function print() {
|
|
92
|
+
const next = read()
|
|
93
|
+
if (!next) return
|
|
94
|
+
open = false
|
|
95
|
+
onApply(next)
|
|
96
|
+
onPrint()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function close() {
|
|
100
|
+
open = false
|
|
101
|
+
onClose?.()
|
|
102
|
+
}
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
<SvModal bind:open onClose={onClose} title={t('pageSetup.title')} size="sm" width={420}>
|
|
106
|
+
<form class="sv-sheet-dialog" onsubmit={(e) => { e.preventDefault(); ok() }}>
|
|
107
|
+
<label class="field">
|
|
108
|
+
<span>{t('pageSetup.orientation')}</span>
|
|
109
|
+
<select bind:this={first} bind:value={orientation}>
|
|
110
|
+
<option value="portrait">{t('pageSetup.portrait')}</option>
|
|
111
|
+
<option value="landscape">{t('pageSetup.landscape')}</option>
|
|
112
|
+
</select>
|
|
113
|
+
</label>
|
|
114
|
+
<label class="field">
|
|
115
|
+
<span>{t('pageSetup.paper')}</span>
|
|
116
|
+
<select bind:value={paper}>
|
|
117
|
+
{#each PAPERS as p (p)}<option value={p}>{p}</option>{/each}
|
|
118
|
+
</select>
|
|
119
|
+
</label>
|
|
120
|
+
<label class="field">
|
|
121
|
+
<span>{t('pageSetup.margins')}</span>
|
|
122
|
+
<select bind:value={margins}>
|
|
123
|
+
<option value="normal">{t('pageSetup.margins.normal')}</option>
|
|
124
|
+
<option value="narrow">{t('pageSetup.margins.narrow')}</option>
|
|
125
|
+
<option value="wide">{t('pageSetup.margins.wide')}</option>
|
|
126
|
+
{#if margins === 'custom'}<option value="custom">{t('pageSetup.margins.custom')}</option>{/if}
|
|
127
|
+
</select>
|
|
128
|
+
</label>
|
|
129
|
+
<label class="field">
|
|
130
|
+
<span>{t('pageSetup.scale')}</span>
|
|
131
|
+
<input type="number" min="10" max="400" bind:value={scale} />
|
|
132
|
+
</label>
|
|
133
|
+
<label class="field">
|
|
134
|
+
<span>{t('pageSetup.printArea')}</span>
|
|
135
|
+
<input type="text" bind:value={area} spellcheck="false" placeholder={t('pageSetup.printAreaPlaceholder')} />
|
|
136
|
+
</label>
|
|
137
|
+
<label class="field">
|
|
138
|
+
<span>{t('pageSetup.titleRows')}</span>
|
|
139
|
+
<input type="text" bind:value={titles} spellcheck="false" placeholder={t('pageSetup.titleRowsPlaceholder')} />
|
|
140
|
+
</label>
|
|
141
|
+
<div class="checks">
|
|
142
|
+
<label class="check"><input type="checkbox" bind:checked={gridlines} /> {t('pageSetup.gridlines')}</label>
|
|
143
|
+
<label class="check"><input type="checkbox" bind:checked={headings} /> {t('pageSetup.headings')}</label>
|
|
144
|
+
</div>
|
|
145
|
+
{#if problem}<p class="status problem" role="alert">{problem}</p>{/if}
|
|
146
|
+
</form>
|
|
147
|
+
{#snippet footer()}
|
|
148
|
+
<div class="sv-sheet-dialog-buttons">
|
|
149
|
+
<button type="button" class="btn" onclick={print}>{t('pageSetup.print')}</button>
|
|
150
|
+
<span class="spacer"></span>
|
|
151
|
+
<button type="button" class="btn primary" onclick={ok}>{t('ok')}</button>
|
|
152
|
+
<button type="button" class="btn" onclick={close}>{t('cancel')}</button>
|
|
153
|
+
</div>
|
|
154
|
+
{/snippet}
|
|
155
|
+
</SvModal>
|
|
156
|
+
|
|
157
|
+
<style>
|
|
158
|
+
.spacer { flex: 1; }
|
|
159
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type PageSetup } from './sheet/page-setup.js';
|
|
2
|
+
type Props = {
|
|
3
|
+
open?: boolean;
|
|
4
|
+
/** The sheet's setup as it stands. */
|
|
5
|
+
setup: PageSetup;
|
|
6
|
+
onApply: (setup: PageSetup) => void;
|
|
7
|
+
/** Print...: the shell applies and prints. */
|
|
8
|
+
onPrint: () => void;
|
|
9
|
+
onClose?: () => void;
|
|
10
|
+
};
|
|
11
|
+
declare const SvSheetPageSetup: import("svelte").Component<Props, {}, "open">;
|
|
12
|
+
type SvSheetPageSetup = ReturnType<typeof SvSheetPageSetup>;
|
|
13
|
+
export default SvSheetPageSetup;
|