@xlcalc/vue 0.21.2 → 0.23.1

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.
Files changed (104) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +7 -2
  3. package/dist/components/CfDialogs.vue.d.ts +3 -0
  4. package/dist/components/CfManager.vue.d.ts +3 -0
  5. package/dist/components/CfPreview.vue.d.ts +9 -0
  6. package/dist/components/CfQuickDialog.vue.d.ts +3 -0
  7. package/dist/components/CfRuleDialog.vue.d.ts +3 -0
  8. package/dist/components/CfStyleDialog.vue.d.ts +15 -0
  9. package/dist/components/CfValuesFields.vue.d.ts +9 -0
  10. package/dist/components/DialogShell.vue.d.ts +1 -1
  11. package/dist/components/FunctionList.vue.d.ts +2 -1
  12. package/dist/components/GoToDialog.vue.d.ts +3 -0
  13. package/dist/components/LinkDialog.vue.d.ts +3 -0
  14. package/dist/components/NameBox.vue.d.ts +3 -0
  15. package/dist/components/NameDialogs.vue.d.ts +3 -0
  16. package/dist/components/NoteBox.vue.d.ts +3 -0
  17. package/dist/components/SheetToolbar.vue.d.ts +7 -4
  18. package/dist/components/SheetView.vue.d.ts +11 -4
  19. package/dist/components/SpellingDialog.vue.d.ts +3 -0
  20. package/dist/components/SymbolDialog.vue.d.ts +3 -0
  21. package/dist/components/TableDialog.vue.d.ts +3 -0
  22. package/dist/components/ToolbarBox.vue.d.ts +31 -0
  23. package/dist/components/TraceArrows.vue.d.ts +3 -0
  24. package/dist/components/ValidationDialog.vue.d.ts +3 -0
  25. package/dist/components/WatchWindow.vue.d.ts +3 -0
  26. package/dist/components/ZoomBar.vue.d.ts +3 -0
  27. package/dist/components/ZoomDialog.vue.d.ts +3 -0
  28. package/dist/components/icons.d.ts +1 -0
  29. package/dist/components/name-icons.d.ts +1 -0
  30. package/dist/components/toolbar-icons.d.ts +16 -0
  31. package/dist/contract/conditional.d.ts +16 -0
  32. package/dist/contract/memory.d.ts +5 -0
  33. package/dist/contract/messages.d.ts +260 -1
  34. package/dist/contract/source.d.ts +41 -0
  35. package/dist/contract/view.d.ts +117 -2
  36. package/dist/contract/workbook.d.ts +73 -0
  37. package/dist/contract.d.ts +4 -2
  38. package/dist/core/autocomplete.d.ts +9 -1
  39. package/dist/core/autosum.d.ts +11 -0
  40. package/dist/core/cell-style.d.ts +5 -0
  41. package/dist/core/cell-view.d.ts +2 -0
  42. package/dist/core/cf-commands.d.ts +70 -0
  43. package/dist/core/cf-describe.d.ts +4 -0
  44. package/dist/core/cf-draft.d.ts +114 -0
  45. package/dist/core/cf-formula.d.ts +30 -0
  46. package/dist/core/cf-presets.d.ts +33 -0
  47. package/dist/core/cf-ranges.d.ts +22 -0
  48. package/dist/core/commands.d.ts +4 -2
  49. package/dist/core/editing.d.ts +6 -1
  50. package/dist/core/extras.d.ts +22 -0
  51. package/dist/core/fill.d.ts +3 -0
  52. package/dist/core/formula-view.d.ts +10 -0
  53. package/dist/core/geometry.d.ts +6 -0
  54. package/dist/core/goto.d.ts +24 -0
  55. package/dist/core/links.d.ts +105 -0
  56. package/dist/core/menu.d.ts +8 -0
  57. package/dist/core/name-dialogs.d.ts +63 -0
  58. package/dist/core/names.d.ts +33 -0
  59. package/dist/core/navigation.d.ts +6 -0
  60. package/dist/core/notes.d.ts +44 -0
  61. package/dist/core/place.d.ts +10 -0
  62. package/dist/core/range-read.d.ts +11 -0
  63. package/dist/core/sheet.d.ts +337 -4
  64. package/dist/core/spell-check.d.ts +54 -0
  65. package/dist/core/state.d.ts +9 -0
  66. package/dist/core/tables.d.ts +63 -0
  67. package/dist/core/trace.d.ts +26 -0
  68. package/dist/core/validation-dialog.d.ts +33 -0
  69. package/dist/core/validation.d.ts +17 -3
  70. package/dist/core/viewport.d.ts +12 -0
  71. package/dist/core/watch.d.ts +35 -0
  72. package/dist/core/windows.d.ts +2 -0
  73. package/dist/core/zoom.d.ts +44 -0
  74. package/dist/format-cells.d.ts +0 -6
  75. package/dist/formula-shift.d.ts +3 -0
  76. package/dist/index.js +12033 -4565
  77. package/dist/local/types.d.ts +4 -1
  78. package/dist/local/workbook.d.ts +25 -0
  79. package/dist/local.js +556 -277
  80. package/dist/memory-workbook.d.ts +21 -0
  81. package/dist/messages-conditional.d.ts +3 -0
  82. package/dist/rect.d.ts +2 -0
  83. package/dist/{ru-RU-BVeg6JGM.js → ru-RU-CzebvM-s.js} +19 -2
  84. package/dist/spelling.d.ts +6 -0
  85. package/dist/style.css +1 -1
  86. package/dist/symbols.d.ts +23 -0
  87. package/dist/toolbar.d.ts +53 -1
  88. package/dist/{typed-entry-2l9Ay-hV.js → typed-entry-3r1pEbc9.js} +4546 -4453
  89. package/dist/validation-rules.d.ts +95 -0
  90. package/docs/api.md +91 -10
  91. package/docs/autocomplete.md +3 -3
  92. package/docs/checks.md +1 -1
  93. package/docs/clipboard.md +1 -1
  94. package/docs/conditional-formatting.md +135 -0
  95. package/docs/editing.md +50 -1
  96. package/docs/go-to-and-symbol.md +37 -0
  97. package/docs/links-notes.md +36 -0
  98. package/docs/local.md +1 -1
  99. package/docs/names.md +62 -0
  100. package/docs/tables.md +40 -0
  101. package/docs/toolbar.md +6 -2
  102. package/docs/validation.md +47 -0
  103. package/docs/view.md +104 -1
  104. package/package.json +2 -2
package/docs/editing.md CHANGED
@@ -7,7 +7,11 @@ Editing uses Excel's keys:
7
7
  - Esc cancels the edit, and Alt+Enter inserts a line break;
8
8
  - Ctrl+Shift+U (or the arrow at the right end of the formula bar) expands the formula bar to five lines and collapses it back to one, as in Excel; while it is collapsed, a multi-line cell shows its first line and the grid does not move;
9
9
  - Delete and Backspace clear the selection;
