@dou-ui/sheet 0.0.0-stage → 0.1.0-alpha.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 (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/dist/cell-types.js +20 -0
  4. package/dist/cell-types.js.map +1 -0
  5. package/dist/code/code-formula-bar.js +6 -0
  6. package/dist/code/code-formula-bar.js.map +1 -0
  7. package/dist/code/code-formula-bar.vue_vue_type_script_setup_true_lang.js +192 -0
  8. package/dist/code/code-formula-bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  9. package/dist/code/index.js +12 -0
  10. package/dist/code/index.js.map +1 -0
  11. package/dist/code/language.js +51 -0
  12. package/dist/code/language.js.map +1 -0
  13. package/dist/code/style.d.ts +1 -0
  14. package/dist/code/style.js +2 -0
  15. package/dist/collaboration/anchor.js +143 -0
  16. package/dist/collaboration/anchor.js.map +1 -0
  17. package/dist/collaboration/index.js +770 -0
  18. package/dist/collaboration/index.js.map +1 -0
  19. package/dist/collaboration/peers.js +87 -0
  20. package/dist/collaboration/peers.js.map +1 -0
  21. package/dist/collaboration/shared.js +450 -0
  22. package/dist/collaboration/shared.js.map +1 -0
  23. package/dist/components/cell-panel.js +6 -0
  24. package/dist/components/cell-panel.js.map +1 -0
  25. package/dist/components/cell-panel.vue_vue_type_script_setup_true_lang.js +70 -0
  26. package/dist/components/cell-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  27. package/dist/components/cell-renders.js +40 -0
  28. package/dist/components/cell-renders.js.map +1 -0
  29. package/dist/components/date-panel.js +6 -0
  30. package/dist/components/date-panel.js.map +1 -0
  31. package/dist/components/date-panel.vue_vue_type_script_setup_true_lang.js +48 -0
  32. package/dist/components/date-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  33. package/dist/components/filter-panel.js +6 -0
  34. package/dist/components/filter-panel.js.map +1 -0
  35. package/dist/components/filter-panel.vue_vue_type_script_setup_true_lang.js +259 -0
  36. package/dist/components/filter-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  37. package/dist/components/format-dialog.js +6 -0
  38. package/dist/components/format-dialog.js.map +1 -0
  39. package/dist/components/format-dialog.vue_vue_type_script_setup_true_lang.js +432 -0
  40. package/dist/components/format-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  41. package/dist/components/format-list.js +6 -0
  42. package/dist/components/format-list.js.map +1 -0
  43. package/dist/components/format-list.vue_vue_type_script_setup_true_lang.js +187 -0
  44. package/dist/components/format-list.vue_vue_type_script_setup_true_lang.js.map +1 -0
  45. package/dist/components/format-presets.js +97 -0
  46. package/dist/components/format-presets.js.map +1 -0
  47. package/dist/components/option-panel.js +6 -0
  48. package/dist/components/option-panel.js.map +1 -0
  49. package/dist/components/option-panel.vue_vue_type_script_setup_true_lang.js +117 -0
  50. package/dist/components/option-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  51. package/dist/components/sheet-comment.js +6 -0
  52. package/dist/components/sheet-comment.js.map +1 -0
  53. package/dist/components/sheet-comment.vue_vue_type_script_setup_true_lang.js +104 -0
  54. package/dist/components/sheet-comment.vue_vue_type_script_setup_true_lang.js.map +1 -0
  55. package/dist/components/sheet-formula-bar.js +6 -0
  56. package/dist/components/sheet-formula-bar.js.map +1 -0
  57. package/dist/components/sheet-formula-bar.vue_vue_type_script_setup_true_lang.js +124 -0
  58. package/dist/components/sheet-formula-bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  59. package/dist/components/sheet-link.js +6 -0
  60. package/dist/components/sheet-link.js.map +1 -0
  61. package/dist/components/sheet-link.vue_vue_type_script_setup_true_lang.js +249 -0
  62. package/dist/components/sheet-link.vue_vue_type_script_setup_true_lang.js.map +1 -0
  63. package/dist/components/sheet-menu.js +6 -0
  64. package/dist/components/sheet-menu.js.map +1 -0
  65. package/dist/components/sheet-menu.vue_vue_type_script_setup_true_lang.js +115 -0
  66. package/dist/components/sheet-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
  67. package/dist/components/sheet-name-box.js +6 -0
  68. package/dist/components/sheet-name-box.js.map +1 -0
  69. package/dist/components/sheet-name-box.vue_vue_type_script_setup_true_lang.js +91 -0
  70. package/dist/components/sheet-name-box.vue_vue_type_script_setup_true_lang.js.map +1 -0
  71. package/dist/components/sheet-note.js +6 -0
  72. package/dist/components/sheet-note.js.map +1 -0
  73. package/dist/components/sheet-note.vue_vue_type_script_setup_true_lang.js +146 -0
  74. package/dist/components/sheet-note.vue_vue_type_script_setup_true_lang.js.map +1 -0
  75. package/dist/components/sheet-outline.js +6 -0
  76. package/dist/components/sheet-outline.js.map +1 -0
  77. package/dist/components/sheet-outline.vue_vue_type_script_setup_true_lang.js +237 -0
  78. package/dist/components/sheet-outline.vue_vue_type_script_setup_true_lang.js.map +1 -0
  79. package/dist/components/sheet-tabs.js +6 -0
  80. package/dist/components/sheet-tabs.js.map +1 -0
  81. package/dist/components/sheet-tabs.vue_vue_type_script_setup_true_lang.js +487 -0
  82. package/dist/components/sheet-tabs.vue_vue_type_script_setup_true_lang.js.map +1 -0
  83. package/dist/components/sheet-toolbar.js +6 -0
  84. package/dist/components/sheet-toolbar.js.map +1 -0
  85. package/dist/components/sheet-toolbar.vue_vue_type_script_setup_true_lang.js +1562 -0
  86. package/dist/components/sheet-toolbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  87. package/dist/components/validation-dialog.js +6 -0
  88. package/dist/components/validation-dialog.js.map +1 -0
  89. package/dist/components/validation-dialog.vue_vue_type_script_setup_true_lang.js +370 -0
  90. package/dist/components/validation-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  91. package/dist/context.js +12 -0
  92. package/dist/context.js.map +1 -0
  93. package/dist/core/address.js +256 -0
  94. package/dist/core/address.js.map +1 -0
  95. package/dist/core/axis.js +72 -0
  96. package/dist/core/axis.js.map +1 -0
  97. package/dist/core/cell-type.js +30 -0
  98. package/dist/core/cell-type.js.map +1 -0
  99. package/dist/core/clipboard.js +141 -0
  100. package/dist/core/clipboard.js.map +1 -0
  101. package/dist/core/commands.js +63 -0
  102. package/dist/core/commands.js.map +1 -0
  103. package/dist/core/comments.js +74 -0
  104. package/dist/core/comments.js.map +1 -0
  105. package/dist/core/conditional.js +362 -0
  106. package/dist/core/conditional.js.map +1 -0
  107. package/dist/core/csv.js +191 -0
  108. package/dist/core/csv.js.map +1 -0
  109. package/dist/core/data.js +118 -0
  110. package/dist/core/data.js.map +1 -0
  111. package/dist/core/document.js +187 -0
  112. package/dist/core/document.js.map +1 -0
  113. package/dist/core/extension.js +60 -0
  114. package/dist/core/extension.js.map +1 -0
  115. package/dist/core/file.js +336 -0
  116. package/dist/core/file.js.map +1 -0
  117. package/dist/core/fill.js +153 -0
  118. package/dist/core/fill.js.map +1 -0
  119. package/dist/core/find.js +42 -0
  120. package/dist/core/find.js.map +1 -0
  121. package/dist/core/format.js +404 -0
  122. package/dist/core/format.js.map +1 -0
  123. package/dist/core/group.js +134 -0
  124. package/dist/core/group.js.map +1 -0
  125. package/dist/core/history.js +68 -0
  126. package/dist/core/history.js.map +1 -0
  127. package/dist/core/index.js +17 -0
  128. package/dist/core/link.js +34 -0
  129. package/dist/core/link.js.map +1 -0
  130. package/dist/core/merge.js +105 -0
  131. package/dist/core/merge.js.map +1 -0
  132. package/dist/core/model.js +48 -0
  133. package/dist/core/model.js.map +1 -0
  134. package/dist/core/nav.js +44 -0
  135. package/dist/core/nav.js.map +1 -0
  136. package/dist/core/paint.js +106 -0
  137. package/dist/core/paint.js.map +1 -0
  138. package/dist/core/plain-cell-types.js +54 -0
  139. package/dist/core/plain-cell-types.js.map +1 -0
  140. package/dist/core/protect.js +246 -0
  141. package/dist/core/protect.js.map +1 -0
  142. package/dist/core/selection.js +37 -0
  143. package/dist/core/selection.js.map +1 -0
  144. package/dist/core/transaction.js +1582 -0
  145. package/dist/core/transaction.js.map +1 -0
  146. package/dist/core/validation.js +135 -0
  147. package/dist/core/validation.js.map +1 -0
  148. package/dist/core/versions.js +161 -0
  149. package/dist/core/versions.js.map +1 -0
  150. package/dist/export/color.js +36 -0
  151. package/dist/export/color.js.map +1 -0
  152. package/dist/export/draw.js +316 -0
  153. package/dist/export/draw.js.map +1 -0
  154. package/dist/export/index.js +390 -0
  155. package/dist/export/index.js.map +1 -0
  156. package/dist/formula/edit.js +210 -0
  157. package/dist/formula/edit.js.map +1 -0
  158. package/dist/formula/engine.js +526 -0
  159. package/dist/formula/engine.js.map +1 -0
  160. package/dist/formula/error.js +39 -0
  161. package/dist/formula/error.js.map +1 -0
  162. package/dist/formula/functions.js +1493 -0
  163. package/dist/formula/functions.js.map +1 -0
  164. package/dist/formula/help.js +408 -0
  165. package/dist/formula/help.js.map +1 -0
  166. package/dist/formula/index.js +7 -0
  167. package/dist/formula/parse.js +369 -0
  168. package/dist/formula/parse.js.map +1 -0
  169. package/dist/formula/values.js +123 -0
  170. package/dist/formula/values.js.map +1 -0
  171. package/dist/formulas.js +30 -0
  172. package/dist/formulas.js.map +1 -0
  173. package/dist/index.js +39 -0
  174. package/dist/index.js.map +1 -0
  175. package/dist/locale.js +1312 -0
  176. package/dist/locale.js.map +1 -0
  177. package/dist/sheet.js +6 -0
  178. package/dist/sheet.js.map +1 -0
  179. package/dist/sheet.vue_vue_type_script_setup_true_lang.js +7166 -0
  180. package/dist/sheet.vue_vue_type_script_setup_true_lang.js.map +1 -0
  181. package/dist/style.css +1 -0
  182. package/dist/style.d.ts +1 -0
  183. package/dist/style.js +17 -0
  184. package/dist/types/cell-types.d.ts +2 -0
  185. package/dist/types/code/code-formula-bar.vue.d.ts +3 -0
  186. package/dist/types/code/index.d.ts +12 -0
  187. package/dist/types/code/language.d.ts +13 -0
  188. package/dist/types/collaboration/anchor.d.ts +65 -0
  189. package/dist/types/collaboration/index.d.ts +59 -0
  190. package/dist/types/collaboration/peers.d.ts +21 -0
  191. package/dist/types/collaboration/shared.d.ts +75 -0
  192. package/dist/types/components/cell-panel.vue.d.ts +20 -0
  193. package/dist/types/components/cell-renders.d.ts +9 -0
  194. package/dist/types/components/date-panel.vue.d.ts +9 -0
  195. package/dist/types/components/filter-panel.vue.d.ts +21 -0
  196. package/dist/types/components/format-dialog.vue.d.ts +24 -0
  197. package/dist/types/components/format-list.vue.d.ts +25 -0
  198. package/dist/types/components/format-presets.d.ts +30 -0
  199. package/dist/types/components/option-panel.vue.d.ts +13 -0
  200. package/dist/types/components/sheet-comment.vue.d.ts +29 -0
  201. package/dist/types/components/sheet-formula-bar.vue.d.ts +3 -0
  202. package/dist/types/components/sheet-link.vue.d.ts +32 -0
  203. package/dist/types/components/sheet-menu.vue.d.ts +20 -0
  204. package/dist/types/components/sheet-name-box.vue.d.ts +3 -0
  205. package/dist/types/components/sheet-note.vue.d.ts +22 -0
  206. package/dist/types/components/sheet-outline.vue.d.ts +36 -0
  207. package/dist/types/components/sheet-tabs.vue.d.ts +9 -0
  208. package/dist/types/components/sheet-toolbar.vue.d.ts +11 -0
  209. package/dist/types/components/validation-dialog.vue.d.ts +25 -0
  210. package/dist/types/context.d.ts +189 -0
  211. package/dist/types/core/address.d.ts +109 -0
  212. package/dist/types/core/axis.d.ts +23 -0
  213. package/dist/types/core/cell-type.d.ts +157 -0
  214. package/dist/types/core/clipboard.d.ts +48 -0
  215. package/dist/types/core/commands.d.ts +76 -0
  216. package/dist/types/core/comments.d.ts +22 -0
  217. package/dist/types/core/conditional.d.ts +114 -0
  218. package/dist/types/core/csv.d.ts +93 -0
  219. package/dist/types/core/data.d.ts +26 -0
  220. package/dist/types/core/document.d.ts +49 -0
  221. package/dist/types/core/extension.d.ts +177 -0
  222. package/dist/types/core/file.d.ts +301 -0
  223. package/dist/types/core/fill.d.ts +23 -0
  224. package/dist/types/core/find.d.ts +39 -0
  225. package/dist/types/core/format.d.ts +47 -0
  226. package/dist/types/core/group.d.ts +76 -0
  227. package/dist/types/core/history.d.ts +27 -0
  228. package/dist/types/core/index.d.ts +33 -0
  229. package/dist/types/core/link.d.ts +14 -0
  230. package/dist/types/core/merge.d.ts +26 -0
  231. package/dist/types/core/model.d.ts +363 -0
  232. package/dist/types/core/nav.d.ts +15 -0
  233. package/dist/types/core/paint.d.ts +19 -0
  234. package/dist/types/core/plain-cell-types.d.ts +6 -0
  235. package/dist/types/core/protect.d.ts +34 -0
  236. package/dist/types/core/selection.d.ts +25 -0
  237. package/dist/types/core/transaction.d.ts +470 -0
  238. package/dist/types/core/validation.d.ts +55 -0
  239. package/dist/types/core/versions.d.ts +38 -0
  240. package/dist/types/export/color.d.ts +7 -0
  241. package/dist/types/export/draw.d.ts +98 -0
  242. package/dist/types/export/index.d.ts +47 -0
  243. package/dist/types/formula/edit.d.ts +62 -0
  244. package/dist/types/formula/engine.d.ts +99 -0
  245. package/dist/types/formula/error.d.ts +30 -0
  246. package/dist/types/formula/functions.d.ts +62 -0
  247. package/dist/types/formula/help.d.ts +12 -0
  248. package/dist/types/formula/index.d.ts +13 -0
  249. package/dist/types/formula/parse.d.ts +92 -0
  250. package/dist/types/formula/values.d.ts +65 -0
  251. package/dist/types/formulas.d.ts +32 -0
  252. package/dist/types/index.d.ts +225 -0
  253. package/dist/types/locale.d.ts +531 -0
  254. package/dist/types/sheet.vue.d.ts +60 -0
  255. package/dist/types/types.d.ts +498 -0
  256. package/dist/types/use-comments.d.ts +47 -0
  257. package/dist/types/use-messages.d.ts +7 -0
  258. package/dist/use-comments.js +130 -0
  259. package/dist/use-comments.js.map +1 -0
  260. package/dist/use-messages.js +29 -0
  261. package/dist/use-messages.js.map +1 -0
  262. package/package.json +93 -4
@@ -0,0 +1,246 @@
1
+ import { cellOf } from "./model.js";
2
+ import { SheetTransaction, sheetKey } from "./transaction.js";
3
+ // src/core/protect.ts
4
+ var NONE = {};
5
+ /** A sheet's protection, `null` when it isn't protected. */
6
+ function protectionOf(sheet) {
7
+ const protect = sheet?.protect;
8
+ if (!protect) return null;
9
+ return protect === true ? NONE : protect;
10
+ }
11
+ /** Whether a cell is locked: unless its style says `locked: false`. Takes a cell as `cells` hold it. */
12
+ function isLocked(cell, book) {
13
+ const name = cellOf(cell)?.style;
14
+ return !name || book.styles?.[name]?.locked !== false;
15
+ }
16
+ /** Whether anything in the workbook is protected, so changes need checking. */
17
+ function hasProtection(book) {
18
+ return !!book.protect || book.sheets.some((sheet) => !!sheet.protect);
19
+ }
20
+ /** A cell's fields besides its look. */
21
+ var sameContent = (a, b) => a?.value === b?.value && a?.type === b?.type && a?.note === b?.note && a?.link === b?.link;
22
+ /** Sheet fields that change freely on a protected sheet: lines added are checked as steps. */
23
+ var FREE_FIELDS = /* @__PURE__ */ new Set([
24
+ "protect",
25
+ "freeze",
26
+ "rowCount",
27
+ "colCount"
28
+ ]);
29
+ /**
30
+ * Checks a change against the protection of the workbook it started from,
31
+ * step by step, so each step meets the cells as they were when it ran. Gives
32
+ * the first thing that isn't allowed, or `null` when all of it is.
33
+ */
34
+ function checkProtection(tr) {
35
+ if (!hasProtection(tr.before) && !hasProtection(tr.doc)) return null;
36
+ const replay = new SheetTransaction(tr.before);
37
+ const { steps } = tr;
38
+ for (let i = 0; i < steps.length; i++) {
39
+ const step = steps[i];
40
+ const refusal = checkStep(step, replay.doc);
41
+ if (refusal) return refusal;
42
+ const follow = following(step, replay.doc);
43
+ replay.step(step);
44
+ if (follow && sameSteps(steps, i + 1, follow)) {
45
+ for (const next of follow) replay.step(next);
46
+ i += follow.length;
47
+ }
48
+ }
49
+ return null;
50
+ }
51
+ /**
52
+ * The steps that follow `step` when the transaction makes it: formulas,
53
+ * rules, merges and groups moved along with lines, or naming a sheet anew.
54
+ */
55
+ function following(step, book) {
56
+ const own = new SheetTransaction(book);
57
+ const make = own;
58
+ try {
59
+ switch (step.type) {
60
+ case "insertLines":
61
+ if (step.cells || step.sizes) return null;
62
+ make.insertLines(step.axis, step.index, step.count, step.sheet);
63
+ break;
64
+ case "removeLines":
65
+ make.deleteLines(step.axis, step.index, step.count, step.sheet);
66
+ break;
67
+ case "moveLines":
68
+ make.moveLines(step.axis, step.from, step.count, step.to, step.sheet);
69
+ break;
70
+ case "removeSheet":
71
+ own.removeSheet(step.sheet);
72
+ break;
73
+ case "updateSheet": {
74
+ const keys = Object.keys(step.patch);
75
+ if (keys.length !== 1 || keys[0] !== "name" || !step.patch.name) return null;
76
+ own.renameSheet(step.sheet, step.patch.name);
77
+ break;
78
+ }
79
+ default: return null;
80
+ }
81
+ } catch {
82
+ return null;
83
+ }
84
+ return own.steps.slice(1);
85
+ }
86
+ function sameSteps(steps, from, expected) {
87
+ if (!expected.length) return false;
88
+ if (from + expected.length > steps.length) return false;
89
+ return expected.every((step, i) => JSON.stringify(step) === JSON.stringify(steps[from + i]));
90
+ }
91
+ function sheetOf(book, key) {
92
+ return book.sheets.find((sheet) => (sheet.id ?? sheet.name) === key);
93
+ }
94
+ function checkStep(step, book) {
95
+ switch (step.type) {
96
+ case "updateBook": return null;
97
+ case "setType":
98
+ if (!book.types?.[step.name]) return null;
99
+ return lockedUsing(book, (cell) => cell.type === step.name);
100
+ case "setStyle": {
101
+ const old = book.styles?.[step.name];
102
+ if (!old) return null;
103
+ if (old.locked !== false !== (step.style?.locked !== false)) return book.sheets.some((sheet) => sheet.protect) ? { reason: "lock" } : null;
104
+ return lockedUsing(book, (cell) => cell.style === step.name);
105
+ }
106
+ case "insertSheet":
107
+ case "removeSheet":
108
+ case "moveSheet": return book.protect ? { reason: "structure" } : null;
109
+ }
110
+ const sheet = sheetOf(book, step.sheet);
111
+ if (step.type === "updateSheet" && book.protect && "name" in step.patch) {
112
+ if (step.patch.name !== sheet?.name) return {
113
+ reason: "structure",
114
+ sheet: step.sheet
115
+ };
116
+ }
117
+ const protect = protectionOf(sheet);
118
+ if (!protect || !sheet) return null;
119
+ const at = { sheet: step.sheet };
120
+ switch (step.type) {
121
+ case "setCell": {
122
+ const old = cellOf(sheet.cells[step.row]?.[step.col]);
123
+ const next = cellOf(step.cell);
124
+ const where = {
125
+ ...at,
126
+ row: step.row,
127
+ col: step.col
128
+ };
129
+ const locked = isLocked(old, book);
130
+ if (locked !== isLocked(next, book)) return {
131
+ reason: "lock",
132
+ ...where
133
+ };
134
+ if (!locked) return null;
135
+ if (!sameContent(old, next)) return {
136
+ reason: "cell",
137
+ ...where
138
+ };
139
+ return protect.formatCells ? null : {
140
+ reason: "format",
141
+ ...where
142
+ };
143
+ }
144
+ case "setSize":
145
+ if (step.axis === "row") return protect.formatRows ? null : {
146
+ reason: "formatRows",
147
+ ...at
148
+ };
149
+ return protect.formatColumns ? null : {
150
+ reason: "formatColumns",
151
+ ...at
152
+ };
153
+ case "insertLines":
154
+ if (step.axis === "row") return protect.insertRows ? null : {
155
+ reason: "insertRows",
156
+ ...at
157
+ };
158
+ return protect.insertColumns ? null : {
159
+ reason: "insertColumns",
160
+ ...at
161
+ };
162
+ case "removeLines": {
163
+ const row = step.axis === "row";
164
+ if (!(row ? protect.deleteRows : protect.deleteColumns)) return {
165
+ reason: row ? "deleteRows" : "deleteColumns",
166
+ ...at
167
+ };
168
+ return lockedIn(sheet, book, (r, c) => {
169
+ const n = row ? r : c;
170
+ return n >= step.index && n < step.index + step.count;
171
+ });
172
+ }
173
+ case "moveLines": return {
174
+ reason: "sheet",
175
+ ...at
176
+ };
177
+ case "updateSheet":
178
+ for (const key of Object.keys(step.patch)) {
179
+ if (FREE_FIELDS.has(key) || key === "name" || sheet[key] === step.patch[key]) continue;
180
+ if (key === "filter") {
181
+ if (!protect.filter) return {
182
+ reason: "filter",
183
+ ...at
184
+ };
185
+ continue;
186
+ }
187
+ if (key === "merges") {
188
+ if (!protect.formatCells) return {
189
+ reason: "format",
190
+ ...at
191
+ };
192
+ continue;
193
+ }
194
+ if (key === "groups" && sameGroups(sheet.groups, step.patch.groups)) continue;
195
+ return {
196
+ reason: "sheet",
197
+ ...at
198
+ };
199
+ }
200
+ return null;
201
+ }
202
+ }
203
+ /** The first locked cell holding something on `sheet` where `where` says, as a refusal. */
204
+ function lockedIn(sheet, book, where) {
205
+ for (const [row, line] of sheet.cells.entries()) {
206
+ if (!line) continue;
207
+ for (const [col, input] of line.entries()) {
208
+ const cell = cellOf(input);
209
+ if (cell == null || !where(row, col) || !isLocked(cell, book)) continue;
210
+ return {
211
+ reason: "cell",
212
+ sheet: sheetKey(sheet),
213
+ row,
214
+ col
215
+ };
216
+ }
217
+ }
218
+ return null;
219
+ }
220
+ /**
221
+ * The first locked cell that `uses` a style or type on a sheet that keeps
222
+ * its locked cells' look, as a refusal.
223
+ */
224
+ function lockedUsing(book, uses) {
225
+ for (const sheet of book.sheets) {
226
+ const protect = protectionOf(sheet);
227
+ if (!protect || protect.formatCells) continue;
228
+ for (const [row, line] of sheet.cells.entries()) for (const [col, input] of (line ?? []).entries()) {
229
+ const cell = cellOf(input);
230
+ if (cell && uses(cell) && isLocked(cell, book)) return {
231
+ reason: "format",
232
+ sheet: sheetKey(sheet),
233
+ row,
234
+ col
235
+ };
236
+ }
237
+ }
238
+ return null;
239
+ }
240
+ function sameGroups(a, b) {
241
+ if (!a || !b || a.length !== b.length) return false;
242
+ return a.every((group, i) => group.range === b[i].range);
243
+ }
244
+ export { checkProtection, hasProtection, isLocked, protectionOf };
245
+
246
+ //# sourceMappingURL=protect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protect.js","names":[],"sources":["../../src/core/protect.ts"],"sourcesContent":["import {\n cellOf,\n type SheetCell,\n type SheetCellInput,\n type SheetData,\n type SheetProtection,\n type SheetWorkbook,\n} from './model'\nimport { SheetTransaction, sheetKey, type SheetStep } from './transaction'\n\n/*\n * Protection. A protected sheet keeps its locked cells, its lines and its\n * rules as they are; a protected workbook keeps its sheets. The grid checks\n * every change it makes against the workbook as it was, and cancels the\n * ones that would change what is protected.\n */\n\n/** Why a change to a protected sheet or workbook isn't allowed. */\nexport type SheetProtectionRefusal =\n /** It changes what a locked cell holds. */\n | 'cell'\n /** It changes the look or number format of a locked cell, or merges cells. */\n | 'format'\n /** It locks or unlocks cells. */\n | 'lock'\n | 'formatRows'\n | 'formatColumns'\n | 'insertRows'\n | 'insertColumns'\n | 'deleteRows'\n | 'deleteColumns'\n | 'filter'\n /** It changes the sheet's rules, groups or other settings. */\n | 'sheet'\n /** It adds, removes, moves or renames a sheet of a protected workbook. */\n | 'structure'\n\n/** What a refused change runs into: the reason, the sheet and, for a cell, where it is. */\nexport interface SheetProtectionCheck {\n reason: SheetProtectionRefusal\n /** The sheet's key. */\n sheet?: string\n row?: number\n col?: number\n}\n\nconst NONE: SheetProtection = {}\n\n/** A sheet's protection, `null` when it isn't protected. */\nexport function protectionOf(sheet: SheetData | undefined): SheetProtection | null {\n const protect = sheet?.protect\n if (!protect) return null\n return protect === true ? NONE : protect\n}\n\n/** Whether a cell is locked: unless its style says `locked: false`. Takes a cell as `cells` hold it. */\nexport function isLocked(cell: SheetCellInput, book: SheetWorkbook) {\n const name = cellOf(cell)?.style\n return !name || book.styles?.[name]?.locked !== false\n}\n\n/** Whether anything in the workbook is protected, so changes need checking. */\nexport function hasProtection(book: SheetWorkbook) {\n return !!book.protect || book.sheets.some((sheet) => !!sheet.protect)\n}\n\n/** A cell's fields besides its look. */\nconst sameContent = (a: SheetCell | undefined, b: SheetCell | undefined) =>\n a?.value === b?.value && a?.type === b?.type && a?.note === b?.note && a?.link === b?.link\n\n/** Sheet fields that change freely on a protected sheet: lines added are checked as steps. */\nconst FREE_FIELDS = new Set(['protect', 'freeze', 'rowCount', 'colCount'])\n\n/**\n * Checks a change against the protection of the workbook it started from,\n * step by step, so each step meets the cells as they were when it ran. Gives\n * the first thing that isn't allowed, or `null` when all of it is.\n */\nexport function checkProtection(tr: SheetTransaction): SheetProtectionCheck | null {\n // a change that turns protection on is checked from there\n if (!hasProtection(tr.before) && !hasProtection(tr.doc)) return null\n const replay = new SheetTransaction(tr.before)\n const { steps } = tr\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]!\n const refusal = checkStep(step, replay.doc)\n if (refusal) return refusal\n // when lines move or a sheet is renamed, formulas and rules follow them:\n // the steps that do exactly that go ahead, anything more is checked\n const follow = following(step, replay.doc)\n replay.step(step)\n if (follow && sameSteps(steps, i + 1, follow)) {\n for (const next of follow) replay.step(next)\n i += follow.length\n }\n }\n return null\n}\n\n/**\n * The steps that follow `step` when the transaction makes it: formulas,\n * rules, merges and groups moved along with lines, or naming a sheet anew.\n */\nfunction following(step: SheetStep, book: SheetWorkbook): SheetStep[] | null {\n const own = new SheetTransaction(book)\n // the transaction's own ways of making these steps, with what follows them\n const make = own as unknown as {\n insertLines: (axis: string, index: number, count: number, sheet: string) => void\n deleteLines: (axis: string, index: number, count: number, sheet: string) => void\n moveLines: (axis: string, from: number, count: number, to: number, sheet: string) => void\n }\n try {\n switch (step.type) {\n case 'insertLines':\n if (step.cells || step.sizes) return null\n make.insertLines(step.axis, step.index, step.count, step.sheet)\n break\n case 'removeLines':\n make.deleteLines(step.axis, step.index, step.count, step.sheet)\n break\n case 'moveLines':\n make.moveLines(step.axis, step.from, step.count, step.to, step.sheet)\n break\n case 'removeSheet':\n own.removeSheet(step.sheet)\n break\n case 'updateSheet': {\n const keys = Object.keys(step.patch)\n if (keys.length !== 1 || keys[0] !== 'name' || !step.patch.name) return null\n own.renameSheet(step.sheet, step.patch.name)\n break\n }\n default:\n return null\n }\n } catch {\n return null\n }\n return own.steps.slice(1)\n}\n\nfunction sameSteps(steps: readonly SheetStep[], from: number, expected: SheetStep[]) {\n if (!expected.length) return false\n if (from + expected.length > steps.length) return false\n return expected.every((step, i) => JSON.stringify(step) === JSON.stringify(steps[from + i]))\n}\n\nfunction sheetOf(book: SheetWorkbook, key: string) {\n return book.sheets.find((sheet) => (sheet.id ?? sheet.name) === key)\n}\n\nfunction checkStep(step: SheetStep, book: SheetWorkbook): SheetProtectionCheck | null {\n switch (step.type) {\n case 'updateBook':\n return null\n case 'setType':\n // a named type changed in place changes every cell using it\n if (!book.types?.[step.name]) return null\n return lockedUsing(book, (cell) => cell.type === step.name)\n case 'setStyle': {\n // a style changed in place locks or unlocks, and restyles, every cell using it\n const old = book.styles?.[step.name]\n if (!old) return null\n if ((old.locked !== false) !== (step.style?.locked !== false))\n return book.sheets.some((sheet) => sheet.protect) ? { reason: 'lock' } : null\n return lockedUsing(book, (cell) => cell.style === step.name)\n }\n case 'insertSheet':\n case 'removeSheet':\n case 'moveSheet':\n return book.protect ? { reason: 'structure' } : null\n default:\n break\n }\n const sheet = sheetOf(book, step.sheet)\n if (step.type === 'updateSheet' && book.protect && 'name' in step.patch)\n if (step.patch.name !== sheet?.name) return { reason: 'structure', sheet: step.sheet }\n const protect = protectionOf(sheet)\n if (!protect || !sheet) return null\n const at = { sheet: step.sheet }\n switch (step.type) {\n case 'setCell': {\n const old = cellOf(sheet.cells[step.row]?.[step.col])\n const next = cellOf(step.cell)\n const where = { ...at, row: step.row, col: step.col }\n const locked = isLocked(old, book)\n if (locked !== isLocked(next, book)) return { reason: 'lock', ...where }\n if (!locked) return null\n if (!sameContent(old, next)) return { reason: 'cell', ...where }\n return protect.formatCells ? null : { reason: 'format', ...where }\n }\n case 'setSize':\n if (step.axis === 'row') return protect.formatRows ? null : { reason: 'formatRows', ...at }\n return protect.formatColumns ? null : { reason: 'formatColumns', ...at }\n case 'insertLines':\n if (step.axis === 'row') return protect.insertRows ? null : { reason: 'insertRows', ...at }\n return protect.insertColumns ? null : { reason: 'insertColumns', ...at }\n case 'removeLines': {\n const row = step.axis === 'row'\n if (!(row ? protect.deleteRows : protect.deleteColumns))\n return { reason: row ? 'deleteRows' : 'deleteColumns', ...at }\n // lines may go only without the locked cells in them\n return lockedIn(sheet, book, (r, c) => {\n const n = row ? r : c\n return n >= step.index && n < step.index + step.count\n })\n }\n case 'moveLines':\n return { reason: 'sheet', ...at }\n case 'updateSheet': {\n for (const key of Object.keys(step.patch) as (keyof typeof step.patch)[]) {\n // a rename is the workbook's to allow\n if (FREE_FIELDS.has(key) || key === 'name' || sheet[key] === step.patch[key]) continue\n if (key === 'filter') {\n if (!protect.filter) return { reason: 'filter', ...at }\n continue\n }\n if (key === 'merges') {\n if (!protect.formatCells) return { reason: 'format', ...at }\n continue\n }\n // folding and unfolding the groups there are\n if (key === 'groups' && sameGroups(sheet.groups, step.patch.groups)) continue\n return { reason: 'sheet', ...at }\n }\n return null\n }\n }\n}\n\n/** The first locked cell holding something on `sheet` where `where` says, as a refusal. */\nfunction lockedIn(\n sheet: SheetData,\n book: SheetWorkbook,\n where: (row: number, col: number) => boolean,\n): SheetProtectionCheck | null {\n for (const [row, line] of sheet.cells.entries()) {\n if (!line) continue\n for (const [col, input] of line.entries()) {\n const cell = cellOf(input)\n if (cell == null || !where(row, col) || !isLocked(cell, book)) continue\n return { reason: 'cell', sheet: sheetKey(sheet), row, col }\n }\n }\n return null\n}\n\n/**\n * The first locked cell that `uses` a style or type on a sheet that keeps\n * its locked cells' look, as a refusal.\n */\nfunction lockedUsing(\n book: SheetWorkbook,\n uses: (cell: SheetCell) => boolean,\n): SheetProtectionCheck | null {\n for (const sheet of book.sheets) {\n const protect = protectionOf(sheet)\n if (!protect || protect.formatCells) continue\n for (const [row, line] of sheet.cells.entries())\n for (const [col, input] of (line ?? []).entries()) {\n const cell = cellOf(input)\n if (cell && uses(cell) && isLocked(cell, book))\n return { reason: 'format', sheet: sheetKey(sheet), row, col }\n }\n }\n return null\n}\n\nfunction sameGroups(a: SheetData['groups'], b: SheetData['groups']) {\n if (!a || !b || a.length !== b.length) return false\n return a.every((group, i) => group.range === b[i]!.range)\n}\n"],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { boundsOf, inBounds, pointRange } from "./address.js";
2
+ // src/core/selection.ts
3
+ /** One cell selected. */
4
+ var selectCell = (point) => ({
5
+ active: point,
6
+ ranges: [pointRange(point)]
7
+ });
8
+ /** Whether a cell is in any of the selected ranges. */
9
+ function isSelected(selection, row, col) {
10
+ return selection.ranges.some((range) => inBounds(boundsOf(range), row, col));
11
+ }
12
+ /** Keeps a point inside a sheet of `rows` × `cols`. */
13
+ var clampPoint = (point, rows, cols) => ({
14
+ row: Math.max(0, Math.min(rows - 1, point.row)),
15
+ col: Math.max(0, Math.min(cols - 1, point.col))
16
+ });
17
+ /** The selection kept inside a sheet of `rows` × `cols`, e.g. after it shrank. */
18
+ function clampSelection(selection, rows, cols) {
19
+ const clamp = (point) => clampPoint(point, rows, cols);
20
+ return {
21
+ active: clamp(selection.active),
22
+ ranges: selection.ranges.map((range) => ({
23
+ start: clamp(range.start),
24
+ end: clamp(range.end)
25
+ }))
26
+ };
27
+ }
28
+ var samePoint = (a, b) => a.row === b.row && a.col === b.col;
29
+ function sameSelection(a, b) {
30
+ return samePoint(a.active, b.active) && a.ranges.length === b.ranges.length && a.ranges.every((range, i) => {
31
+ const other = b.ranges[i];
32
+ return samePoint(range.start, other.start) && samePoint(range.end, other.end);
33
+ });
34
+ }
35
+ export { clampPoint, clampSelection, isSelected, samePoint, sameSelection, selectCell };
36
+
37
+ //# sourceMappingURL=selection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.js","names":[],"sources":["../../src/core/selection.ts"],"sourcesContent":["import { boundsOf, inBounds, pointRange, type SheetPoint, type SheetRange } from './address'\n\n/**\n * What is selected on a sheet: one or more ranges, and the cell the\n * keyboard is on, which is inside the last range.\n */\nexport interface SheetSelection {\n active: SheetPoint\n ranges: SheetRange[]\n}\n\n/** One cell selected. */\nexport const selectCell = (point: SheetPoint): SheetSelection => ({\n active: point,\n ranges: [pointRange(point)],\n})\n\n/** Whether a cell is in any of the selected ranges. */\nexport function isSelected(selection: SheetSelection, row: number, col: number) {\n return selection.ranges.some((range) => inBounds(boundsOf(range), row, col))\n}\n\n/** Keeps a point inside a sheet of `rows` × `cols`. */\nexport const clampPoint = (point: SheetPoint, rows: number, cols: number): SheetPoint => ({\n row: Math.max(0, Math.min(rows - 1, point.row)),\n col: Math.max(0, Math.min(cols - 1, point.col)),\n})\n\n/** The selection kept inside a sheet of `rows` × `cols`, e.g. after it shrank. */\nexport function clampSelection(selection: SheetSelection, rows: number, cols: number) {\n const clamp = (point: SheetPoint) => clampPoint(point, rows, cols)\n return {\n active: clamp(selection.active),\n ranges: selection.ranges.map((range) => ({ start: clamp(range.start), end: clamp(range.end) })),\n }\n}\n\nexport const samePoint = (a: SheetPoint, b: SheetPoint) => a.row === b.row && a.col === b.col\n\nexport function sameSelection(a: SheetSelection, b: SheetSelection) {\n return (\n samePoint(a.active, b.active) &&\n a.ranges.length === b.ranges.length &&\n a.ranges.every((range, i) => {\n const other = b.ranges[i]!\n return samePoint(range.start, other.start) && samePoint(range.end, other.end)\n })\n )\n}\n"],"mappings":";;;AAYA,IAAa,cAAc,WAAuC;CAChE,QAAQ;CACR,QAAQ,CAAC,WAAW,KAAK,CAAC;AAC5B;;AAGA,SAAgB,WAAW,WAA2B,KAAa,KAAa;CAC9E,OAAO,UAAU,OAAO,MAAM,UAAU,SAAS,SAAS,KAAK,GAAG,KAAK,GAAG,CAAC;AAC7E;;AAGA,IAAa,cAAc,OAAmB,MAAc,UAA8B;CACxF,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,GAAG,MAAM,GAAG,CAAC;CAC9C,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,GAAG,MAAM,GAAG,CAAC;AAChD;;AAGA,SAAgB,eAAe,WAA2B,MAAc,MAAc;CACpF,MAAM,SAAS,UAAsB,WAAW,OAAO,MAAM,IAAI;CACjE,OAAO;EACL,QAAQ,MAAM,UAAU,MAAM;EAC9B,QAAQ,UAAU,OAAO,KAAK,WAAW;GAAE,OAAO,MAAM,MAAM,KAAK;GAAG,KAAK,MAAM,MAAM,GAAG;EAAE,EAAE;CAChG;AACF;AAEA,IAAa,aAAa,GAAe,MAAkB,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE;AAE1F,SAAgB,cAAc,GAAmB,GAAmB;CAClE,OACE,UAAU,EAAE,QAAQ,EAAE,MAAM,KAC5B,EAAE,OAAO,WAAW,EAAE,OAAO,UAC7B,EAAE,OAAO,OAAO,OAAO,MAAM;EAC3B,MAAM,QAAQ,EAAE,OAAO;EACvB,OAAO,UAAU,MAAM,OAAO,MAAM,KAAK,KAAK,UAAU,MAAM,KAAK,MAAM,GAAG;CAC9E,CAAC;AAEL"}