@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,91 @@
1
+ import { formatCell, parseRange, splitSheet } from "../core/address.js";
2
+ import { format } from "../locale.js";
3
+ import { useSheet } from "../context.js";
4
+ import { computed, createElementBlock, defineComponent, nextTick, normalizeClass, openBlock, ref, unref, useTemplateRef } from "vue";
5
+ // src/components/sheet-name-box.vue?vue&type=script&setup=true&lang.ts
6
+ var _hoisted_1 = [
7
+ "value",
8
+ "aria-label",
9
+ "aria-invalid"
10
+ ];
11
+ /** The formula bar's name box: the active cell's name, or a cell or range to go to. */
12
+ var sheet_name_box_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
13
+ name: "DouSheetNameBox",
14
+ __name: "sheet-name-box",
15
+ setup(__props) {
16
+ const sheet = useSheet();
17
+ const { editor, messages: m } = sheet;
18
+ const nameInput = useTemplateRef("name");
19
+ const nameTyping = ref(null);
20
+ /** Whether the text in the name box is no cell or range; it stays there to fix, or Escape. */
21
+ const nameInvalid = ref(false);
22
+ const cellName = computed(() => {
23
+ const e = editor.cell.value;
24
+ return formatCell(e ?? sheet.active.value);
25
+ });
26
+ const nameText = computed(() => nameTyping.value ?? cellName.value);
27
+ function goTo() {
28
+ const text = (nameTyping.value ?? "").trim();
29
+ if (!text) {
30
+ nameTyping.value = null;
31
+ return sheet.focus();
32
+ }
33
+ const { sheet: name, ref: target } = splitSheet(text);
34
+ const range = parseRange(target);
35
+ const at = name == null ? sheet.sheetIndex.value : sheet.doc.value.sheets.findIndex((s) => s.name.toLowerCase() === name.toLowerCase());
36
+ if (!range || at === -1) {
37
+ nameInvalid.value = true;
38
+ sheet.announce(format(m.value.badAddress, { text }));
39
+ nameInput.value?.select();
40
+ return;
41
+ }
42
+ nameTyping.value = null;
43
+ nameInvalid.value = false;
44
+ if (at !== sheet.sheetIndex.value) sheet.showSheet(at);
45
+ nextTick(() => {
46
+ sheet.select(target);
47
+ sheet.focus();
48
+ });
49
+ }
50
+ function onNameInput(event) {
51
+ nameTyping.value = event.target.value;
52
+ nameInvalid.value = false;
53
+ }
54
+ /** Leaving the box shows the active cell again. */
55
+ function onNameBlur() {
56
+ nameTyping.value = null;
57
+ nameInvalid.value = false;
58
+ }
59
+ function onNameKey(event) {
60
+ if (event.isComposing) return;
61
+ if (event.key === "Enter") {
62
+ event.preventDefault();
63
+ goTo();
64
+ } else if (event.key === "Escape") {
65
+ event.preventDefault();
66
+ nameTyping.value = null;
67
+ nameInvalid.value = false;
68
+ sheet.focus();
69
+ }
70
+ }
71
+ return (_ctx, _cache) => {
72
+ return openBlock(), createElementBlock("input", {
73
+ ref: "name",
74
+ class: normalizeClass(["dou-sheet-formula-bar__name", { "is-invalid": nameInvalid.value }]),
75
+ value: nameText.value,
76
+ "aria-label": unref(m).nameBox,
77
+ "aria-invalid": nameInvalid.value || void 0,
78
+ autocomplete: "off",
79
+ autocapitalize: "off",
80
+ spellcheck: "false",
81
+ onFocus: _cache[0] || (_cache[0] = ($event) => $event.target.select()),
82
+ onInput: onNameInput,
83
+ onKeydown: onNameKey,
84
+ onBlur: onNameBlur
85
+ }, null, 42, _hoisted_1);
86
+ };
87
+ }
88
+ });
89
+ export { sheet_name_box_vue_vue_type_script_setup_true_lang_default as default };
90
+
91
+ //# sourceMappingURL=sheet-name-box.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-name-box.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_normalizeClass","_unref"],"sources":["../../src/components/sheet-name-box.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, ref, useTemplateRef } from 'vue'\nimport { useSheet } from '../context'\nimport { formatCell, parseRange, splitSheet } from '../core/address'\nimport { format } from '../locale'\n\n/** The formula bar's name box: the active cell's name, or a cell or range to go to. */\ndefineOptions({ name: 'DouSheetNameBox' })\n\nconst sheet = useSheet()\nconst { editor, messages: m } = sheet\nconst nameInput = useTemplateRef<HTMLInputElement>('name')\n\nconst nameTyping = ref<string | null>(null)\n/** Whether the text in the name box is no cell or range; it stays there to fix, or Escape. */\nconst nameInvalid = ref(false)\nconst cellName = computed(() => {\n const e = editor.cell.value\n return formatCell(e ?? sheet.active.value)\n})\nconst nameText = computed(() => nameTyping.value ?? cellName.value)\n\nfunction goTo() {\n const text = (nameTyping.value ?? '').trim()\n if (!text) {\n nameTyping.value = null\n return sheet.focus()\n }\n const { sheet: name, ref: target } = splitSheet(text)\n const range = parseRange(target)\n const at =\n name == null\n ? sheet.sheetIndex.value\n : sheet.doc.value.sheets.findIndex((s) => s.name.toLowerCase() === name.toLowerCase())\n if (!range || at === -1) {\n nameInvalid.value = true\n sheet.announce(format(m.value.badAddress, { text }))\n nameInput.value?.select()\n return\n }\n nameTyping.value = null\n nameInvalid.value = false\n if (at !== sheet.sheetIndex.value) sheet.showSheet(at)\n void nextTick(() => {\n sheet.select(target)\n sheet.focus()\n })\n}\n\nfunction onNameInput(event: Event) {\n nameTyping.value = (event.target as HTMLInputElement).value\n nameInvalid.value = false\n}\n\n/** Leaving the box shows the active cell again. */\nfunction onNameBlur() {\n nameTyping.value = null\n nameInvalid.value = false\n}\n\nfunction onNameKey(event: KeyboardEvent) {\n if (event.isComposing) return\n if (event.key === 'Enter') {\n event.preventDefault()\n goTo()\n } else if (event.key === 'Escape') {\n event.preventDefault()\n nameTyping.value = null\n nameInvalid.value = false\n sheet.focus()\n }\n}\n</script>\n\n<template>\n <input\n ref=\"name\"\n class=\"dou-sheet-formula-bar__name\"\n :value=\"nameText\"\n :class=\"{ 'is-invalid': nameInvalid }\"\n :aria-label=\"m.nameBox\"\n :aria-invalid=\"nameInvalid || undefined\"\n autocomplete=\"off\"\n autocapitalize=\"off\"\n spellcheck=\"false\"\n @focus=\"($event.target as HTMLInputElement).select()\"\n @input=\"onNameInput\"\n @keydown=\"onNameKey\"\n @blur=\"onNameBlur\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;;;;;EASA,MAAM,QAAQ,SAAS;EACvB,MAAM,EAAE,QAAQ,UAAU,MAAM;EAChC,MAAM,YAAY,eAAiC,MAAM;EAEzD,MAAM,aAAa,IAAmB,IAAI;;EAE1C,MAAM,cAAc,IAAI,KAAK;EAC7B,MAAM,WAAW,eAAe;GAC9B,MAAM,IAAI,OAAO,KAAK;GACtB,OAAO,WAAW,KAAK,MAAM,OAAO,KAAK;EAC3C,CAAC;EACD,MAAM,WAAW,eAAe,WAAW,SAAS,SAAS,KAAK;EAElE,SAAS,OAAO;GACd,MAAM,QAAQ,WAAW,SAAS,GAAA,CAAI,KAAK;GAC3C,IAAI,CAAC,MAAM;IACT,WAAW,QAAQ;IACnB,OAAO,MAAM,MAAM;GACrB;GACA,MAAM,EAAE,OAAO,MAAM,KAAK,WAAW,WAAW,IAAI;GACpD,MAAM,QAAQ,WAAW,MAAM;GAC/B,MAAM,KACJ,QAAQ,OACJ,MAAM,WAAW,QACjB,MAAM,IAAI,MAAM,OAAO,WAAW,MAAM,EAAE,KAAK,YAAY,MAAM,KAAK,YAAY,CAAC;GACzF,IAAI,CAAC,SAAS,OAAO,IAAI;IACvB,YAAY,QAAQ;IACpB,MAAM,SAAS,OAAO,EAAE,MAAM,YAAY,EAAE,KAAK,CAAC,CAAC;IACnD,UAAU,OAAO,OAAO;IACxB;GACF;GACA,WAAW,QAAQ;GACnB,YAAY,QAAQ;GACpB,IAAI,OAAO,MAAM,WAAW,OAAO,MAAM,UAAU,EAAE;GACrD,eAAoB;IAClB,MAAM,OAAO,MAAM;IACnB,MAAM,MAAM;GACd,CAAC;EACH;EAEA,SAAS,YAAY,OAAc;GACjC,WAAW,QAAS,MAAM,OAA4B;GACtD,YAAY,QAAQ;EACtB;;EAGA,SAAS,aAAa;GACpB,WAAW,QAAQ;GACnB,YAAY,QAAQ;EACtB;EAEA,SAAS,UAAU,OAAsB;GACvC,IAAI,MAAM,aAAa;GACvB,IAAI,MAAM,QAAQ,SAAS;IACzB,MAAM,eAAe;IACrB,KAAK;GACP,OAAO,IAAI,MAAM,QAAQ,UAAU;IACjC,MAAM,eAAe;IACrB,WAAW,QAAQ;IACnB,YAAY,QAAQ;IACpB,MAAM,MAAM;GACd;EACF;;GAIE,OAAAA,UAAA,GAAAC,mBAcE,SAAA;IAbA,KAAI;IACJ,OAAKC,eAAA,CAAC,+BAA6B,EAAA,cAEX,YAAA,MAAW,CAAA,CAAA;IADlC,OAAO,SAAA;IAEP,cAAYC,MAAA,CAAA,CAAC,CAAC;IACd,gBAAc,YAAA,SAAe,KAAA;IAC9B,cAAa;IACb,gBAAe;IACf,YAAW;IACV,SAAK,OAAA,OAAA,OAAA,MAAA,WAAG,OAAO,OAA4B,OAAM;IACjD,SAAO;IACP,WAAS;IACT,QAAM"}
@@ -0,0 +1,6 @@
1
+ import sheet_note_vue_vue_type_script_setup_true_lang_default from "./sheet-note.vue_vue_type_script_setup_true_lang.js";
2
+ // src/components/sheet-note.vue
3
+ var sheet_note_default = sheet_note_vue_vue_type_script_setup_true_lang_default;
4
+ export { sheet_note_default as default };
5
+
6
+ //# sourceMappingURL=sheet-note.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-note.js","names":["_sfc_main"],"sources":["../../src/components/sheet-note.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouButton, useFloating, useZIndex, type VirtualElement } from 'dou-ui'\nimport { computed, nextTick, ref, useTemplateRef, watch } from 'vue'\nimport type { SheetNoteMessages } from '../locale'\n\n/*\n * A cell's note, beside the cell: read when the pointer rests on the cell\n * or a finger taps it, or written in the box when it is being edited.\n */\n\nconst props = defineProps<{\n /** The cell the note belongs to. */\n anchor: VirtualElement\n note: string\n editing: boolean\n messages: SheetNoteMessages\n}>()\n\nconst emit = defineEmits<{\n /** `leaving` when focus left the box for something else. */\n save: [note: string, leaving: boolean]\n cancel: [leaving: boolean]\n /** The pointer came onto the note, or left it. */\n hover: [inside: boolean]\n}>()\n\nconst box = useTemplateRef<HTMLElement>('box')\nconst input = useTemplateRef<HTMLTextAreaElement>('input')\nconst draft = ref(props.note)\n\nconst { style, placement, update } = useFloating(() => props.anchor, box, {\n open: true,\n placement: 'right-start',\n offset: 6,\n})\nconst zIndex = useZIndex().next()\n\n/** Grows the box with the text, up to the height the styles allow. */\nfunction fit() {\n const el = input.value\n if (!el) return\n el.style.height = 'auto'\n el.style.height = `${el.scrollHeight}px`\n void nextTick(update)\n}\n\nwatch(\n () => props.editing,\n async (editing) => {\n draft.value = props.note\n if (!editing) return\n await nextTick()\n fit()\n const el = input.value\n el?.focus({ preventScroll: true })\n el?.setSelectionRange(el.value.length, el.value.length)\n },\n { immediate: true, flush: 'post' },\n)\n\nconst changed = computed(() => draft.value !== props.note)\nlet done = false\n\nfunction save(leaving = false) {\n if (done) return\n done = true\n emit('save', draft.value, leaving)\n}\n\nfunction cancel(leaving = false) {\n if (done) return\n done = true\n emit('cancel', leaving)\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n // the grid's keys stay out of the box\n event.stopPropagation()\n if (event.isComposing) return\n if (event.key === 'Escape') {\n event.preventDefault()\n cancel()\n } else if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {\n event.preventDefault()\n save()\n }\n}\n\n/** Focus leaving the box keeps what was written, as clicking another cell does. */\nfunction onFocusout(event: FocusEvent) {\n const next = event.relatedTarget\n if (next instanceof Node && box.value?.contains(next)) return\n if (changed.value) save(true)\n else cancel(true)\n}\n\ndefineExpose({ focus: () => input.value?.focus({ preventScroll: true }) })\n</script>\n\n<template>\n <Transition name=\"dou-floating\" appear>\n <div\n ref=\"box\"\n class=\"dou-dropdown dou-floating dou-sheet__note\"\n :class=\"{ 'is-editing': editing }\"\n :style=\"[style, { zIndex }]\"\n :data-placement=\"placement\"\n :role=\"editing ? 'dialog' : undefined\"\n :aria-label=\"editing ? messages.label : undefined\"\n @pointerenter=\"emit('hover', true)\"\n @pointerleave=\"emit('hover', false)\"\n @pointerdown.stop\n @focusout=\"editing && onFocusout($event)\"\n @contextmenu.stop\n @wheel.stop\n >\n <template v-if=\"editing\">\n <textarea\n ref=\"input\"\n v-model=\"draft\"\n class=\"dou-sheet__note-input\"\n :aria-label=\"messages.label\"\n :placeholder=\"messages.placeholder\"\n rows=\"3\"\n @input=\"fit\"\n @keydown=\"onKeydown\"\n />\n <!-- pressing a button leaves focus in the box, so it isn't taken as leaving -->\n <div class=\"dou-sheet__note-actions\" @mousedown.prevent>\n <DouButton size=\"sm\" variant=\"ghost\" @keydown=\"onKeydown\" @click=\"cancel()\">\n {{ messages.cancel }}\n </DouButton>\n <DouButton size=\"sm\" variant=\"solid\" @keydown=\"onKeydown\" @click=\"save()\">\n {{ messages.save }}\n </DouButton>\n </div>\n </template>\n <p v-else class=\"dou-sheet__note-text\">{{ note }}</p>\n </div>\n </Transition>\n</template>\n"],"mappings":""}
@@ -0,0 +1,146 @@
1
+ import { DouButton, useFloating, useZIndex } from "dou-ui";
2
+ import { Fragment, Transition, computed, createBlock, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, openBlock, ref, toDisplayString, unref, useTemplateRef, vModelText, watch, withCtx, withDirectives, withModifiers } from "vue";
3
+ // src/components/sheet-note.vue?vue&type=script&setup=true&lang.ts
4
+ var _hoisted_1 = [
5
+ "data-placement",
6
+ "role",
7
+ "aria-label"
8
+ ];
9
+ var _hoisted_2 = ["aria-label", "placeholder"];
10
+ var _hoisted_3 = {
11
+ key: 1,
12
+ class: "dou-sheet__note-text"
13
+ };
14
+ var sheet_note_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
15
+ __name: "sheet-note",
16
+ props: {
17
+ anchor: {},
18
+ note: {},
19
+ editing: { type: Boolean },
20
+ messages: {}
21
+ },
22
+ emits: [
23
+ "save",
24
+ "cancel",
25
+ "hover"
26
+ ],
27
+ setup(__props, { expose: __expose, emit: __emit }) {
28
+ const props = __props;
29
+ const emit = __emit;
30
+ const box = useTemplateRef("box");
31
+ const input = useTemplateRef("input");
32
+ const draft = ref(props.note);
33
+ const { style, placement, update } = useFloating(() => props.anchor, box, {
34
+ open: true,
35
+ placement: "right-start",
36
+ offset: 6
37
+ });
38
+ const zIndex = useZIndex().next();
39
+ /** Grows the box with the text, up to the height the styles allow. */
40
+ function fit() {
41
+ const el = input.value;
42
+ if (!el) return;
43
+ el.style.height = "auto";
44
+ el.style.height = `${el.scrollHeight}px`;
45
+ nextTick(update);
46
+ }
47
+ watch(() => props.editing, async (editing) => {
48
+ draft.value = props.note;
49
+ if (!editing) return;
50
+ await nextTick();
51
+ fit();
52
+ const el = input.value;
53
+ el?.focus({ preventScroll: true });
54
+ el?.setSelectionRange(el.value.length, el.value.length);
55
+ }, {
56
+ immediate: true,
57
+ flush: "post"
58
+ });
59
+ const changed = computed(() => draft.value !== props.note);
60
+ let done = false;
61
+ function save(leaving = false) {
62
+ if (done) return;
63
+ done = true;
64
+ emit("save", draft.value, leaving);
65
+ }
66
+ function cancel(leaving = false) {
67
+ if (done) return;
68
+ done = true;
69
+ emit("cancel", leaving);
70
+ }
71
+ function onKeydown(event) {
72
+ event.stopPropagation();
73
+ if (event.isComposing) return;
74
+ if (event.key === "Escape") {
75
+ event.preventDefault();
76
+ cancel();
77
+ } else if (event.key === "Enter" && (event.ctrlKey || event.metaKey)) {
78
+ event.preventDefault();
79
+ save();
80
+ }
81
+ }
82
+ /** Focus leaving the box keeps what was written, as clicking another cell does. */
83
+ function onFocusout(event) {
84
+ const next = event.relatedTarget;
85
+ if (next instanceof Node && box.value?.contains(next)) return;
86
+ if (changed.value) save(true);
87
+ else cancel(true);
88
+ }
89
+ __expose({ focus: () => input.value?.focus({ preventScroll: true }) });
90
+ return (_ctx, _cache) => {
91
+ return openBlock(), createBlock(Transition, {
92
+ name: "dou-floating",
93
+ appear: ""
94
+ }, {
95
+ default: withCtx(() => [createElementVNode("div", {
96
+ ref_key: "box",
97
+ ref: box,
98
+ class: normalizeClass(["dou-dropdown dou-floating dou-sheet__note", { "is-editing": __props.editing }]),
99
+ style: normalizeStyle([unref(style), { zIndex: unref(zIndex) }]),
100
+ "data-placement": unref(placement),
101
+ role: __props.editing ? "dialog" : void 0,
102
+ "aria-label": __props.editing ? __props.messages.label : void 0,
103
+ onPointerenter: _cache[4] || (_cache[4] = ($event) => emit("hover", true)),
104
+ onPointerleave: _cache[5] || (_cache[5] = ($event) => emit("hover", false)),
105
+ onPointerdown: _cache[6] || (_cache[6] = withModifiers(() => {}, ["stop"])),
106
+ onFocusout: _cache[7] || (_cache[7] = ($event) => __props.editing && onFocusout($event)),
107
+ onContextmenu: _cache[8] || (_cache[8] = withModifiers(() => {}, ["stop"])),
108
+ onWheel: _cache[9] || (_cache[9] = withModifiers(() => {}, ["stop"]))
109
+ }, [__props.editing ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [withDirectives(createElementVNode("textarea", {
110
+ ref_key: "input",
111
+ ref: input,
112
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => draft.value = $event),
113
+ class: "dou-sheet__note-input",
114
+ "aria-label": __props.messages.label,
115
+ placeholder: __props.messages.placeholder,
116
+ rows: "3",
117
+ onInput: fit,
118
+ onKeydown
119
+ }, null, 40, _hoisted_2), [[vModelText, draft.value]]), createElementVNode("div", {
120
+ class: "dou-sheet__note-actions",
121
+ onMousedown: _cache[3] || (_cache[3] = withModifiers(() => {}, ["prevent"]))
122
+ }, [createVNode(unref(DouButton), {
123
+ size: "sm",
124
+ variant: "ghost",
125
+ onKeydown,
126
+ onClick: _cache[1] || (_cache[1] = ($event) => cancel())
127
+ }, {
128
+ default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.cancel), 1)]),
129
+ _: 1
130
+ }), createVNode(unref(DouButton), {
131
+ size: "sm",
132
+ variant: "solid",
133
+ onKeydown,
134
+ onClick: _cache[2] || (_cache[2] = ($event) => save())
135
+ }, {
136
+ default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.save), 1)]),
137
+ _: 1
138
+ })], 32)], 64)) : (openBlock(), createElementBlock("p", _hoisted_3, toDisplayString(__props.note), 1))], 46, _hoisted_1)]),
139
+ _: 1
140
+ });
141
+ };
142
+ }
143
+ });
144
+ export { sheet_note_vue_vue_type_script_setup_true_lang_default as default };
145
+
146
+ //# sourceMappingURL=sheet-note.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-note.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_Transition","_withCtx","_createElementVNode","_normalizeClass","_normalizeStyle","_unref","_withModifiers","_createElementBlock","_Fragment","_withDirectives","_vModelText","_createVNode","_createTextVNode","_toDisplayString"],"sources":["../../src/components/sheet-note.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouButton, useFloating, useZIndex, type VirtualElement } from 'dou-ui'\nimport { computed, nextTick, ref, useTemplateRef, watch } from 'vue'\nimport type { SheetNoteMessages } from '../locale'\n\n/*\n * A cell's note, beside the cell: read when the pointer rests on the cell\n * or a finger taps it, or written in the box when it is being edited.\n */\n\nconst props = defineProps<{\n /** The cell the note belongs to. */\n anchor: VirtualElement\n note: string\n editing: boolean\n messages: SheetNoteMessages\n}>()\n\nconst emit = defineEmits<{\n /** `leaving` when focus left the box for something else. */\n save: [note: string, leaving: boolean]\n cancel: [leaving: boolean]\n /** The pointer came onto the note, or left it. */\n hover: [inside: boolean]\n}>()\n\nconst box = useTemplateRef<HTMLElement>('box')\nconst input = useTemplateRef<HTMLTextAreaElement>('input')\nconst draft = ref(props.note)\n\nconst { style, placement, update } = useFloating(() => props.anchor, box, {\n open: true,\n placement: 'right-start',\n offset: 6,\n})\nconst zIndex = useZIndex().next()\n\n/** Grows the box with the text, up to the height the styles allow. */\nfunction fit() {\n const el = input.value\n if (!el) return\n el.style.height = 'auto'\n el.style.height = `${el.scrollHeight}px`\n void nextTick(update)\n}\n\nwatch(\n () => props.editing,\n async (editing) => {\n draft.value = props.note\n if (!editing) return\n await nextTick()\n fit()\n const el = input.value\n el?.focus({ preventScroll: true })\n el?.setSelectionRange(el.value.length, el.value.length)\n },\n { immediate: true, flush: 'post' },\n)\n\nconst changed = computed(() => draft.value !== props.note)\nlet done = false\n\nfunction save(leaving = false) {\n if (done) return\n done = true\n emit('save', draft.value, leaving)\n}\n\nfunction cancel(leaving = false) {\n if (done) return\n done = true\n emit('cancel', leaving)\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n // the grid's keys stay out of the box\n event.stopPropagation()\n if (event.isComposing) return\n if (event.key === 'Escape') {\n event.preventDefault()\n cancel()\n } else if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {\n event.preventDefault()\n save()\n }\n}\n\n/** Focus leaving the box keeps what was written, as clicking another cell does. */\nfunction onFocusout(event: FocusEvent) {\n const next = event.relatedTarget\n if (next instanceof Node && box.value?.contains(next)) return\n if (changed.value) save(true)\n else cancel(true)\n}\n\ndefineExpose({ focus: () => input.value?.focus({ preventScroll: true }) })\n</script>\n\n<template>\n <Transition name=\"dou-floating\" appear>\n <div\n ref=\"box\"\n class=\"dou-dropdown dou-floating dou-sheet__note\"\n :class=\"{ 'is-editing': editing }\"\n :style=\"[style, { zIndex }]\"\n :data-placement=\"placement\"\n :role=\"editing ? 'dialog' : undefined\"\n :aria-label=\"editing ? messages.label : undefined\"\n @pointerenter=\"emit('hover', true)\"\n @pointerleave=\"emit('hover', false)\"\n @pointerdown.stop\n @focusout=\"editing && onFocusout($event)\"\n @contextmenu.stop\n @wheel.stop\n >\n <template v-if=\"editing\">\n <textarea\n ref=\"input\"\n v-model=\"draft\"\n class=\"dou-sheet__note-input\"\n :aria-label=\"messages.label\"\n :placeholder=\"messages.placeholder\"\n rows=\"3\"\n @input=\"fit\"\n @keydown=\"onKeydown\"\n />\n <!-- pressing a button leaves focus in the box, so it isn't taken as leaving -->\n <div class=\"dou-sheet__note-actions\" @mousedown.prevent>\n <DouButton size=\"sm\" variant=\"ghost\" @keydown=\"onKeydown\" @click=\"cancel()\">\n {{ messages.cancel }}\n </DouButton>\n <DouButton size=\"sm\" variant=\"solid\" @keydown=\"onKeydown\" @click=\"save()\">\n {{ messages.save }}\n </DouButton>\n </div>\n </template>\n <p v-else class=\"dou-sheet__note-text\">{{ note }}</p>\n </div>\n </Transition>\n</template>\n"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import sheet_outline_vue_vue_type_script_setup_true_lang_default from "./sheet-outline.vue_vue_type_script_setup_true_lang.js";
2
+ // src/components/sheet-outline.vue
3
+ var sheet_outline_default = sheet_outline_vue_vue_type_script_setup_true_lang_default;
4
+ export { sheet_outline_default as default };
5
+
6
+ //# sourceMappingURL=sheet-outline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-outline.js","names":["_sfc_main"],"sources":["../../src/components/sheet-outline.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { MinusIcon, PlusIcon } from '@dou-ui/icons'\nimport { computed } from 'vue'\nimport type { SheetAxis } from '../core/axis'\nimport {\n OUTLINE_LANE as LANE,\n type SheetGroupAxis,\n type SheetGroupLines,\n type SheetGroupSummary,\n} from '../core/group'\n\n/*\n * The outline beside the row (or column) headers: a lane per depth, a line\n * along each group with a button on its summary line, and the level\n * buttons by the headers. It follows the grid's scroll from outside it.\n */\n\nconst props = defineProps<{\n axis: 'row' | 'col'\n groups: SheetGroupAxis\n /** Which side of a group its button is on. */\n summary: SheetGroupSummary\n lines: SheetAxis\n /** Frozen lines, which don't scroll. */\n frozen: number\n /** The header before the first line: the column letters for rows. */\n head: number\n scroll: number\n /** The grid's size along the axis. */\n view: number\n /** Whether to show the level buttons by the headers. */\n levels: boolean\n /** The room before the outline along the axis, the other outline's corner, which a finger may reach into. */\n before: number\n /** Labels of the buttons. */\n label: (group: SheetGroupLines) => string\n levelLabel: (level: number) => string\n}>()\n\nconst emit = defineEmits<{\n toggle: [group: SheetGroupLines]\n level: [level: number]\n wheel: [event: WheelEvent]\n}>()\n\n/** How big the buttons in the lanes are. */\nconst BUTTON = 14\n\nconst frozenSize = computed(() => props.lines.offset(props.frozen))\n\ninterface Mark {\n key: string\n group: SheetGroupLines\n /** Across the lanes: the lane's middle. */\n lane: number\n /** The line along the group, from `from` to `to`, with its end tick at `tick`. */\n from: number\n to: number\n tick: 'start' | 'end' | null\n /** The middle of the button's line; `null` without a button. */\n button: number | null\n /** Whether the button's line is frozen: its button is drawn with the frozen lines alone. */\n frozenButton: boolean\n}\n\nconst marks = computed(() => {\n const { lines, groups } = props\n const out: Mark[] = []\n for (const g of groups.list) {\n const at = groups.buttonLine(g, lines.count, props.summary)\n // inside a folded group, or on a hidden line: nothing to show\n if (at >= 0 && lines.hidden(at)) continue\n const lane = (g.depth - 1) * LANE + LANE / 2\n const button = at >= 0 ? lines.offset(at) + lines.size(at) / 2 : null\n const start = lines.offset(g.start)\n const end = lines.offset(g.end + 1)\n // without a line along it, a mark is just its button\n const alone = button ?? start\n const mark: Mark = {\n key: `${g.start}:${g.end}`,\n group: g,\n lane,\n from: alone,\n to: alone,\n tick: null,\n button,\n frozenButton: at >= 0 && at < props.frozen,\n }\n if (!g.collapsed && end > start) {\n if (button == null) Object.assign(mark, { from: start + 2, to: end - 2 })\n else if (at < g.start)\n Object.assign(mark, { from: button + BUTTON / 2, to: end - 2, tick: 'end' })\n else Object.assign(mark, { from: start + 2, to: button - BUTTON / 2, tick: 'start' })\n }\n out.push(mark)\n }\n return out\n})\n\n/** The marks within `from`–`to` along the axis. */\nfunction within(from: number, to: number) {\n return marks.value.filter((m) => {\n const lo = Math.min(m.from, m.button ?? m.from) - BUTTON\n const hi = Math.max(m.to, m.button ?? m.to) + BUTTON\n return hi >= from && lo <= to\n })\n}\n\nconst frozenMarks = computed(() => (frozenSize.value ? within(0, frozenSize.value) : []))\n/** How far past the edges marks are still drawn, so a quick scroll doesn't show gaps. */\nconst OVERSCAN = 64\n\nconst bodyMarks = computed(() => {\n // before the grid has a size, all of them\n if (props.view <= 0) return marks.value\n const from = frozenSize.value + props.scroll\n return within(from - OVERSCAN, from + props.view + OVERSCAN)\n})\n\nconst width = computed(() => (props.groups.depth + (props.levels ? 1 : 0)) * LANE)\n\n/** A box placed along the axis at `pos` and across it at `lane`. */\nfunction place(pos: number, lane: number, along: number, across: number) {\n return props.axis === 'row'\n ? `top:${pos}px;left:${lane}px;height:${along}px;width:${across}px`\n : `left:${pos}px;top:${lane}px;width:${along}px;height:${across}px`\n}\n\nfunction lineStyle(m: Mark) {\n return place(m.from, m.lane, Math.max(0, m.to - m.from), 6)\n}\n\n/** How far a finger's touch reaches from a button's middle, at most: 40px across. */\nconst REACH = 20\n\n/**\n * The touch target around a button, as an inset: as far as `REACH` each\n * way, and only halfway to a button nearby, so neighbours don't overlap.\n */\nfunction reach(before: number, after: number, start: number, end: number) {\n const half = BUTTON / 2\n // the inset counts from inside the button's 1px border\n const [a1, a2, c1, c2] = [before, after, start, end].map((n) => -(Math.max(half, n) - half + 1))\n return props.axis === 'row'\n ? `--dou-sheet-hit:${a1}px ${c2}px ${a2}px ${c1}px`\n : `--dou-sheet-hit:${c1}px ${a2}px ${c2}px ${a1}px`\n}\n\nconst hits = computed(() => {\n const out = new Map<string, string>()\n const buttons = marks.value.filter((m) => m.button != null)\n for (const m of buttons) {\n let before = REACH\n let after = REACH\n let start = REACH\n let end = REACH\n for (const o of buttons) {\n if (o === m) continue\n const along = o.button! - m.button!\n const across = o.lane - m.lane\n if (across === 0) {\n if (along > 0) after = Math.min(after, along / 2)\n else before = Math.min(before, -along / 2)\n } else if (Math.abs(along) < REACH * 2) {\n if (across > 0) end = Math.min(end, across / 2)\n else start = Math.min(start, -across / 2)\n }\n }\n out.set(m.key, reach(before, after, start, end))\n }\n return out\n})\n\nfunction buttonStyle(m: Mark) {\n return `${place(m.button! - BUTTON / 2, m.lane - BUTTON / 2, BUTTON, BUTTON)};${hits.value.get(m.key)}`\n}\n\n/** Where a mark's button shows along the outline, or `null` when it is scrolled away. */\nfunction shownAt(m: Mark) {\n if (m.button == null) return null\n if (m.frozenButton) return props.head + m.button\n const at = props.head + m.button - props.scroll\n return at >= props.head + frozenSize.value ? at : null\n}\n\n/**\n * A level button: side by side with the others across the lanes. Along the\n * axis it reaches into the corner before it and, for what it can't get\n * there, further toward the lines, short of the group buttons in its lane.\n * The outline doesn't clip, so the reach can leave the levels' band.\n */\nfunction levelStyle(level: number) {\n const middle = props.head / 2\n const box = place(middle - BUTTON / 2, (level - 1) * LANE + (LANE - BUTTON) / 2, BUTTON, BUTTON)\n const lane = (level - 1) * LANE + LANE / 2\n let room = Infinity\n for (const m of marks.value) {\n const at = m.lane === lane ? shownAt(m) : null\n if (at != null) room = Math.min(room, (at - middle) / 2)\n }\n const before = Math.min(REACH, middle + props.before)\n const after = Math.min(REACH * 2 - before, room)\n // across, the lane alone: past it are the sheet's edge, the other levels and the headers\n return `${box};${reach(before, after, LANE / 2, LANE / 2)}`\n}\n\nconst levelList = computed(() =>\n props.levels ? Array.from({ length: props.groups.depth + 1 }, (_, i) => i + 1) : [],\n)\n\nconst layerStyle = (from: number, size?: number) =>\n props.axis === 'row'\n ? `top:${from}px;${size == null ? 'bottom:0' : `height:${size}px`};width:${width.value}px`\n : `left:${from}px;${size == null ? 'right:0' : `width:${size}px`};height:${width.value}px`\n\nconst shift = computed(() => {\n const by = -(frozenSize.value + props.scroll)\n return props.axis === 'row' ? `transform:translateY(${by}px)` : `transform:translateX(${by}px)`\n})\n\ndefineExpose({ size: width })\n</script>\n\n<template>\n <div\n class=\"dou-sheet__outline\"\n :class=\"`is-${axis}`\"\n :style=\"axis === 'row' ? `width:${width}px` : `height:${width}px`\"\n @wheel=\"emit('wheel', $event)\"\n >\n <div\n v-if=\"levelList.length && head\"\n class=\"dou-sheet__outline-levels\"\n :style=\"layerStyle(0, head)\"\n >\n <button\n v-for=\"level in levelList\"\n :key=\"level\"\n type=\"button\"\n class=\"dou-sheet__outline-button is-level\"\n :style=\"levelStyle(level)\"\n :aria-label=\"levelLabel(level)\"\n tabindex=\"-1\"\n @click=\"emit('level', level)\"\n >\n {{ level }}\n </button>\n </div>\n <div\n v-for=\"layer in [\n { key: 'frozen', list: frozenMarks, style: layerStyle(head, frozenSize), inner: '' },\n { key: 'body', list: bodyMarks, style: layerStyle(head + frozenSize), inner: shift },\n ]\"\n :key=\"layer.key\"\n class=\"dou-sheet__outline-layer\"\n :style=\"layer.style\"\n >\n <div v-if=\"layer.list.length\" class=\"dou-sheet__outline-inner\" :style=\"layer.inner\">\n <template v-for=\"m in layer.list\" :key=\"m.key\">\n <span\n v-if=\"m.to > m.from\"\n class=\"dou-sheet__outline-line\"\n :class=\"m.tick && `is-tick-${m.tick}`\"\n :style=\"lineStyle(m)\"\n aria-hidden=\"true\"\n />\n <button\n v-if=\"m.button != null && m.frozenButton === (layer.key === 'frozen')\"\n type=\"button\"\n class=\"dou-sheet__outline-button\"\n :style=\"buttonStyle(m)\"\n :aria-label=\"label(m.group)\"\n :aria-expanded=\"!m.group.collapsed\"\n tabindex=\"-1\"\n @click=\"emit('toggle', m.group)\"\n >\n <PlusIcon v-if=\"m.group.collapsed\" />\n <MinusIcon v-else />\n </button>\n </template>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":""}
@@ -0,0 +1,237 @@
1
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, defineComponent, normalizeClass, normalizeStyle, openBlock, renderList, toDisplayString, unref } from "vue";
2
+ import { MinusIcon, PlusIcon } from "@dou-ui/icons";
3
+ // src/components/sheet-outline.vue?vue&type=script&setup=true&lang.ts
4
+ var _hoisted_1 = ["aria-label", "onClick"];
5
+ var _hoisted_2 = [
6
+ "aria-label",
7
+ "aria-expanded",
8
+ "onClick"
9
+ ];
10
+ var BUTTON = 14;
11
+ var OVERSCAN = 64;
12
+ var REACH = 20;
13
+ /**
14
+ * The touch target around a button, as an inset: as far as `REACH` each
15
+ * way, and only halfway to a button nearby, so neighbours don't overlap.
16
+ */
17
+ var sheet_outline_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
18
+ __name: "sheet-outline",
19
+ props: {
20
+ axis: {},
21
+ groups: {},
22
+ summary: {},
23
+ lines: {},
24
+ frozen: {},
25
+ head: {},
26
+ scroll: {},
27
+ view: {},
28
+ levels: { type: Boolean },
29
+ before: {},
30
+ label: { type: Function },
31
+ levelLabel: { type: Function }
32
+ },
33
+ emits: [
34
+ "toggle",
35
+ "level",
36
+ "wheel"
37
+ ],
38
+ setup(__props, { expose: __expose, emit: __emit }) {
39
+ const props = __props;
40
+ const emit = __emit;
41
+ /** How big the buttons in the lanes are. */
42
+ const frozenSize = computed(() => props.lines.offset(props.frozen));
43
+ const marks = computed(() => {
44
+ const { lines, groups } = props;
45
+ const out = [];
46
+ for (const g of groups.list) {
47
+ const at = groups.buttonLine(g, lines.count, props.summary);
48
+ if (at >= 0 && lines.hidden(at)) continue;
49
+ const lane = (g.depth - 1) * 16 + 8;
50
+ const button = at >= 0 ? lines.offset(at) + lines.size(at) / 2 : null;
51
+ const start = lines.offset(g.start);
52
+ const end = lines.offset(g.end + 1);
53
+ const alone = button ?? start;
54
+ const mark = {
55
+ key: `${g.start}:${g.end}`,
56
+ group: g,
57
+ lane,
58
+ from: alone,
59
+ to: alone,
60
+ tick: null,
61
+ button,
62
+ frozenButton: at >= 0 && at < props.frozen
63
+ };
64
+ if (!g.collapsed && end > start) {
65
+ if (button == null) Object.assign(mark, {
66
+ from: start + 2,
67
+ to: end - 2
68
+ });
69
+ else if (at < g.start) Object.assign(mark, {
70
+ from: button + BUTTON / 2,
71
+ to: end - 2,
72
+ tick: "end"
73
+ });
74
+ else Object.assign(mark, {
75
+ from: start + 2,
76
+ to: button - BUTTON / 2,
77
+ tick: "start"
78
+ });
79
+ }
80
+ out.push(mark);
81
+ }
82
+ return out;
83
+ });
84
+ /** The marks within `from`–`to` along the axis. */
85
+ function within(from, to) {
86
+ return marks.value.filter((m) => {
87
+ const lo = Math.min(m.from, m.button ?? m.from) - BUTTON;
88
+ return Math.max(m.to, m.button ?? m.to) + BUTTON >= from && lo <= to;
89
+ });
90
+ }
91
+ const frozenMarks = computed(() => frozenSize.value ? within(0, frozenSize.value) : []);
92
+ /** How far past the edges marks are still drawn, so a quick scroll doesn't show gaps. */
93
+ const bodyMarks = computed(() => {
94
+ if (props.view <= 0) return marks.value;
95
+ const from = frozenSize.value + props.scroll;
96
+ return within(from - OVERSCAN, from + props.view + OVERSCAN);
97
+ });
98
+ const width = computed(() => (props.groups.depth + (props.levels ? 1 : 0)) * 16);
99
+ /** A box placed along the axis at `pos` and across it at `lane`. */
100
+ function place(pos, lane, along, across) {
101
+ return props.axis === "row" ? `top:${pos}px;left:${lane}px;height:${along}px;width:${across}px` : `left:${pos}px;top:${lane}px;width:${along}px;height:${across}px`;
102
+ }
103
+ function lineStyle(m) {
104
+ return place(m.from, m.lane, Math.max(0, m.to - m.from), 6);
105
+ }
106
+ /** How far a finger's touch reaches from a button's middle, at most: 40px across. */
107
+ function reach(before, after, start, end) {
108
+ const half = BUTTON / 2;
109
+ const [a1, a2, c1, c2] = [
110
+ before,
111
+ after,
112
+ start,
113
+ end
114
+ ].map((n) => -(Math.max(half, n) - half + 1));
115
+ return props.axis === "row" ? `--dou-sheet-hit:${a1}px ${c2}px ${a2}px ${c1}px` : `--dou-sheet-hit:${c1}px ${a2}px ${c2}px ${a1}px`;
116
+ }
117
+ const hits = computed(() => {
118
+ const out = /* @__PURE__ */ new Map();
119
+ const buttons = marks.value.filter((m) => m.button != null);
120
+ for (const m of buttons) {
121
+ let before = REACH;
122
+ let after = REACH;
123
+ let start = REACH;
124
+ let end = REACH;
125
+ for (const o of buttons) {
126
+ if (o === m) continue;
127
+ const along = o.button - m.button;
128
+ const across = o.lane - m.lane;
129
+ if (across === 0) {
130
+ if (along > 0) after = Math.min(after, along / 2);
131
+ else before = Math.min(before, -along / 2);
132
+ } else if (Math.abs(along) < 40) {
133
+ if (across > 0) end = Math.min(end, across / 2);
134
+ else start = Math.min(start, -across / 2);
135
+ }
136
+ }
137
+ out.set(m.key, reach(before, after, start, end));
138
+ }
139
+ return out;
140
+ });
141
+ function buttonStyle(m) {
142
+ return `${place(m.button - BUTTON / 2, m.lane - BUTTON / 2, BUTTON, BUTTON)};${hits.value.get(m.key)}`;
143
+ }
144
+ /** Where a mark's button shows along the outline, or `null` when it is scrolled away. */
145
+ function shownAt(m) {
146
+ if (m.button == null) return null;
147
+ if (m.frozenButton) return props.head + m.button;
148
+ const at = props.head + m.button - props.scroll;
149
+ return at >= props.head + frozenSize.value ? at : null;
150
+ }
151
+ /**
152
+ * A level button: side by side with the others across the lanes. Along the
153
+ * axis it reaches into the corner before it and, for what it can't get
154
+ * there, further toward the lines, short of the group buttons in its lane.
155
+ * The outline doesn't clip, so the reach can leave the levels' band.
156
+ */
157
+ function levelStyle(level) {
158
+ const middle = props.head / 2;
159
+ const box = place(middle - BUTTON / 2, (level - 1) * 16 + (16 - BUTTON) / 2, BUTTON, BUTTON);
160
+ const lane = (level - 1) * 16 + 8;
161
+ let room = Infinity;
162
+ for (const m of marks.value) {
163
+ const at = m.lane === lane ? shownAt(m) : null;
164
+ if (at != null) room = Math.min(room, (at - middle) / 2);
165
+ }
166
+ const before = Math.min(REACH, middle + props.before);
167
+ return `${box};${reach(before, Math.min(40 - before, room), 8, 8)}`;
168
+ }
169
+ const levelList = computed(() => props.levels ? Array.from({ length: props.groups.depth + 1 }, (_, i) => i + 1) : []);
170
+ const layerStyle = (from, size) => props.axis === "row" ? `top:${from}px;${size == null ? "bottom:0" : `height:${size}px`};width:${width.value}px` : `left:${from}px;${size == null ? "right:0" : `width:${size}px`};height:${width.value}px`;
171
+ const shift = computed(() => {
172
+ const by = -(frozenSize.value + props.scroll);
173
+ return props.axis === "row" ? `transform:translateY(${by}px)` : `transform:translateX(${by}px)`;
174
+ });
175
+ __expose({ size: width });
176
+ return (_ctx, _cache) => {
177
+ return openBlock(), createElementBlock("div", {
178
+ class: normalizeClass(["dou-sheet__outline", `is-${__props.axis}`]),
179
+ style: normalizeStyle(__props.axis === "row" ? `width:${width.value}px` : `height:${width.value}px`),
180
+ onWheel: _cache[0] || (_cache[0] = ($event) => emit("wheel", $event))
181
+ }, [levelList.value.length && __props.head ? (openBlock(), createElementBlock("div", {
182
+ key: 0,
183
+ class: "dou-sheet__outline-levels",
184
+ style: normalizeStyle(layerStyle(0, __props.head))
185
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(levelList.value, (level) => {
186
+ return openBlock(), createElementBlock("button", {
187
+ key: level,
188
+ type: "button",
189
+ class: "dou-sheet__outline-button is-level",
190
+ style: normalizeStyle(levelStyle(level)),
191
+ "aria-label": __props.levelLabel(level),
192
+ tabindex: "-1",
193
+ onClick: ($event) => emit("level", level)
194
+ }, toDisplayString(level), 13, _hoisted_1);
195
+ }), 128))], 4)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList([{
196
+ key: "frozen",
197
+ list: frozenMarks.value,
198
+ style: layerStyle(__props.head, frozenSize.value),
199
+ inner: ""
200
+ }, {
201
+ key: "body",
202
+ list: bodyMarks.value,
203
+ style: layerStyle(__props.head + frozenSize.value),
204
+ inner: shift.value
205
+ }], (layer) => {
206
+ return openBlock(), createElementBlock("div", {
207
+ key: layer.key,
208
+ class: "dou-sheet__outline-layer",
209
+ style: normalizeStyle(layer.style)
210
+ }, [layer.list.length ? (openBlock(), createElementBlock("div", {
211
+ key: 0,
212
+ class: "dou-sheet__outline-inner",
213
+ style: normalizeStyle(layer.inner)
214
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(layer.list, (m) => {
215
+ return openBlock(), createElementBlock(Fragment, { key: m.key }, [m.to > m.from ? (openBlock(), createElementBlock("span", {
216
+ key: 0,
217
+ class: normalizeClass(["dou-sheet__outline-line", m.tick && `is-tick-${m.tick}`]),
218
+ style: normalizeStyle(lineStyle(m)),
219
+ "aria-hidden": "true"
220
+ }, null, 6)) : createCommentVNode("", true), m.button != null && m.frozenButton === (layer.key === "frozen") ? (openBlock(), createElementBlock("button", {
221
+ key: 1,
222
+ type: "button",
223
+ class: "dou-sheet__outline-button",
224
+ style: normalizeStyle(buttonStyle(m)),
225
+ "aria-label": __props.label(m.group),
226
+ "aria-expanded": !m.group.collapsed,
227
+ tabindex: "-1",
228
+ onClick: ($event) => emit("toggle", m.group)
229
+ }, [m.group.collapsed ? (openBlock(), createBlock(unref(PlusIcon), { key: 0 })) : (openBlock(), createBlock(unref(MinusIcon), { key: 1 }))], 12, _hoisted_2)) : createCommentVNode("", true)], 64);
230
+ }), 128))], 4)) : createCommentVNode("", true)], 4);
231
+ }), 128))], 38);
232
+ };
233
+ }
234
+ });
235
+ export { sheet_outline_vue_vue_type_script_setup_true_lang_default as default };
236
+
237
+ //# sourceMappingURL=sheet-outline.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-outline.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_normalizeClass","_normalizeStyle","_Fragment","_renderList","_toDisplayString","_createCommentVNode","_createBlock","_unref"],"sources":["../../src/components/sheet-outline.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { MinusIcon, PlusIcon } from '@dou-ui/icons'\nimport { computed } from 'vue'\nimport type { SheetAxis } from '../core/axis'\nimport {\n OUTLINE_LANE as LANE,\n type SheetGroupAxis,\n type SheetGroupLines,\n type SheetGroupSummary,\n} from '../core/group'\n\n/*\n * The outline beside the row (or column) headers: a lane per depth, a line\n * along each group with a button on its summary line, and the level\n * buttons by the headers. It follows the grid's scroll from outside it.\n */\n\nconst props = defineProps<{\n axis: 'row' | 'col'\n groups: SheetGroupAxis\n /** Which side of a group its button is on. */\n summary: SheetGroupSummary\n lines: SheetAxis\n /** Frozen lines, which don't scroll. */\n frozen: number\n /** The header before the first line: the column letters for rows. */\n head: number\n scroll: number\n /** The grid's size along the axis. */\n view: number\n /** Whether to show the level buttons by the headers. */\n levels: boolean\n /** The room before the outline along the axis, the other outline's corner, which a finger may reach into. */\n before: number\n /** Labels of the buttons. */\n label: (group: SheetGroupLines) => string\n levelLabel: (level: number) => string\n}>()\n\nconst emit = defineEmits<{\n toggle: [group: SheetGroupLines]\n level: [level: number]\n wheel: [event: WheelEvent]\n}>()\n\n/** How big the buttons in the lanes are. */\nconst BUTTON = 14\n\nconst frozenSize = computed(() => props.lines.offset(props.frozen))\n\ninterface Mark {\n key: string\n group: SheetGroupLines\n /** Across the lanes: the lane's middle. */\n lane: number\n /** The line along the group, from `from` to `to`, with its end tick at `tick`. */\n from: number\n to: number\n tick: 'start' | 'end' | null\n /** The middle of the button's line; `null` without a button. */\n button: number | null\n /** Whether the button's line is frozen: its button is drawn with the frozen lines alone. */\n frozenButton: boolean\n}\n\nconst marks = computed(() => {\n const { lines, groups } = props\n const out: Mark[] = []\n for (const g of groups.list) {\n const at = groups.buttonLine(g, lines.count, props.summary)\n // inside a folded group, or on a hidden line: nothing to show\n if (at >= 0 && lines.hidden(at)) continue\n const lane = (g.depth - 1) * LANE + LANE / 2\n const button = at >= 0 ? lines.offset(at) + lines.size(at) / 2 : null\n const start = lines.offset(g.start)\n const end = lines.offset(g.end + 1)\n // without a line along it, a mark is just its button\n const alone = button ?? start\n const mark: Mark = {\n key: `${g.start}:${g.end}`,\n group: g,\n lane,\n from: alone,\n to: alone,\n tick: null,\n button,\n frozenButton: at >= 0 && at < props.frozen,\n }\n if (!g.collapsed && end > start) {\n if (button == null) Object.assign(mark, { from: start + 2, to: end - 2 })\n else if (at < g.start)\n Object.assign(mark, { from: button + BUTTON / 2, to: end - 2, tick: 'end' })\n else Object.assign(mark, { from: start + 2, to: button - BUTTON / 2, tick: 'start' })\n }\n out.push(mark)\n }\n return out\n})\n\n/** The marks within `from`–`to` along the axis. */\nfunction within(from: number, to: number) {\n return marks.value.filter((m) => {\n const lo = Math.min(m.from, m.button ?? m.from) - BUTTON\n const hi = Math.max(m.to, m.button ?? m.to) + BUTTON\n return hi >= from && lo <= to\n })\n}\n\nconst frozenMarks = computed(() => (frozenSize.value ? within(0, frozenSize.value) : []))\n/** How far past the edges marks are still drawn, so a quick scroll doesn't show gaps. */\nconst OVERSCAN = 64\n\nconst bodyMarks = computed(() => {\n // before the grid has a size, all of them\n if (props.view <= 0) return marks.value\n const from = frozenSize.value + props.scroll\n return within(from - OVERSCAN, from + props.view + OVERSCAN)\n})\n\nconst width = computed(() => (props.groups.depth + (props.levels ? 1 : 0)) * LANE)\n\n/** A box placed along the axis at `pos` and across it at `lane`. */\nfunction place(pos: number, lane: number, along: number, across: number) {\n return props.axis === 'row'\n ? `top:${pos}px;left:${lane}px;height:${along}px;width:${across}px`\n : `left:${pos}px;top:${lane}px;width:${along}px;height:${across}px`\n}\n\nfunction lineStyle(m: Mark) {\n return place(m.from, m.lane, Math.max(0, m.to - m.from), 6)\n}\n\n/** How far a finger's touch reaches from a button's middle, at most: 40px across. */\nconst REACH = 20\n\n/**\n * The touch target around a button, as an inset: as far as `REACH` each\n * way, and only halfway to a button nearby, so neighbours don't overlap.\n */\nfunction reach(before: number, after: number, start: number, end: number) {\n const half = BUTTON / 2\n // the inset counts from inside the button's 1px border\n const [a1, a2, c1, c2] = [before, after, start, end].map((n) => -(Math.max(half, n) - half + 1))\n return props.axis === 'row'\n ? `--dou-sheet-hit:${a1}px ${c2}px ${a2}px ${c1}px`\n : `--dou-sheet-hit:${c1}px ${a2}px ${c2}px ${a1}px`\n}\n\nconst hits = computed(() => {\n const out = new Map<string, string>()\n const buttons = marks.value.filter((m) => m.button != null)\n for (const m of buttons) {\n let before = REACH\n let after = REACH\n let start = REACH\n let end = REACH\n for (const o of buttons) {\n if (o === m) continue\n const along = o.button! - m.button!\n const across = o.lane - m.lane\n if (across === 0) {\n if (along > 0) after = Math.min(after, along / 2)\n else before = Math.min(before, -along / 2)\n } else if (Math.abs(along) < REACH * 2) {\n if (across > 0) end = Math.min(end, across / 2)\n else start = Math.min(start, -across / 2)\n }\n }\n out.set(m.key, reach(before, after, start, end))\n }\n return out\n})\n\nfunction buttonStyle(m: Mark) {\n return `${place(m.button! - BUTTON / 2, m.lane - BUTTON / 2, BUTTON, BUTTON)};${hits.value.get(m.key)}`\n}\n\n/** Where a mark's button shows along the outline, or `null` when it is scrolled away. */\nfunction shownAt(m: Mark) {\n if (m.button == null) return null\n if (m.frozenButton) return props.head + m.button\n const at = props.head + m.button - props.scroll\n return at >= props.head + frozenSize.value ? at : null\n}\n\n/**\n * A level button: side by side with the others across the lanes. Along the\n * axis it reaches into the corner before it and, for what it can't get\n * there, further toward the lines, short of the group buttons in its lane.\n * The outline doesn't clip, so the reach can leave the levels' band.\n */\nfunction levelStyle(level: number) {\n const middle = props.head / 2\n const box = place(middle - BUTTON / 2, (level - 1) * LANE + (LANE - BUTTON) / 2, BUTTON, BUTTON)\n const lane = (level - 1) * LANE + LANE / 2\n let room = Infinity\n for (const m of marks.value) {\n const at = m.lane === lane ? shownAt(m) : null\n if (at != null) room = Math.min(room, (at - middle) / 2)\n }\n const before = Math.min(REACH, middle + props.before)\n const after = Math.min(REACH * 2 - before, room)\n // across, the lane alone: past it are the sheet's edge, the other levels and the headers\n return `${box};${reach(before, after, LANE / 2, LANE / 2)}`\n}\n\nconst levelList = computed(() =>\n props.levels ? Array.from({ length: props.groups.depth + 1 }, (_, i) => i + 1) : [],\n)\n\nconst layerStyle = (from: number, size?: number) =>\n props.axis === 'row'\n ? `top:${from}px;${size == null ? 'bottom:0' : `height:${size}px`};width:${width.value}px`\n : `left:${from}px;${size == null ? 'right:0' : `width:${size}px`};height:${width.value}px`\n\nconst shift = computed(() => {\n const by = -(frozenSize.value + props.scroll)\n return props.axis === 'row' ? `transform:translateY(${by}px)` : `transform:translateX(${by}px)`\n})\n\ndefineExpose({ size: width })\n</script>\n\n<template>\n <div\n class=\"dou-sheet__outline\"\n :class=\"`is-${axis}`\"\n :style=\"axis === 'row' ? `width:${width}px` : `height:${width}px`\"\n @wheel=\"emit('wheel', $event)\"\n >\n <div\n v-if=\"levelList.length && head\"\n class=\"dou-sheet__outline-levels\"\n :style=\"layerStyle(0, head)\"\n >\n <button\n v-for=\"level in levelList\"\n :key=\"level\"\n type=\"button\"\n class=\"dou-sheet__outline-button is-level\"\n :style=\"levelStyle(level)\"\n :aria-label=\"levelLabel(level)\"\n tabindex=\"-1\"\n @click=\"emit('level', level)\"\n >\n {{ level }}\n </button>\n </div>\n <div\n v-for=\"layer in [\n { key: 'frozen', list: frozenMarks, style: layerStyle(head, frozenSize), inner: '' },\n { key: 'body', list: bodyMarks, style: layerStyle(head + frozenSize), inner: shift },\n ]\"\n :key=\"layer.key\"\n class=\"dou-sheet__outline-layer\"\n :style=\"layer.style\"\n >\n <div v-if=\"layer.list.length\" class=\"dou-sheet__outline-inner\" :style=\"layer.inner\">\n <template v-for=\"m in layer.list\" :key=\"m.key\">\n <span\n v-if=\"m.to > m.from\"\n class=\"dou-sheet__outline-line\"\n :class=\"m.tick && `is-tick-${m.tick}`\"\n :style=\"lineStyle(m)\"\n aria-hidden=\"true\"\n />\n <button\n v-if=\"m.button != null && m.frozenButton === (layer.key === 'frozen')\"\n type=\"button\"\n class=\"dou-sheet__outline-button\"\n :style=\"buttonStyle(m)\"\n :aria-label=\"label(m.group)\"\n :aria-expanded=\"!m.group.collapsed\"\n tabindex=\"-1\"\n @click=\"emit('toggle', m.group)\"\n >\n <PlusIcon v-if=\"m.group.collapsed\" />\n <MinusIcon v-else />\n </button>\n </template>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;AA8CA,IAAM,SAAS;AAgEf,IAAM,WAAW;AAuBjB,IAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;EApHd,MAAM,QAAQ;EAsBd,MAAM,OAAO;;EASb,MAAM,aAAa,eAAe,MAAM,MAAM,OAAO,MAAM,MAAM,CAAC;EAiBlE,MAAM,QAAQ,eAAe;GAC3B,MAAM,EAAE,OAAO,WAAW;GAC1B,MAAM,MAAc,CAAC;GACrB,KAAK,MAAM,KAAK,OAAO,MAAM;IAC3B,MAAM,KAAK,OAAO,WAAW,GAAG,MAAM,OAAO,MAAM,OAAO;IAE1D,IAAI,MAAM,KAAK,MAAM,OAAO,EAAE,GAAG;IACjC,MAAM,QAAQ,EAAE,QAAQ,KAAA,KAAA;IACxB,MAAM,SAAS,MAAM,IAAI,MAAM,OAAO,EAAE,IAAI,MAAM,KAAK,EAAE,IAAI,IAAI;IACjE,MAAM,QAAQ,MAAM,OAAO,EAAE,KAAK;IAClC,MAAM,MAAM,MAAM,OAAO,EAAE,MAAM,CAAC;IAElC,MAAM,QAAQ,UAAU;IACxB,MAAM,OAAa;KACjB,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE;KACrB,OAAO;KACP;KACA,MAAM;KACN,IAAI;KACJ,MAAM;KACN;KACA,cAAc,MAAM,KAAK,KAAK,MAAM;IACtC;IACA,IAAI,CAAC,EAAE,aAAa,MAAM,OAAO;KAC/B,IAAI,UAAU,MAAM,OAAO,OAAO,MAAM;MAAE,MAAM,QAAQ;MAAG,IAAI,MAAM;KAAE,CAAC;UACnE,IAAI,KAAK,EAAE,OACd,OAAO,OAAO,MAAM;MAAE,MAAM,SAAS,SAAS;MAAG,IAAI,MAAM;MAAG,MAAM;KAAM,CAAC;UACxE,OAAO,OAAO,MAAM;MAAE,MAAM,QAAQ;MAAG,IAAI,SAAS,SAAS;MAAG,MAAM;KAAQ,CAAC;IACtF;IACA,IAAI,KAAK,IAAI;GACf;GACA,OAAO;EACT,CAAC;;EAGD,SAAS,OAAO,MAAc,IAAY;GACxC,OAAO,MAAM,MAAM,QAAQ,MAAM;IAC/B,MAAM,KAAK,KAAK,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,IAAI;IAElD,OADW,KAAK,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,IAAI,UACjC,QAAQ,MAAM;GAC7B,CAAC;EACH;EAEA,MAAM,cAAc,eAAgB,WAAW,QAAQ,OAAO,GAAG,WAAW,KAAK,IAAI,CAAC,CAAE;;EAIxF,MAAM,YAAY,eAAe;GAE/B,IAAI,MAAM,QAAQ,GAAG,OAAO,MAAM;GAClC,MAAM,OAAO,WAAW,QAAQ,MAAM;GACtC,OAAO,OAAO,OAAO,UAAU,OAAO,MAAM,OAAO,QAAQ;EAC7D,CAAC;EAED,MAAM,QAAQ,gBAAgB,MAAM,OAAO,SAAS,MAAM,SAAS,IAAI,MAAA,EAAU;;EAGjF,SAAS,MAAM,KAAa,MAAc,OAAe,QAAgB;GACvE,OAAO,MAAM,SAAS,QAClB,OAAO,IAAI,UAAU,KAAK,YAAY,MAAM,WAAW,OAAO,MAC9D,QAAQ,IAAI,SAAS,KAAK,WAAW,MAAM,YAAY,OAAO;EACpE;EAEA,SAAS,UAAU,GAAS;GAC1B,OAAO,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,EAAE,KAAK,EAAE,IAAI,GAAG,CAAC;EAC5D;;EASA,SAAS,MAAM,QAAgB,OAAe,OAAe,KAAa;GACxE,MAAM,OAAO,SAAS;GAEtB,MAAM,CAAC,IAAI,IAAI,IAAI,MAAM;IAAC;IAAQ;IAAO;IAAO;GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,KAAK,IAAI,MAAM,CAAC,IAAI,OAAO,EAAE;GAC/F,OAAO,MAAM,SAAS,QAClB,mBAAmB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAC9C,mBAAmB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG;EACpD;EAEA,MAAM,OAAO,eAAe;GAC1B,MAAM,sBAAM,IAAI,IAAoB;GACpC,MAAM,UAAU,MAAM,MAAM,QAAQ,MAAM,EAAE,UAAU,IAAI;GAC1D,KAAK,MAAM,KAAK,SAAS;IACvB,IAAI,SAAS;IACb,IAAI,QAAQ;IACZ,IAAI,QAAQ;IACZ,IAAI,MAAM;IACV,KAAK,MAAM,KAAK,SAAS;KACvB,IAAI,MAAM,GAAG;KACb,MAAM,QAAQ,EAAE,SAAU,EAAE;KAC5B,MAAM,SAAS,EAAE,OAAO,EAAE;KAC1B,IAAI,WAAW,GAAG;MAChB,IAAI,QAAQ,GAAG,QAAQ,KAAK,IAAI,OAAO,QAAQ,CAAC;WAC3C,SAAS,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC;KAC3C,OAAO,IAAI,KAAK,IAAI,KAAK,IAAI,IAAW;MACtC,IAAI,SAAS,GAAG,MAAM,KAAK,IAAI,KAAK,SAAS,CAAC;WACzC,QAAQ,KAAK,IAAI,OAAO,CAAC,SAAS,CAAC;KAC1C;IACF;IACA,IAAI,IAAI,EAAE,KAAK,MAAM,QAAQ,OAAO,OAAO,GAAG,CAAC;GACjD;GACA,OAAO;EACT,CAAC;EAED,SAAS,YAAY,GAAS;GAC5B,OAAO,GAAG,MAAM,EAAE,SAAU,SAAS,GAAG,EAAE,OAAO,SAAS,GAAG,QAAQ,MAAM,EAAE,GAAG,KAAK,MAAM,IAAI,EAAE,GAAG;EACtG;;EAGA,SAAS,QAAQ,GAAS;GACxB,IAAI,EAAE,UAAU,MAAM,OAAO;GAC7B,IAAI,EAAE,cAAc,OAAO,MAAM,OAAO,EAAE;GAC1C,MAAM,KAAK,MAAM,OAAO,EAAE,SAAS,MAAM;GACzC,OAAO,MAAM,MAAM,OAAO,WAAW,QAAQ,KAAK;EACpD;;;;;;;EAQA,SAAS,WAAW,OAAe;GACjC,MAAM,SAAS,MAAM,OAAO;GAC5B,MAAM,MAAM,MAAM,SAAS,SAAS,IAAI,QAAQ,KAAA,MAAA,KAAoB,UAAU,GAAG,QAAQ,MAAM;GAC/F,MAAM,QAAQ,QAAQ,KAAA,KAAA;GACtB,IAAI,OAAO;GACX,KAAK,MAAM,KAAK,MAAM,OAAO;IAC3B,MAAM,KAAK,EAAE,SAAS,OAAO,QAAQ,CAAC,IAAI;IAC1C,IAAI,MAAM,MAAM,OAAO,KAAK,IAAI,OAAO,KAAK,UAAU,CAAC;GACzD;GACA,MAAM,SAAS,KAAK,IAAI,OAAO,SAAS,MAAM,MAAM;GAGpD,OAAO,GAAG,IAAI,GAAG,MAAM,QAFT,KAAK,IAAI,KAAY,QAAQ,IAEZ,GAAA,GAAc,CAAW;EAC1D;EAEA,MAAM,YAAY,eAChB,MAAM,SAAS,MAAM,KAAK,EAAE,QAAQ,MAAM,OAAO,QAAQ,EAAE,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CACpF;EAEA,MAAM,cAAc,MAAc,SAChC,MAAM,SAAS,QACX,OAAO,KAAK,KAAK,QAAQ,OAAO,aAAa,UAAU,KAAK,IAAI,SAAS,MAAM,MAAM,MACrF,QAAQ,KAAK,KAAK,QAAQ,OAAO,YAAY,SAAS,KAAK,IAAI,UAAU,MAAM,MAAM;EAE3F,MAAM,QAAQ,eAAe;GAC3B,MAAM,KAAK,EAAE,WAAW,QAAQ,MAAM;GACtC,OAAO,MAAM,SAAS,QAAQ,wBAAwB,GAAG,OAAO,wBAAwB,GAAG;EAC7F,CAAC;EAED,SAAa,EAAE,MAAM,MAAM,CAAC;;GAI1B,OAAAA,UAAA,GAAAC,mBA0DM,OAAA;IAzDJ,OAAKC,eAAA,CAAC,sBAAoB,MACZ,QAAA,MAAI,CAAA;IACjB,OAAKC,eAAE,QAAA,SAAI,QAAA,SAAsB,MAAA,MAAK,MAAA,UAAiB,MAAA,MAAK,GAAA;IAC5D,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,SAAU,MAAM;G,IAGpB,UAAA,MAAU,UAAU,QAAA,QAD5BH,UAAA,GAAAC,mBAiBM,OAAA;;IAfJ,OAAM;IACL,OAAKE,eAAE,WAAU,GAAI,QAAA,IAAI,CAAA;G,KAE1BH,UAAA,IAAA,GAAAC,mBAWSG,UAAA,MAAAC,WAVS,UAAA,QAAT,UAAK;IADd,OAAAL,UAAA,GAAAC,mBAWS,UAAA;KATN,KAAK;KACN,MAAK;KACL,OAAM;KACL,OAAKE,eAAE,WAAW,KAAK,CAAA;KACvB,cAAY,QAAA,WAAW,KAAK;KAC7B,UAAS;KACR,UAAK,WAAE,KAAI,SAAU,KAAK;IAExB,GAAAG,gBAAA,KAAK,GAAA,IAAA,UAAA;G,iDAGZN,UAAA,IAAA,GAAAC,mBAiCMG,UAAA,MAAAC,WAAA,CAhC6C;IAAA,KAAA;IAAA,MAAA,YAAA;IAAW,OAAS,WAAW,QAAA,MAAM,WAAA,KAAU;IAAA,OAAA;GAAA,GAA6C;IAAA,KAAA;IAAA,MAAA,UAAA;IAAS,OAAS,WAAW,QAAA,OAAO,WAAA,KAAU;IAAA,OAAU,MAAA;GAAK,CAAnM,IAAA,UAAK;IADd,OAAAL,UAAA,GAAAC,mBAiCM,OAAA;KA5BH,KAAK,MAAM;KACZ,OAAM;KACL,OAAKE,eAAE,MAAM,KAAK;I,IAER,MAAM,KAAK,UAAtBH,UAAA,GAAAC,mBAuBM,OAAA;;KAvBwB,OAAM;KAA4B,OAAKE,eAAE,MAAM,KAAK;I,KAChFH,UAAA,IAAA,GAAAC,mBAqBWG,UAAA,MAAAC,WArBW,MAAM,OAAX,MAAC;K,mDAAsB,KAAA,EAAE,I,IAEhC,EAAE,KAAK,EAAE,QADjBL,UAAA,GAAAC,mBAME,QAAA;;MAJA,OAAKC,eAAA,CAAC,2BACE,EAAE,QAAI,WAAe,EAAE,MAAI,CAAA;MAClC,OAAKC,eAAE,UAAU,CAAC,CAAA;MACnB,eAAY;K,6CAGN,EAAE,UAAM,QAAY,EAAE,kBAAkB,MAAM,QAAG,aADzDH,UAAA,GAAAC,mBAYS,UAAA;;MAVP,MAAK;MACL,OAAM;MACL,OAAKE,eAAE,YAAY,CAAC,CAAA;MACpB,cAAY,QAAA,MAAM,EAAE,KAAK;MACzB,iBAAa,CAAG,EAAE,MAAM;MACzB,UAAS;MACR,UAAK,WAAE,KAAI,UAAW,EAAE,KAAK;K,IAEd,EAAE,MAAM,aAAxBH,UAAA,GAAAQ,YAAqCC,MAAA,QAAA,GAAA,EAAA,KAAA,EAAA,CAAA,MACrCT,UAAA,GAAAQ,YAAoBC,MAAA,SAAA,GAAA,EAAA,KAAA,EAAA,CAAA,E"}
@@ -0,0 +1,6 @@
1
+ import sheet_tabs_vue_vue_type_script_setup_true_lang_default from "./sheet-tabs.vue_vue_type_script_setup_true_lang.js";
2
+ // src/components/sheet-tabs.vue
3
+ var sheet_tabs_default = sheet_tabs_vue_vue_type_script_setup_true_lang_default;
4
+ export { sheet_tabs_default as default };
5
+
6
+ //# sourceMappingURL=sheet-tabs.js.map