10
+ - Ctrl+` shows the formulas instead of the values, as Excel's Show Formulas does ([view.md](view.md#show-formulas));
10
11
  - Ctrl+Page Down and Ctrl+Page Up go to the next and the previous visible sheet;
12
+ - F5 and Ctrl+G (Control+G on a Mac as well) open Excel's Go To dialog ([go-to-and-symbol.md](go-to-and-symbol.md));
13
+ - Ctrl+F3 opens the Name Manager, and Ctrl+L on a Mac Define Name, with a source that has defined names ([names.md](names.md));
14
+ - F7 opens Spelling when the source has `spelling` ([Spelling](#spelling)), and Ctrl+T or Ctrl+L (Control+T on a Mac) opens Create Table when it has `table` ([tables.md](tables.md));
11
15
  - Ctrl+arrow goes where the source's `end(sheet, cell, direction)` points, as Excel's Range.End, and Shift+Ctrl+arrow extends the selection there. Without `end`, or under a display filter, it goes to the edge of the data known to the sheet.
12
16
 
13
17
  Without `edit` the sheet is read-only.
@@ -67,6 +71,7 @@ When the outcome carries `correction`, the formula Excel suggests for an unclose
67
71
  The source's other optional methods enable the following:
68
72
 
69
73
  - Ctrl+Enter (Cmd+Return on a Mac), in the cell editor or the formula bar, enters the text into every cell of the selection through `fill(sheet, range, text, active)`, as Excel enters it from the active cell; the selection stays, and the text is sent even if it did not change. Without `fill`, or with a single cell, the text goes to the active cell through `edit` if it changed, as with Enter, and the active cell does not move.
74
+ - Ctrl+D and Ctrl+R (Cmd or Control on a Mac, as Excel for Mac takes either; with any keyboard layout) are Excel's Fill Down and Fill Right through `structure`, as a single `copyRange`: the selection's top row is copied over its other rows (its left column over its other columns) with its values, formulas and formatting, relative references shifting as Excel's fill shifts them and absolute ones kept. A selection one row tall takes the row above it, one column wide the column to its left, and row 1 alone (column A alone) is left as it is. Entire columns copy their first row down the whole sheet, and entire rows their first column across it. On a sheet the workbook itself filters, xlcalc's `copyRange` fills only the visible rows, as Excel's Fill Down does. Under the sheet's display filter, whose hidden rows the source does not know, nothing is filled, as nothing is pasted there from the sheet's own copy; a locked cell among the filled ones is reported instead, as is what the source refuses (xlcalc refuses a copy that would split a merged area or part of an array, as Excel does). The selection stays as it was. On an editable sheet the keys do not reach the browser (its bookmark and reload), even where nothing can be filled; on a read-only sheet they do. A host's ribbon runs the same commands through `fillDown()` and `fillRight()` ([api.md](api.md#sheetviewapi)); Excel's cell context menu has no Fill commands, and neither does the sheet's.
70
75
  - A paste on the grid goes to `paste(sheet, cell, text)` as a single call at the selection's top-left cell, and the source parses the text as Excel pastes it. Without `paste`, the component splits the text as Excel pastes it (xlcalc's `parseClipboard`: a row at each line break, a field at each tab, and one more row of empty fields after a final line break) and sends the fields to `edit`; a range that would extend past the edge of the sheet is rejected. Pasting the sheet's own copy goes through `structure` instead ([clipboard.md](clipboard.md)).
71
76
  - Ctrl+Z and Ctrl+Y (Cmd on a Mac; Ctrl+Shift+Z also redoes; with any keyboard layout) on the grid call `undo()` and `redo()`, one call at a time. In an editor they undo the typing. Without these methods there is no undo.
72
77
  - A successful outcome's `select` sets where the selection goes after a paste, a fill, an undo or an edit; if it is on another sheet, the component switches to it as the Name Box does. If the selection was moved while the call was pending, it stays where it was moved.
@@ -74,7 +79,7 @@ The source's other optional methods enable the following:
74
79
  - Columns are drawn with xlcalc's geometry, the one it uses to lay out `####`, overflow and wrapped text (Excel for Mac's): a stored width is `columnWidthToPoints(width)` points, times 4/3 px rounded to a whole pixel, and a column whose width is `null` in a window is 53 points (71 px). A width dragged with the mouse is converted back through `columnWidthFromPoints`, in whole points, and the cells whose display changes with it come back in the `changes` of `layout`'s outcome and are redrawn, as an edit's are (a date that no longer shows `####`). The Column Width box counts characters of the stored width as Excel for Mac's does (`columnWidthToChars` and `columnWidthFromChars`): the default column is 8, and typing 8 gives the default back.
75
80
  - A window's `appearance` is the conditional formatting of its cells as xlcalc calculates it (`ConditionalAppearance`), and the grid draws it as Excel does: a rule's style over the cell's own (font color, bold, italic, underline, strikethrough, fill, borders; a fill hides gridlines as the cell's own fill does), a color scale's color as a fill, a data bar from its `start` to its `end` (from the right with `rightToLeft`; a gradient from the bar's color at its axis toward white, or a solid fill; a border; a dashed axis across the cell), an icon from any of the 20 icon sets at the left of the cell before its text, and with `hideValue` only the bar or the icon (an icon shown alone follows the cell's own alignment, left for General). The text and color produced by a rule's number format are the window's `text` and `colors`.
76
81
  - `subscribe(listener)` notifies the sheet of changes made elsewhere. `changed` patches the loaded windows; `reload` reads the sheets and windows again and reapplies a display filter; `repaint` with ranges re-reads in place only the windows of the displayed sheet that overlap the ranges: each window stays drawn until its response arrives, and the sizes, the scroll position and the display filter's rows stay as they are (a row that no longer matches the filter after an edit remains until the filter is reapplied, as Excel keeps it until Reapply). Repaints from one task are read together, and a repaint that arrives within 80 ms of the previous one aborts its request and reads once the burst ends; a `changed` that arrives while a window is being read is applied over its response, and a `changed` for cells off screen draws nothing. In the example after this list, `memorySource` simulates an edit from another tab and a rejection by a server.
77
- - Ctrl+B, Ctrl+I and Ctrl+U (Cmd on a Mac, with any keyboard layout) on the grid toggle bold, italic and underline over the selection according to the active cell's formatting, through `format`, as the toolbar buttons do. Without `format` the browser handles these keys.
82
+ - Ctrl+B, Ctrl+I and Ctrl+U (Cmd on a Mac, with any keyboard layout) on the grid toggle bold, italic and underline over the selection according to the active cell's formatting, through `format`, as the toolbar buttons do. Ctrl+Shift+% (Control on a Mac too, as in Excel for Mac, since Cmd+Shift+5 is the system's screenshot key; the key of 5 on any layout) applies Percent Style, Excel's `0%` (the built-in format 9), as the toolbar's button does. Without `format` the browser handles these keys.
78
83
  - Clicking a column letter or a row number selects the entire column or row up to Excel's last row or column, so the `state` event and the Name Box report `B:D`, `2:5`, or `1:1048576` for the entire sheet, and formatting applies to entire rows or columns.
79
84
 
80
85
  ```vue
@@ -95,3 +100,47 @@ const refuseNext = () => source.failNext({ ok: false, reason: 'refused', message
95
100
  <SheetView :source="source" style="height: 300px" />
96
101
  </template>
97
102
  ```
103
+
104
+ ## Spelling
105
+
106
+ If the source has `spelling(req)`, F7 (also on a Mac, where Excel uses it too) and the sheet's `checkSpelling()` method open Excel's Spelling dialog. The check starts at the active cell, goes by rows through the entire sheet, or only through the selection when more than one cell is selected, and wraps around to the cells before the active cell; formulas, words in uppercase and words with digits are not checked, as Excel's defaults. For each misspelt word the sheet selects its cell, and the dialog shows the cell's text with the word marked under Not in Dictionary and the source's corrections under Suggestions, the first one chosen (Up and Down choose another, a double click is Change):
107
+
108
+ - Ignore Once goes on to the next word, in the same cell first (`after` is the cell, `from` the position after the word);
109
+ - Ignore All skips the word for the rest of this check (`ignore`);
110
+ - Add to Dictionary, present when the source has `learnWord`, makes the word the user's own and goes on;
111
+ - Change writes the cell's text with the word replaced by the chosen suggestion through `edit`, as typed text (a text that opened with an apostrophe keeps it), and goes on after the new word;
112
+ - Change All does the same, and replaces the word in each cell it is found in afterwards without stopping there, as Excel goes on;
113
+ - Cancel or Esc ends the check.
114
+
115
+ When the check comes back to where it started, or there is nothing to correct, Excel's message says that the check is complete. On a read-only sheet Change and Change All are disabled; a locked cell is not changed. The editor keeps `spellcheck="false"`: Excel does not check spelling as you type. `memorySource` and `./local` check spelling with the host's `SpellChecker` (a dictionary such as hunspell's), given as their `spelling` option.
116
+
117
+ ```vue
118
+ <script setup lang="ts">
119
+ import { SheetView, memorySource } from '@xlcalc/vue'
120
+ import '@xlcalc/vue/style.css'
121
+
122
+ // A tiny word list for the example; a host passes a real dictionary
123
+ const words = new Set(['the', 'quick', 'brown', 'fox', 'jumps', 'over', 'lazy', 'dog'])
124
+ const own = new Set<string>()
125
+ const source = memorySource(
126
+ { sheets: [{ name: 'Notes', cells: { A1: 'teh quick brown fox', A2: 'jumps ovr the lazy dog', A3: 'teh end' } }] },
127
+ {
128
+ spelling: {
129
+ check: (w) => words.has(w.toLowerCase()) || own.has(w.toLowerCase()),
130
+ suggest: (w) => ({ teh: ['the', 'ten'], ovr: ['over'] })[w.toLowerCase()] ?? [],
131
+ add: (w) => void own.add(w.toLowerCase()),
132
+ },
133
+ },
134
+ )
135
+ </script>
136
+
137
+ <template>
138
+ <!-- click the grid and press F7 -->
139
+ <SheetView :source="source" style="height: 300px" />
140
+ </template>
141
+ ```
142
+
143
+ ## AutoSum
144
+
145
+ With a source that has `autoSum`, Alt+= (Option+= on a Mac, by the key's position on any layout) is Excel's AutoSum, and so is the sheet's `autoSum()` method, which a host's ribbon button calls. The source guesses the range as Excel does (`./local` through xlcalc's `getAutoSum`: the run of numbers above the cell, else to its left, up to a subtotal), and the active cell's edit opens with `=SUM(range)` in the source's locale and the range selected: Enter enters it, typing replaces the range and the arrows point at another, as in Point mode. Without numbers the edit opens with `=SUM()` and the caret between the parentheses. Excel's AutoSum over a selection of several cells, which enters the sums at once, is not offered: the sheet sums at the active cell. Excel also gives the sum the number format of what it sums (a sum of percentages shows as a percentage); xlcalc does not yet.
146
+
@@ -0,0 +1,37 @@
1
+ # Go To and Symbol
2
+
3
+ ## Go To
4
+
5
+ F5 and Ctrl+G on the grid open Excel's Go To dialog (Home > Find & Select > Go To); on a Mac it is Control+G, since Cmd+G finds again in the browser. The host opens it with the sheet's `goTo()` method ([api.md](api.md#sheetviewapi)). The dialog has the Go to list, the Reference box, OK and Cancel; Go To Special is not there.
6
+
7
+ The list shows the last four locations that jumps from Go To and from hyperlinks into the workbook have left, newest first, each once, written as Excel lists them: absolute and with the sheet's name (`Data!$B$2:$D$5`, `'Sheet 2'!$C:$C`). The Reference box opens with the first of them, so F5 and Enter go back to where the last jump came from, and F5 and Enter again return. A click on a location puts it into the Reference box, the up and down arrows step through the list from anywhere in the dialog, and a double click goes there. The locations last as long as the workbook does in the component. With a source that has `names`, the defined names that refer to ranges follow the locations, alphabetically, as the Name Box lists them, and OK on a name goes to its range ([names.md](names.md)).
8
+
9
+ OK (or Enter) goes to the reference as the Name Box does: a cell, a range, entire columns or rows, another sheet (`'Sheet 2'!B7`), with the flash and a Back history entry. Text that is not such a reference brings up Excel's alert, `Reference isn’t valid.`, with OK alone; afterwards the dialog stays with the text selected. Esc, Cancel or a click outside the dialog closes it and returns to the grid. The dialog works on a read-only sheet too. On a phone it takes the full screen, and on a touch screen its inputs and items are 44 px. Its texts are `SheetMessages`' `goToTitle`, `goToList`, `goToReference` and `goToBad`, with `ok` and `cancel`.
10
+
11
+ ## Symbol
12
+
13
+ The sheet's `insertSymbol()` method opens Excel's Symbol dialog (Insert > Symbol) on an editable sheet with an active cell; Excel has no key for it, so the host gives it a button. The dialog has two tabs.
14
+
15
+ Symbols: the Subset box, the grid of characters, the recently used symbols and the Character code box. The grid runs through the Unicode blocks of Excel's Subset list that a text font usually covers (Basic Latin, Latin-1 Supplement, the Latin extensions, Greek and Coptic, Cyrillic, General Punctuation, Currency Symbols, Letterlike Symbols, Number Forms, Arrows, Mathematical Operators, Box Drawing, Geometric Shapes, Miscellaneous Symbols, Dingbats and the others in `SymbolSubset`), with every assigned character in code order and without control characters. The Subset box shows the selected character's block, and choosing a block goes to its first character. The grid is 16 characters wide, as Excel's, or as many as fit on a narrow screen; the arrow keys move by a character and by a row, Home and End to the ends of the row (with Ctrl, of the grid), and Page Up and Page Down by the rows in view. The Character code box shows the selected character's Unicode code in hex (`00A9`) and selects the character whose code is typed there, with or without `U+`; a code outside the grid's blocks (`1F600`) is inserted too. The recently used symbols are a row of 16, newest first: Office's row (`€ £ ¥ © ® ™ ± ≠ ≤ ≥ ÷ × ∞ µ α β`) until something is inserted, then kept in the browser's storage under `storageKey`, otherwise for the lifetime of the component. The dialog opens on the last character inserted.
16
+
17
+ Special Characters: Excel's list by name, Em Dash, En Dash, Nonbreaking Hyphen, Optional Hyphen, Em Space, En Space, 1/4 Em Space, Nonbreaking Space, Copyright, Registered, Trademark, Section, Paragraph, Ellipsis, the single and double opening and closing quotes, No-Width Optional Break and No-Width Non Break.
18
+
19
+ The characters are shown in the active cell's font, Excel's "(normal text)"; the dialog has no font box. Insert, Enter or a double click inserts the selected character of the tab on display. While the cell or the formula bar is being edited, the character goes at the caret in place of the selected text, and the edit stays open while the dialog is shown. Otherwise Insert starts editing the active cell with the character as typing does, so the character replaces the cell's contents, as in Excel; to add to them, start the edit with F2 or a double click first. The dialog stays open for more characters, each after the last, and its Cancel button becomes Close; closing it (Esc, Close, a click outside) returns to the edit with the caret after the characters inserted, where Enter enters them, or to the grid when nothing was inserted. A locked cell gets the sheet's message instead. On a phone the dialog takes the full screen, and on a touch screen its cells, tabs and items are 44 px. Its texts are `SheetMessages`' `symbolTitle`, `symbolTab`, `symbolSubsetLabel`, `symbolSubset`, `symbolRecent`, `symbolCode`, `symbolCodeFrom`, `symbolCharacter`, `symbolSpecial` and `symbolInsert`, with `cancel` and `close`.
20
+
21
+ ```vue
22
+ <script setup lang="ts">
23
+ import { ref } from 'vue'
24
+ import { SheetView, memorySource, type SheetViewApi } from '@xlcalc/vue'
25
+ import '@xlcalc/vue/style.css'
26
+
27
+ const source = memorySource({ sheets: [{ name: 'Notes', cells: { A1: 'Price', B1: 'EUR 120' } }] })
28
+ const sheet = ref<SheetViewApi | null>(null)
29
+ </script>
30
+
31
+ <template>
32
+ <!-- mousedown.prevent keeps an open edit open: the symbol goes at its caret -->
33
+ <button @mousedown.prevent @click="sheet?.insertSymbol()">Symbol…</button>
34
+ <button @click="sheet?.goTo()">Go To…</button>
35
+ <SheetView ref="sheet" :source="source" style="height: 360px" />
36
+ </template>
37
+ ```
@@ -0,0 +1,36 @@
1
+ # Hyperlinks, notes, Clear and the default font
2
+
3
+ ## Hyperlinks
4
+
5
+ With the source's `link` and an editable sheet, Ctrl+K (Cmd+K on a Mac), the sheet's `insertLink()` method and the cell menu's Link open Excel's Insert Hyperlink dialog for the selection. On a cell that has a link the same commands open it as Edit Hyperlink, filled from the link, with Remove Link. The dialog has:
6
+
7
+ - Text to display: the active cell's text. On an empty cell it follows the address as it is typed, until it is typed in itself, as Excel's does. Over several cells, or on a cell with a formula, it shows `<<Selection in Document>>` and cannot be changed.
8
+ - Link to: Existing File or Web Page, with its Address, or Place in This Document, with Type the cell reference (A1 by default) and the places under Cell Reference, which are the workbook's visible sheets. The link's place is the chosen sheet and the reference, written as Excel writes it (`'Q 2'!B3:C4`); a reference that is not a cell or a range ("Reference isn’t valid.") keeps the dialog open. Under Defined Names are the workbook's names that refer to ranges, as the Name Box lists them ([names.md](names.md)), and a place of an edited link that is not a cell reference; a link to a name goes to its range.
9
+ - ScreenTip, a field in the dialog rather than Excel's separate ScreenTip box, and OK and Cancel; Enter is OK and Esc is Cancel.
10
+
11
+ OK writes the link over the selection through `link(sheet, range, link)`, the cells' contents kept, as a single undo step. When Text to display was changed, the sheet first enters the new text into the active cell through `edit`, as typed, and then writes the link: two undo steps where Excel's dialog makes one. An empty Text to display on OK means the address, as in Excel. Excel also gives a new link's cell its Hyperlink cell style; the sheet does not write a style, since it draws every link underlined in `--xs-link`.
12
+
13
+ The cell menu has Excel's hyperlink items: Link on a cell without a link; Edit Hyperlink, Open Hyperlink and Remove Hyperlink on a cell with one. Open Hyperlink follows the link as a click on it does: a place in the workbook is selected, any other link goes to the host's `openLink` when it listens (or with `hostLinks`), and otherwise a web link opens in a new tab. Remove Hyperlink removes the links over the selection, keeping the cells' text. Right-clicking a web link in a cell, or a long press on it, opens this menu when the sheet can edit links, as Excel's does; otherwise it leaves the browser's own menu for the link, as before. On a read-only sheet, or without `link`, only Open Hyperlink is offered, and Ctrl+K does nothing.
14
+
15
+ After `link` succeeds the sheet reads the windows over the range again, whether or not the source sends a `repaint`.
16
+
17
+ ## Notes
18
+
19
+ With the source's `note` and an editable sheet, the cell menu has Excel's New Note on a cell without a note, and Edit Note and Delete Note on a cell with one; Shift+F2 does New Note or Edit Note for the active cell, as in Excel. The note is edited in a box anchored to its cell, Excel's pale yellow note box to the right of the cell (to its left where the viewport has no room), with the author's name in bold on the first line: for a new note the `noteAuthor` prop, which a host sets to the user's name as Excel takes it from its Options, and for an existing note its own author. Enter starts a new line. Esc or a press outside the box saves the note through `note(sheet, cell, note)`, as Excel keeps a note's text once you leave it; an unchanged note sends nothing, and neither does a new one left empty without an author. Delete Note removes the active cell's note through `note(sheet, cell, null)`. Each is a single undo step, after which the sheet reads the windows over the cell again. Notes are displayed as before, with the red indicator and the cell's tooltip; Excel's Show/Hide Note and Show All Notes are not provided.
20
+
21
+ ## Clear Formats and Clear All
22
+
23
+ Excel has Clear Formats and Clear All under Home > Clear, not in the cell context menu, so the sheet has them as its method `clear(what)` for a host's own ribbon or buttons ([api.md](api.md#sheetviewapi)). With the source's `clear` and an editable sheet, `clear('formats')` removes the styles, number formats and conditional formats over the selection, and `clear('all')` also its contents, hyperlinks, notes and data validation rules, each as a single call to the source and so a single undo step. The selection goes as Excel writes it (`B2:D5`, `B:D`, `2:5`); under a display filter only its visible rows are cleared, as Excel clears only the visible cells of a filtered range, so the call carries the runs of visible rows (`A1:A2`, `A4`). A locked cell in the selection displays its reason and nothing is sent. Since the outcome carries the cells' values and not their formatting, the sheet reads the windows over the cleared ranges again in place, as on a `repaint`, whether or not the source sends one. Delete clears contents only, through `edit`, as before.
24
+
25
+ ## The workbook's default font
26
+
27
+ A sheet whose `SheetInfo` has `font` (`{ name, size }`, the workbook's Normal style) draws every cell without a font of its own in that font, as Excel draws it: the grid's table takes the font's name and its size in the grid's pixels (11 pt is 12.5 px, the rest in proportion), and the cells inherit it. A cell's own font name or size takes precedence. The row numbers and column letters keep the interface font, `--xs-font`. Without `font` nothing changes: cells are drawn in `--xs-font` and `--xs-font-size`. The row heights are the source's either way (`rowHeights`, `defaultRowHeight`), and overflow into empty neighbors goes by the column widths, so neither depends on the font.
28
+
29
+ `@xlcalc/vue/local` gives the workbook's font, and Calibri 11 for a workbook without one, since xlcalc measures column widths and `####` in Calibri 11 whatever the font. A browser without Calibri (most outside Windows and Office) draws the cells in a fallback font, whose widths differ, so a value can overflow where xlcalc says it fits. Calibri itself may not be served from a web page, but Carlito, under the SIL Open Font License, has Calibri's widths; a host serves it under Calibri's name, and an installed Calibri still takes precedence:
30
+
31
+ ```css
32
+ @font-face {
33
+ font-family: Calibri;
34
+ src: local('Calibri'), url('/fonts/Carlito-Regular.woff2') format('woff2');
35
+ }
36
+ ```
package/docs/local.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # In-browser calculation: `@xlcalc/vue/local`
2
2
 
3
- `localSource(book)` is a `SheetSource` over an xlcalc `BookInput`. It requires `xlcalc` 0.46.0 or later, an optional peer dependency of the package that the host installs. The workbook is calculated in a Web Worker (`xlcalc/worker`), or on the page's main thread with `calc: 'inline'`. The workbook's locale module is loaded when the source opens (ru-RU from `xlcalc/locales/ru-RU`); for a locale xlcalc has no module for, opening fails with the library's message.
3
+ `localSource(book)` is a `SheetSource` over an xlcalc `BookInput`. It requires `xlcalc` 0.46.0 or later, an optional peer dependency of the package that the host installs. Some of its methods need a later xlcalc: `autoSum` and the workbook's default font need 0.59.0 (with an older one there is no AutoSum and the font is Calibri 11), and with 0.59.0 `setNames` refuses a name Excel rejects (an older xlcalc accepts it). The workbook is calculated in a Web Worker (`xlcalc/worker`), or on the page's main thread with `calc: 'inline'`. The workbook's locale module is loaded when the source opens (ru-RU from `xlcalc/locales/ru-RU`); for a locale xlcalc has no module for, opening fails with the library's message.
4
4
 
5
5
  ## What the source does
6
6
 
package/docs/names.md ADDED
@@ -0,0 +1,62 @@
1
+ # Defined names
2
+
3
+ A source with `names(signal)` returns the workbook's defined names as Excel's Name Manager lists them: `SheetName` with the name, what it refers to (`ref`, a formula in the source's locale, without `=`) and the sheet it belongs to (`scope`; a name without one belongs to the workbook). With `setNames(names)` the sheet also defines and changes them: each change sends the entire list, which the source replaces as a single undo step, and a name the source rejects (a name Excel does not accept, one that already exists in its scope, a formula that does not parse) is refused with its message. Without `names` the sheet knows no names; without `setNames`, or on a read-only sheet, it shows them but does not change them.
4
+
5
+ On a sheet, as in Excel, the names visible are the sheet's own names and the workbook's names, a sheet's own name hiding a workbook name of the same name. A name refers to a range when its formula is a single reference to a range with its sheet (`Sheet1!$B$2:$D$9`, `'Plan 2'!$C:$C`); a constant (`0.2`), a formula, or several areas do not.
6
+
7
+ ## The Name Box
8
+
9
+ - A defined name typed into the Name Box and Enter go to its range, on its sheet. A sheet's own name of another sheet is typed with its sheet: `'Plan 2'!Total`. A name that does not refer to a range gives Excel's "Reference isn't valid." on the message line; Excel would go to the range a formula such as `OFFSET(...)` returns, which the sheet cannot calculate.
10
+ - When the selection is exactly a name's range on the active sheet, the Name Box shows the name instead of the address, as Excel's does (the first such name in alphabetical order).
11
+ - The arrow next to it lists the names visible on the active sheet that refer to ranges, in alphabetical order, as Excel's dropdown does; a click on one goes to its range. Alt+Down opens and closes the list from the box, Up, Down, Home and End move in it, Enter goes, Esc closes it.
12
+ - A new name typed with a selection (text that is neither an address nor a name) defines it over the selection, in the workbook's scope, as Excel's Name Box does: the name refers to the selection as an absolute reference with its sheet (`Sheet1!$A$1:$A$3`). A name the source refuses gives Excel's "You must enter a valid reference or type a valid name for the selection."
13
+
14
+ ## Define Name
15
+
16
+ The sheet's `defineName()` opens Excel's New Name dialog (Formulas > Define Name), as does Define Name… in the cell's context menu, and Ctrl+L in Excel for Mac. Its Name is empty, its Scope is Workbook (or one of the sheets, except very hidden ones), and Refers to is the selection as an absolute reference with its sheet and `=` (`=Sheet1!$B$2:$C$3`). OK adds the name through `setNames`; a refusal is shown in Excel's alert with the source's message, and the dialog stays open. The dialog's Comment is not offered: `SheetName` has none. Refers to is typed; selecting a range on the grid while the dialog is open is not supported. `defineName()` returns false when names cannot be defined (no `names` or `setNames`, a read-only sheet) or while a cell is being edited.
17
+
18
+ ## The Name Manager
19
+
20
+ Ctrl+F3 (on a Mac too) and the sheet's `nameManager()` open Excel's Name Manager: every name of the workbook, sorted by name, with its Refers To (with `=`) and Scope (the sheet's name, or Workbook). Excel's Value column is left out: it would need the source to calculate a name's value. Up and Down move the selection, Enter or a double click edits the selected name.
21
+
22
+ - New… opens the New Name dialog, Edit… the Edit Name dialog for the selected name (the same fields, with Scope fixed, as Excel's Edit Name has it), and Delete removes it after Excel's question.
23
+ - Refers to at the bottom shows the selected name's formula. Editing it enables Commit (the check mark), which replaces the formula, and Cancel (the cross), which restores it; Enter and Esc in the box do the same. Closing with an edit not committed asks whether to save it, as Excel does.
24
+ - A refusal is shown in Excel's alert with the source's message; the edit stays for fixing.
25
+ - Without `setNames`, or on a read-only sheet, it only lists the names.
26
+ - It is not opened while a cell is being edited (`nameManager()` returns false), nor without the source's `names`.
27
+
28
+ ## Formula AutoComplete
29
+
30
+ Formula AutoComplete lists the names visible on the active sheet together with the functions ([autocomplete.md](autocomplete.md)), as Excel lists defined names: the names that begin with the typed text, merged in among the functions in alphabetical order (a name spelt as a function follows it), each with a tag icon where a function has fx. Tab or a double click inserts a name without a parenthesis. Names are offered without the source's `functionNames` too.
31
+
32
+ ## When the names are read
33
+
34
+ The sheet reads the names once per source, when the workbook loads, and again after each change: after `setNames` (with the sheet, whose formulas may now calculate differently, unless the source sent `reload` meanwhile), after an undo or a redo, and on a `reload` event. The list stays until the new one arrives, and an earlier request's answer is dropped. The Name Box, the Name Manager and AutoComplete all use this one list (`useNames` in `src/core/names.ts`, `names` of the sheet's context).
35
+
36
+ ## Sources
37
+
38
+ `memorySource` keeps a workbook's `names` as text and checks a name as Excel checks one, without calculating it. `./local` returns its session's names with their formulas translated into the workbook's locale, and parses the formulas of `setNames` in it, refusing one that does not parse; the sheet is read again after a change, since a name changes the values of formulas anywhere.
39
+
40
+ ```vue
41
+ <script setup lang="ts">
42
+ import { ref } from 'vue'
43
+ import { SheetView, memorySource, type SheetViewApi } from '@xlcalc/vue'
44
+ import '@xlcalc/vue/style.css'
45
+
46
+ const source = memorySource({
47
+ sheets: [{ name: 'Sheet1', cells: { A1: 'Rent', B1: 1200, A2: 'Food', B2: 400 } }],
48
+ names: [{ name: 'Costs', ref: 'Sheet1!$B$1:$B$2' }, { name: 'Rate', ref: '0.2' }],
49
+ })
50
+ const sheet = ref<SheetViewApi | null>(null)
51
+ </script>
52
+
53
+ <template>
54
+ <button @click="sheet?.defineName()">Define Name…</button>
55
+ <button @click="sheet?.nameManager()">Name Manager</button>
56
+ <SheetView ref="sheet" :source="source" style="height: 300px" />
57
+ </template>
58
+ ```
59
+
60
+ Type `Costs` into the Name Box and press Enter, or select A1:A2 and type `Items` there to define a name.
61
+
62
+ The texts are `SheetMessages`' `nameBoxList`, `nameBoxBad`, `nameNotRange`, `menuDefineName`, `nameItem`, `nameNewTitle`, `nameEditTitle`, `nameLabel`, `nameScope`, `nameRefersTo`, `nameWorkbook`, `nameManager`, `nameNew`, `nameEdit`, `nameDelete`, `nameColumn`, `nameCommit`, `nameDeleteAsk` and `nameSaveAsk`, with `ok`, `cancel`, `close`, `validationYes`, `validationNo` and `validationTitle` (the alert's title).
package/docs/tables.md ADDED
@@ -0,0 +1,40 @@
1
+ # Tables
2
+
3
+ If the source has `table(op)` and the sheet is editable, Ctrl+T and Ctrl+L, Excel's keys for Create Table, open its dialog, and so does the sheet's `insertTable()` method, which a host's Insert Table or Format as Table button calls. On a Mac it is Control+T, since the browser keeps Cmd+T, and Control+L stays Excel for Mac's Define Name ([names.md](names.md)); some browsers keep Ctrl+T for a new tab (Chrome on Windows and Linux), and Ctrl+L or the method works there.
4
+
5
+ The dialog proposes the selection when it has more than one cell (clipped to the data), otherwise the active cell's current region, as Excel's Range.CurrentRegion finds it: the range grown while a row or column next to it, corners included, has a non-empty cell. The range is shown as Excel shows it, `=$A$1:$C$5`, and can be typed with or without `$` and `=`, with the sheet's own name or without one; a range Excel would not take keeps the dialog open with its message. My table has headers is checked when the first row holds text in every column above at least one more row.
6
+
7
+ OK creates the table through `table({ op: 'addTable', sheet, table })`, named `Table1`, `Table2` and so on: the first number from the count of the workbook's tables on that no table and no defined name has (the word is `tableNamePrefix`, `Таблица` in Russian). With headers, the columns are named after the header cells' text: a number or a date as displayed, an empty header `Column1` (the first number no other column uses), and a name a column to the left already has gets the next free number (`Qty`, `Qty2`), compared case-insensitively, as Excel names them. Without headers, Excel puts a header row of `Column1`, `Column2`… above the data: the sheet first moves the cells from the range's first row down by one row in the range's columns through `structure` (`moveRange`), then adds the table over the range one row taller, so this takes two undo steps where Excel takes one. Without `structure` the box stays checked. The table is drawn with the sheet's table colors (`--xs-table-head-bg`, `--xs-table-line`); the library's table style and Excel's gallery of styles are not offered yet.
8
+
9
+ `convertToRange()` is Excel's Convert to Range on the table at the active cell: after Excel's question, Yes sends `convertTable` and the cells keep their contents. `deleteTable()` deletes the table at the active cell with its cells (`deleteTable`). Both resolve to `null` when there is no table at the active cell, the source has no `table`, or the answer is No. `./local` implements `table` with xlcalc's table operations; `memorySource` has none.
10
+
11
+ ```vue
12
+ <script setup lang="ts">
13
+ import { onUnmounted, ref } from 'vue'
14
+ import { SheetView, type SheetViewApi } from '@xlcalc/vue'
15
+ import { localSource } from '@xlcalc/vue/local'
16
+ import '@xlcalc/vue/style.css'
17
+
18
+ const source = localSource({
19
+ sheets: [
20
+ {
21
+ name: 'Orders',
22
+ cells: {
23
+ A1: { value: 'Item' }, B1: { value: 'Qty' }, C1: { value: 'Qty' },
24
+ A2: { value: 'Pens' }, B2: { value: 10 }, C2: { value: 12 },
25
+ A3: { value: 'Paper' }, B3: { value: 3 }, C3: { value: 5 },
26
+ },
27
+ },
28
+ ],
29
+ })
30
+ onUnmounted(() => void source.close())
31
+ const sheet = ref<SheetViewApi | null>(null)
32
+ </script>
33
+
34
+ <template>
35
+ <!-- Insert Table proposes =$A$1:$C$3 with headers, and names the columns Item, Qty, Qty2 -->
36
+ <button @click="sheet?.insertTable()">Insert table</button>
37
+ <button @click="sheet?.convertToRange()">Convert to range</button>
38
+ <SheetView ref="sheet" :source="source" :locale="source.locale" style="height: 360px" />
39
+ </template>
40
+ ```
package/docs/toolbar.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## `SheetToolbar`
4
4
 
5
- `SheetToolbar` is Excel's formatting toolbar over the same source: Undo and Redo, Bold, Italic, Underline, font and fill colors from Excel's palette, borders (All Borders, Outside Borders, Bottom Border, No Border), horizontal alignment, Wrap Text, Excel's Number Format box and, for a host that displays the dialog ([below](#formatdialog)), Format Cells. It formats the selection reported by the sheet's `state` event through `format(sheet, patches)`, as Excel formats a selection: Bold applies on top of each cell's formatting, and Outside Borders is four patches in one call and therefore a single undo step. Its buttons show as pressed according to the active cell's formatting, and clicking a pressed button removes that formatting, as in Excel. The toolbar is shown only when the source has `format`; Undo and Redo appear when the source has `undo` and `redo`, and are disabled while its `history` (the local source's) has no steps.
5
+ `SheetToolbar` is Excel's formatting toolbar over the same source: Undo and Redo, the Font and Font Size boxes with Increase and Decrease Font Size, Bold, Italic, Underline, font and fill colors from Excel's palette, borders (All Borders, Outside Borders, Bottom Border, No Border), Top, Middle and Bottom Align, horizontal alignment, Decrease and Increase Indent, Wrap Text, Excel's Number Format box with Accounting Number Format, Percent Style, Comma Style, Increase Decimal and Decrease Decimal and, for a host that displays the dialog ([below](#formatdialog)), Format Cells. It formats the selection reported by the sheet's `state` event through `format(sheet, patches)`, as Excel formats a selection: Bold applies on top of each cell's formatting, and Outside Borders is four patches in one call and therefore a single undo step. Its buttons show as pressed according to the active cell's formatting, and clicking a pressed button removes that formatting, as in Excel. The toolbar is shown only when the source has `format`; Undo and Redo appear when the source has `undo` and `redo`, and are disabled while its `history` (the local source's) has no steps.
6
6
 
7
7
  With `sheet` and the source's `structure`, the toolbar has Excel's Merge & Center: the button merges the selection and centers its contents, and its dropdown has Merge & Center, Merge Across, Merge Cells and Unmerge Cells, each a single undo step through the sheet's `merge(command)`. The button shows as pressed on a merged cell, and clicking it then unmerges, as Excel's does; on a single cell outside a merged range it does nothing, and it is disabled on a read-only sheet and under a display filter. Before a merge that would keep only one of several values in a range (in a row, for Merge Across), the sheet shows Excel's warning "Merging cells only keeps the upper-left value and discards other values.", with OK on Enter and Cancel on Esc; it counts the cells that contain a value or a formula in its loaded windows, or in the source's windows over the range when the loaded ones do not cover it. If the source rejects the merge, its message is displayed.
8
8
 
@@ -29,7 +29,11 @@ const sheet = ref<SheetViewApi | null>(null)
29
29
  </template>
30
30
  ```
31
31
 
32
- The Number Format box works as Excel's does, as measured by xlcalc (`numberFormatCategory` and `numberFormatChoices` of `xlcalc/text`, without the engine): it shows the category of the active cell's format (General if there is none, Custom where no Excel category matches the code), and its list applies Excel's eleven items (General, Number, Currency, Accounting, Short Date, Long Date, Time, Percentage, Fraction, Scientific, Text), each with the format Excel sets (Percentage is `0.00%`), after which the box shows the new category. `locale` is the workbook's locale, as for `SheetView`: the category names and the Currency item's code follow it, with ru-RU's data loaded as a separate chunk; without it, en-US. With `sheet` (the sheet's template ref), the toolbar formats, undoes and redoes through the sheet's methods ([api.md](api.md#sheetviewapi)), and the sheet sets the selection and displays a rejection itself. Without it, the toolbar calls the source and emits `select` with where the selection goes after an undo or a redo (for the sheet's `focus`) and `error` with the source's rejection. It emits `done` after each call, so the host can return focus to the grid. Its buttons do not take focus from the grid. Below 600 px it keeps Undo, Redo, Bold, Italic and Underline in a row and moves the rest into a menu; in a narrow viewport or on a touch screen every target is 44 × 44 px.
32
+ The Font and Font Size boxes show the active cell's font and size, and each takes a typed value or a pick from its list: Enter or a pick applies it to the selection, and Esc, or leaving the box without Enter, restores what it showed (Esc also emits `done`, so the host can return focus to the grid). A cell without its own font or size shows the workbook's default font (`state.font`, from the source's `SheetInfo.font`), and empty boxes when the source does not give one. A browser does not tell which fonts are installed, so the Font box's list is Excel's common fonts (Aptos, Aptos Narrow, Arial, Calibri, Cambria, Consolas, Courier New, Georgia, Segoe UI, Tahoma, Times New Roman, Verdana), each drawn in its own font, and the `fonts` prop replaces it; any name may be typed, and typing completes it with the first font of the list it begins, as Excel's box does. The Font Size box's list is Excel's (8 to 72), and it takes any size from 1 to 409, with a decimal point or comma, rounded to half points (Excel takes sizes in multiples of .5); any other text stays in the box, marked invalid with the message `fmtSizeRange`, until it is corrected or Esc restores the box. The arrows go through the list, putting each item into the box.
33
+
34
+ Increase and Decrease Font Size step the active cell's size (11 points for a cell without one, the size the grid draws it at) through Excel's list, beyond 72 in steps of 10 up to 409, and below 8 a point at a time down to 1, and set the new size over the selection; at a limit they send nothing. Top, Middle and Bottom Align show as pressed according to the active cell's vertical alignment, Bottom for a cell without one (Excel's default); clicking a pressed one returns the selection to Bottom. Increase Indent adds a level to the active cell's indent and keeps the Left, Right and Distributed alignments, which have an indent, while any other alignment (General, Center and the rest) becomes Left, as in Excel; Decrease Indent takes a level off without changing the alignment, and does nothing at 0 or with an alignment that has no indent. Indents go up to 250 levels. Percent Style sets Excel's `0%` (the built-in format 9) over the selection, as Ctrl+Shift+% on the grid does ([editing.md](editing.md)); the Number Format box then names Percentage. Accounting Number Format and Comma Style set Excel's built-in formats 44 and 43, which display in the workbook's locale (its currency for Accounting). Increase Decimal and Decrease Decimal take the active cell's format, value and column width (`state.numberFormat`, `cellValue`, `columnWidth`) through xlcalc's `stepDecimals`, as Excel for Mac steps them (a General cell takes the decimals it shows, one more or one less; a code takes a decimal in each section), and put the result on the whole selection, as Excel does; when the step changes nothing (General without a number, no decimal to take away) nothing is sent.
35
+
36
+ The Number Format box works as Excel's does, as measured by xlcalc (`numberFormatCategory` and `numberFormatChoices` of `xlcalc/text`, without the engine): it shows the category of the active cell's format (General if there is none, Custom where no Excel category matches the code), and its list applies Excel's eleven items (General, Number, Currency, Accounting, Short Date, Long Date, Time, Percentage, Fraction, Scientific, Text), each with the format Excel sets (Percentage is `0.00%`), after which the box shows the new category. `locale` is the workbook's locale, as for `SheetView`: the category names and the Currency item's code follow it, with ru-RU's data loaded as a separate chunk; without it, en-US. With `sheet` (the sheet's template ref), the toolbar formats, undoes and redoes through the sheet's methods ([api.md](api.md#sheetviewapi)), and the sheet sets the selection and displays a rejection itself. Without it, the toolbar calls the source and emits `select` with where the selection goes after an undo or a redo (for the sheet's `focus`) and `error` with the source's rejection. It emits `done` after each call, so the host can return focus to the grid. Its buttons do not take focus from the grid; the font boxes and the Number Format box do, while they are used. Below 600 px it keeps Undo, Redo, Bold, Italic and Underline in a row and moves the rest, the font boxes too, into a menu; in a narrow viewport or on a touch screen every target is 44 × 44 px.
33
37
 
34
38
  ## `FormatDialog`
35
39
 
@@ -39,3 +39,50 @@ These parts look and behave like Excel's. `useValidation` (`src/core/validation.
39
39
  `ValidationDropdown` is the arrow at the bottom right of the active cell, and the list below the cell, as wide as the cell and its arrow, or above the cell where the viewport has no room below. `ValidationPrompt` is the input message: a pale yellow box below the cell starting from its middle, shifted left or placed over the cell where the viewport ends. `ValidationAlert` is the alert with its style's icon and buttons: Stop has Retry and Cancel; Warning has the rule's message, "Continue?" and Yes, No and Cancel; Information has OK and Cancel. It opens with Excel's default button focused (Retry, No, OK), and Esc means Cancel. Yes and OK keep the value, Retry and No reopen the cell editor with the typed text, and Cancel leaves the cell unchanged. On a touch screen the arrow and the list items are 44 px, and on a phone so are the alert's buttons. Their texts come from `SheetMessages` (`validationList`, `validationTitle`, `retry`, `validationYes`, `validationNo`, `validationContinue`, `validationStyle`, with `ok` and `cancel`), and their colors from the `--xs-prompt-*` and `--xs-alert-*` variables.
40
40
 
41
41
  `SheetView` mounts these parts: the arrow and the input message next to the active cell when the source has `validation`, and the alert when an edit or a Ctrl+Enter is rejected with `alert`. A chosen item is written through the source's `pick(sheet, cell, item, text)`, by its position in the list and its text, and the source writes it as Excel writes a picked item: the item's value, not parsed as typed text (a list cell containing the text `001` gives `001`, one displaying `50%` gives the number 0.5), keeping the cell's number format and without checking the rule. A source without `pick` (`memorySource`) receives the item's text through `edit` with `accept`. While the alert is open, the edited cell stays active and displays the typed text as pending.
42
+
43
+ ## The Data Validation dialog
44
+
45
+ `SheetViewApi.dataValidation()` opens Excel's Data Validation dialog (Data > Data Validation) for the selection, for a host's ribbon or menu: Excel's cell context menu has no entry for it, so the sheet adds none. It needs the source's `rules` and `setRules` and an editable sheet, and returns `false` otherwise. `memorySource` has neither method; `./local` has both.
46
+
47
+ ```vue
48
+ <script setup lang="ts">
49
+ import { onUnmounted, ref } from 'vue'
50
+ import { SheetView, type SheetViewApi } from '@xlcalc/vue'
51
+ import { localSource } from '@xlcalc/vue/local'
52
+ import '@xlcalc/vue/style.css'
53
+
54
+ const source = localSource({
55
+ sheets: [
56
+ {
57
+ name: 'Tasks',
58
+ cells: { A1: { value: 'Status' }, D1: { value: 'Statuses' }, D2: { value: 'Open' }, D3: { value: 'On hold' }, D4: { value: 'Closed' } },
59
+ validations: [{ range: 'A2:A20', type: 'list', formula1: '$D$2:$D$4' }],
60
+ },
61
+ ],
62
+ })
63
+ onUnmounted(() => void source.close())
64
+ const sheet = ref<SheetViewApi | null>(null)
65
+ </script>
66
+
67
+ <template>
68
+ <button @click="sheet?.dataValidation()">Data Validation…</button>
69
+ <SheetView ref="sheet" :source="source" :locale="source.locale" style="height: 300px" />
70
+ </template>
71
+ ```
72
+
73
+ When it opens, the sheet reads the sheet's rules from `rules` and looks at the selection as Excel does:
74
+
75
+ - no rule in the selection: the dialog opens with Excel's defaults (Any value);
76
+ - one rule's settings over every cell: the dialog opens with them;
77
+ - the same settings over some cells only: Excel's question "The selection contains some cells without Data Validation settings. Do you want to extend Data Validation to these cells?", where Yes opens the dialog with those settings for the whole selection, No opens it with the defaults, and Cancel opens nothing;
78
+ - rules of more than one kind: "The selection contains more than one type of validation. Erase current settings and continue?", where OK opens the dialog with the defaults and Cancel opens nothing.
79
+
80
+ Rules count as one kind when every setting is the same, their formulas compared as written for their own cells.
81
+
82
+ The dialog has Excel's three tabs. Settings has Allow (Any value, Whole number, Decimal, List, Date, Time, Text length, Custom), Data with Excel's eight comparisons, the boxes the type and the comparison call for (Minimum and Maximum, Value, Length, Start date and End date, Start time and End time, Source, Formula), Ignore blank, In-cell dropdown for a list, and "Apply these changes to all other cells with the same settings", offered when the dialog opened with a rule's settings. Input Message has its check box, Title (32 characters, as Excel allows) and Input message (255); Error Alert has its check box, Style (Stop, Warning, Information), Title (32) and Error message (225). Clear All returns every tab to the defaults and leaves the dialog open, so OK then removes the rule from the selection.
83
+
84
+ The boxes show a rule's formulas in the source's locale, with `=`, written for the active cell (a rule `B2>A2` over B2:B9 shows `=B5>A5` with B5 active); a number shows as it is (`10`, `1,5` in ru-RU), a date or time bound in the locale's short date or time (`1/1/2025`, `01.01.2025`, `9:00:00 AM`), and a literal list with the locale's list separator: `Open,On hold,Closed` in en-US and `Open;On hold;Closed` in ru-RU. OK reads the boxes as Excel reads them: `=` starts a formula, and anything else is read as typed into a cell (`xlcalc/entry`), so a bound must be a number, a date or a time, and a list typed with the locale's separator is stored with commas, as a file stores it in every locale (`"Open,On hold,Closed"`). Before writing, OK refuses an empty box ("You must enter a value in the Source box."), a bound that is not a value ("The Minimum you entered is not valid.") and a maximum below the minimum ("The Maximum must be greater than or equal to the Minimum."), on the Settings tab, and leaves the dialog open.
85
+
86
+ OK writes the sheet's whole list of data validation rules in one `setRules` call: the new rule over the selection (or none for Any value without an input message or alert text), with "Apply these changes to all other cells with the same settings" over every cell with the settings the dialog opened with too. A rule the selection covers only part of keeps its other cells, with its formulas written again for the top-left cell of what remains, as a rule's formulas are relative to that cell. When the source refuses (a formula that does not parse), the dialog stays open with its message. After the call the sheet re-reads the windows over the changed cells and requests the active cell's rule again, so its dropdown and input message follow at once. The texts are the `SheetMessages` keys `dataValidation` and those starting with `dv`, with the style names of `validationStyle`.
87
+
88
+ Circle Invalid Data and Clear Validation Circles are not offered: they need each cell's value checked against its rule, and the source contract has no such check (`validation` returns a cell's dropdown and input message, and an edit is checked only as it is written). Excel's warning "The Source currently evaluates to an error" before OK is not given either, since the sheet cannot calculate the list's formula; the source's own check of the formula applies.
package/docs/view.md CHANGED
@@ -1,4 +1,4 @@
1
- # Freeze Panes, Reapply and Trace Precedents
1
+ # Freeze Panes, zoom, Watch Window, Reapply, Show Formulas, Trace Precedents and Trace Dependents
2
2
 
3
3
  ## Reapply
4
4
 
@@ -43,8 +43,111 @@ const sheet = ref<SheetViewApi | null>(null)
43
43
  </template>
44
44
  ```
45
45
 
46
+ ## Show Formulas
47
+
48
+ Ctrl+` (Control+` on a Mac too, as in Excel for Mac; the key left of 1, with any keyboard layout) is Excel's Show Formulas, and pressing it again shows the values. The sheet's methods do the same for a host's button: `showFormulas()` toggles it, `showFormulas(true)` and `showFormulas(false)` set it, and the `state` event's `showFormulas` tells whether it is on, so the button can stay pressed. While it is on, every cell with a formula shows its formula as the window gives it, in the source's locale, with `=` (`=SUM(B2:B9)`, `=СУММ(B2:B9)`), aligned as text (left unless the cell's own alignment says otherwise) and overflowing into empty neighbors as text does. A constant is shown without its number format: a number as the formula bar writes it in General, in the workbook's locale (a date as its serial number, `45688`; `1234.5` for `1,234.50`), through `entryText` of `xlcalc/entry`, a separate chunk that loads when the view is first turned on; text as stored; a boolean or an error as displayed. The number format's color is not applied. Columns are drawn twice as wide, as Excel draws them in this view, while the workbook's widths stay as they are: a width dragged with the mouse meanwhile is stored as half the drawn one, and with the view off the column is drawn at that stored width.
49
+
50
+ As in Excel, it is a setting of each sheet: another sheet shows its values until it gets its own, and a sheet displayed again keeps its setting. The source has no place for it, so the sheet keeps it as it keeps the frozen panes choice, in the browser's storage under `storageKey` (otherwise for the component's lifetime). Editing works as before: F2 opens the cell's own text, and an entry shows as its formula once it is in. The selection's formula ranges are highlighted on the grid in this view as in the other.
51
+ ## Zoom
52
+
53
+ The sheet is drawn at Excel's zoom, from 10% to 400%, and each sheet keeps its own, as each of Excel's sheet views does. Everything in the grid scales together: cells, fonts, borders, row numbers and column letters, frozen panes, the selection, the editor and the boxes over cells (a validation list, its input message). The Formula AutoComplete list and the argument tooltip keep their size, as in Excel, and so does the fill handle, so it can still be grabbed zoomed out. Gridlines and thin borders stay one screen pixel wide when zoomed out. Zoom changes only the view: column widths and row heights stay as the workbook has them, and nothing is sent to the source.
54
+
55
+ The zoom changes by:
56
+
57
+ - Ctrl+wheel over the grid (on a Mac too): each notch zooms in or out by 15%. A trackpad's pinch, which the browser sends as Ctrl+wheel (Safari as its gesture events), zooms in proportion to the gesture about the pointer.
58
+ - Two fingers on a touch screen: the sheet zooms about their middle, and the page itself does not.
59
+ - The status bar, at the right end of the bottom bar on a desktop: Zoom Out (−) and Zoom In (+) go to the next multiple of 10%; the slider covers 10% to 100% on its left half and 100% to 400% on its right, with 100% at the middle; the percentage opens Excel's Zoom dialog.
60
+ - The Zoom dialog: 200%, 100%, 75%, 50%, 25%, Fit selection and Custom (10 to 400). Fit selection is Excel's Zoom to Selection: the zoom at which the selection fills the viewport, with the selection scrolled to its top left corner.
61
+
62
+ The wheel, the slider and the dialog keep the top left cell in place; a pinch keeps the cell under it. A host sets a sheet's zoom with `setZoom(percent)`, or Zoom to Selection with `setZoom('selection')`, and opens a sheet at its zoom with the `zoom` prop, keyed by sheet name; a sheet the prop does not name opens at the workbook's saved zoom (`SheetInfo.zoom`, which `./local` reads from the xlsx sheet view), otherwise at 100%. The `zoom` event reports what the user changes (a pinch once it ends), so the host can keep it and pass it back; `state.zoom` is the displayed sheet's zoom, absent at 100%.
63
+
64
+ ```vue
65
+ <script setup lang="ts">
66
+ import { ref } from 'vue'
67
+ import { SheetView, memorySource, type SheetViewApi, type SheetZoomEvent } from '@xlcalc/vue'
68
+ import '@xlcalc/vue/style.css'
69
+
70
+ const source = memorySource({ sheets: [{ name: 'Budget', cells: { A1: 'Item', B1: 'Price', A2: 'Desks', B2: 250 } }] })
71
+ const sheet = ref<SheetViewApi | null>(null)
72
+ // The zoom by sheet as the user left it, to open the sheets at it again
73
+ const zooms = ref<Record<string, number>>({ Budget: 150 })
74
+ const onZoom = (e: SheetZoomEvent) => (zooms.value = { ...zooms.value, [e.sheet]: e.zoom })
75
+ </script>
76
+
77
+ <template>
78
+ <button @click="sheet?.setZoom(100)">100%</button>
79
+ <button @click="sheet?.setZoom('selection')">Zoom to selection</button>
80
+ <SheetView ref="sheet" :source="source" :zoom="zooms" style="height: 360px" @zoom="onZoom" />
81
+ </template>
82
+ ```
83
+
84
+ The grid's content is drawn under CSS `zoom`, which current Chrome, Safari and Firefox support as standardized: its geometry stays in the workbook's pixels, and the pointer's page coordinates are divided by the zoom where the sheet finds the cell under the pointer itself (a drag of the fill handle, a range pointed at in a formula, a column edge).
85
+
86
+ ## Watch Window
87
+
88
+ Excel's Watch Window lists cells whose values stay in view whatever sheet is displayed. The host opens it with `watchWindow()` (and closes it with `watchWindow(false)`); it floats over the sheet within the component's box, at its top right corner (over the lower part of the grid on a phone), is moved by its title bar, resized by its corner, and closed by its close button.
89
+
90
+ Add Watch adds each cell of the selection, by rows, that is not watched yet, since Excel has one watch per cell; at most 1,000 cells are watched. The list has Excel's columns: Book, Sheet, Name, Cell, Value (the displayed value) and Formula (with `=`, in the source's locale). Book and Name stay empty: the sheet does not know the workbook's name, and does not look up a defined name for a watched cell. A click chooses a row, Ctrl+click (Cmd+click on a Mac) adds a row to the chosen ones or takes it out, Shift+click chooses the rows from the last one clicked, and the arrow keys move the choice. Delete Watch, or Delete, removes the chosen rows. A double click on a row, or Enter, goes to its cell, on its sheet.
91
+
92
+ The values are read through the source's `window`, one window over each sheet's watched cells (a window per cell when that would exceed `maxCells`), only while the window is open. They are read again when cells change (an edit's outcome, a `changed` event), when the sheets are read again (a `reload` event, a structure change) and when the list changes; a workbook being recalculated is asked again a second later. The `watches` event reports the list after each Add Watch or Delete Watch, and the `watches` prop replaces it, so the host keeps the list as view state.
93
+
94
+ ```vue
95
+ <script setup lang="ts">
96
+ import { ref } from 'vue'
97
+ import { SheetView, memorySource, type SheetViewApi, type SheetWatch } from '@xlcalc/vue'
98
+ import '@xlcalc/vue/style.css'
99
+
100
+ const source = memorySource({
101
+ sheets: [
102
+ { name: 'Summary', cells: { A1: 'Total', B1: { value: 60, formula: 'SUM(Data!B1:B3)' } } },
103
+ { name: 'Data', cells: { B1: 10, B2: 20, B3: 30 } },
104
+ ],
105
+ })
106
+ const sheet = ref<SheetViewApi | null>(null)
107
+ const watches = ref<SheetWatch[]>([{ sheet: 'Summary', cell: 'B1' }])
108
+ </script>
109
+
110
+ <template>
111
+ <button @click="sheet?.watchWindow()">Watch Window</button>
112
+ <SheetView ref="sheet" :source="source" :watches="watches" style="height: 360px" @watches="watches = $event" />
113
+ </template>
114
+ ```
115
+
46
116
  ## Trace Precedents
47
117
 
48
118
  If the source has `explain(sheet, cell)`, the context menu has Trace Precedents. Instead of drawing arrows as Excel does, the sheet opens a panel to the right of the grid (below it on a phone) with the source's tree of the active cell's precedents. While open, the panel follows the active cell: it requests the tree again 150 ms after the active cell stops moving or its value changes, and when the source reports changes. Since `explain` takes no abort signal, a response that arrives after a newer request is discarded.
49
119
 
50
120
  Each line is a node, and each two-space indent is one level deeper, as in the text of xlcalc's `explain` (`'Q 4'!A2 = 60 ← Data!A4*2`). References in it to cells, columns or rows on a single sheet are links; a reference without a sheet name refers to the sheet of its line's node. Clicking a link selects its range, like Ctrl+click on a reference in the formula bar, and the panel then shows the precedents of that cell. The close button (✕) and Esc close the panel. `./local` returns the session's `explain` in the workbook's locale, and `memorySource` builds a tree from the formulas as given, with xlcalc's English wording. The panel's width, and its height on a phone, are `--xs-explain-w` (340 px) and `--xs-explain-h` (45 %).
121
+
122
+ ## Trace Dependents
123
+
124
+ If the source has `dependents(sheet, range)`, the sheet's `traceDependents()` method draws Excel's tracer arrows from the active cell to the cells whose formulas refer to it directly: a dot in the traced cell, a blue line and an arrowhead at each dependent on the same sheet, a red one from a cell whose value is an error, and a dashed black line to a worksheet icon next to the cell when formulas on other sheets refer to it (one icon for all of them, as in Excel). Each further call adds the next level: the dependents of the cells the arrows already reach whose own dependents are not drawn yet. When there is no further level, nothing is added and the method returns `false`; on a cell no formula refers to it also shows Excel's message. A call traces at most 200 cells; what the source leaves out of its response (`more`) is not drawn.
125
+
126
+ The arrows are drawn in a layer over the cells that scrolls with the grid. An arrow between cells of the scrolling part goes under the frozen panes and the headers, and one with an end in the frozen panes goes over them and follows them, clipped to the cells' area. Each sheet keeps its own arrows. `removeArrows()` is Excel's Remove Arrows and removes every arrow; as in Excel, any change of cells from the sheet (an edit, a paste, a cleared range, a structure operation such as inserting rows) removes them too, and formatting does not. Like Excel, the sheet traces from the active cell, not from each cell of a selected range. The colors are `--xs-trace`, `--xs-trace-error` and `--xs-trace-sheet`.
127
+
128
+ Excel's Trace Dependents is a ribbon command without a key, and its cell context menu has no such item, so the sheet offers it through the method for a host's own button. `./local` answers `dependents` from the session's dependency graph; `memorySource` has no engine and no `dependents`.
129
+
130
+ ```vue
131
+ <script setup lang="ts">
132
+ import { onUnmounted, ref } from 'vue'
133
+ import { SheetView, type SheetViewApi } from '@xlcalc/vue'
134
+ import { localSource } from '@xlcalc/vue/local'
135
+ import '@xlcalc/vue/style.css'
136
+
137
+ const source = localSource({
138
+ sheets: [
139
+ { name: 'Rates', cells: { A1: { value: 'Rate' }, B1: { value: 0.2 }, A2: { value: 'Base' }, B2: { value: 100 }, A3: { value: 'Tax' }, B3: { formula: 'B1*B2' }, A4: { value: 'Total' }, B4: { formula: 'B2+B3' } } },
140
+ { name: 'Report', cells: { A1: { value: 'Tax' }, B1: { formula: 'Rates!B3' } } },
141
+ ],
142
+ })
143
+ onUnmounted(() => void source.close())
144
+ const sheet = ref<SheetViewApi | null>(null)
145
+ </script>
146
+
147
+ <template>
148
+ <!-- select B1, then click twice: B3, then B4 and the icon for Report -->
149
+ <button @click="sheet?.traceDependents()">Trace dependents</button>
150
+ <button @click="sheet?.removeArrows()">Remove arrows</button>
151
+ <SheetView ref="sheet" :source="source" :locale="source.locale" style="height: 360px" />
152
+ </template>
153
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xlcalc/vue",
3
- "version": "0.21.2",
3
+ "version": "0.23.1",
4
4
  "description": "Vue 3 sheet component for xlcalc workbooks: a windowed grid with styles, formulas and editing over a pluggable sheet source",
5
5
  "keywords": [
6
6
  "vue",
@@ -89,6 +89,6 @@
89
89
  "vitest": "^4.1.10",
90
90
  "vue": "^3.5.39",
91
91
  "vue-tsc": "^3.3.5",
92
- "xlcalc": "^0.54.2"
92
+ "xlcalc": "^0.59.0"
93
93
  }
94
94
  }