@dou-ui/sheet 0.0.0-stage → 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,124 @@
1
+ import { formulaParts, formulaReferences, partClass } from "../formula/edit.js";
2
+ import { useSheet } from "../context.js";
3
+ import sheet_name_box_default from "./sheet-name-box.js";
4
+ import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, renderList, toDisplayString, unref, useTemplateRef, watch } from "vue";
5
+ import { FunctionIcon } from "@dou-ui/icons";
6
+ // src/components/sheet-formula-bar.vue?vue&type=script&setup=true&lang.ts
7
+ var _hoisted_1 = { class: "dou-sheet-formula-bar" };
8
+ var _hoisted_2 = {
9
+ class: "dou-sheet-formula-bar__mark",
10
+ "aria-hidden": "true"
11
+ };
12
+ var _hoisted_3 = [
13
+ "value",
14
+ "aria-label",
15
+ "aria-autocomplete",
16
+ "aria-controls",
17
+ "readonly"
18
+ ];
19
+ var sheet_formula_bar_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
20
+ name: "DouSheetFormulaBar",
21
+ __name: "sheet-formula-bar",
22
+ setup(__props) {
23
+ const sheet = useSheet();
24
+ const { editor, messages: m } = sheet;
25
+ const input = useTemplateRef("input");
26
+ const mirror = useTemplateRef("mirror");
27
+ const editingHere = computed(() => !!editor.cell.value);
28
+ const text = computed(() => editingHere.value ? editor.text.value : editor.textAt(sheet.active.value));
29
+ const marks = computed(() => editingHere.value ? formulaReferences(text.value) : []);
30
+ /** A formula is shown in its colors, under the box's clear text. */
31
+ const isFormula = computed(() => text.value.startsWith("="));
32
+ const parts = computed(() => isFormula.value ? formulaParts(text.value, marks.value) : []);
33
+ /** As many lines as the text has, up to five; more scroll. */
34
+ const lines = computed(() => Math.min(5, text.value.split("\n").length));
35
+ let composing = false;
36
+ const setComposing = (value) => composing = value;
37
+ function onInput(event) {
38
+ const el = event.target;
39
+ if (!editor.input(el.value, el.selectionStart)) el.value = text.value;
40
+ syncMirror();
41
+ }
42
+ function onKey(event) {
43
+ if (composing || event.isComposing) return;
44
+ if (editingHere.value) {
45
+ if (editor.key(event) && !editor.cell.value) sheet.focus();
46
+ return;
47
+ }
48
+ if (event.key === "Escape" || event.key === "Enter") {
49
+ event.preventDefault();
50
+ sheet.focus();
51
+ }
52
+ }
53
+ function syncCaret() {
54
+ const el = input.value;
55
+ if (el && editingHere.value) editor.moveCaret(el.selectionStart);
56
+ syncMirror();
57
+ }
58
+ function syncMirror() {
59
+ const el = input.value;
60
+ const shown = mirror.value;
61
+ if (!el || !shown) return;
62
+ shown.scrollLeft = el.scrollLeft;
63
+ shown.scrollTop = el.scrollTop;
64
+ }
65
+ function onBlur(event) {
66
+ const next = event.relatedTarget;
67
+ if (!editor.cell.value || !document.hasFocus()) return;
68
+ if (next?.closest(".dou-sheet__input, .dou-sheet__assist")) return;
69
+ editor.commit();
70
+ }
71
+ watch(text, () => void nextTick(syncMirror));
72
+ let detach;
73
+ onMounted(() => {
74
+ if (input.value) detach = editor.attach(input.value);
75
+ });
76
+ onBeforeUnmount(() => detach?.());
77
+ return (_ctx, _cache) => {
78
+ return openBlock(), createElementBlock("div", _hoisted_1, [
79
+ createVNode(sheet_name_box_default),
80
+ createElementVNode("span", _hoisted_2, [createVNode(unref(FunctionIcon))]),
81
+ createElementVNode("div", {
82
+ class: "dou-sheet-formula-bar__box",
83
+ style: normalizeStyle(`--dou-sheet-bar-lines:${lines.value}`)
84
+ }, [isFormula.value ? (openBlock(), createElementBlock("div", {
85
+ key: 0,
86
+ ref_key: "mirror",
87
+ ref: mirror,
88
+ class: "dou-sheet-formula-bar__mirror",
89
+ "aria-hidden": "true"
90
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(parts.value, (part, i) => {
91
+ return openBlock(), createElementBlock("span", {
92
+ key: i,
93
+ class: normalizeClass(unref(partClass)(part))
94
+ }, toDisplayString(part.text), 3);
95
+ }), 128))], 512)) : createCommentVNode("", true), createElementVNode("textarea", {
96
+ ref_key: "input",
97
+ ref: input,
98
+ class: normalizeClass(["dou-sheet-formula-bar__input", { "is-formula": isFormula.value }]),
99
+ value: text.value,
100
+ "aria-label": unref(m).formulaBox,
101
+ "aria-autocomplete": editingHere.value ? "list" : void 0,
102
+ "aria-controls": editingHere.value ? unref(editor).helpId : void 0,
103
+ readonly: unref(sheet).readonly.value,
104
+ rows: "1",
105
+ autocomplete: "off",
106
+ autocapitalize: "off",
107
+ spellcheck: "false",
108
+ onInput,
109
+ onKeydown: onKey,
110
+ onKeyup: syncCaret,
111
+ onClick: syncCaret,
112
+ onSelect: syncCaret,
113
+ onScroll: syncMirror,
114
+ onCompositionstart: _cache[0] || (_cache[0] = ($event) => setComposing(true)),
115
+ onCompositionend: _cache[1] || (_cache[1] = ($event) => setComposing(false)),
116
+ onBlur
117
+ }, null, 42, _hoisted_3)], 4)
118
+ ]);
119
+ };
120
+ }
121
+ });
122
+ export { sheet_formula_bar_vue_vue_type_script_setup_true_lang_default as default };
123
+
124
+ //# sourceMappingURL=sheet-formula-bar.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-formula-bar.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_createVNode","SheetNameBox","_createElementVNode","_unref","_normalizeStyle","_Fragment","_renderList","_normalizeClass","_toDisplayString","_createCommentVNode"],"sources":["../../src/components/sheet-formula-bar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { FunctionIcon } from '@dou-ui/icons'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue'\nimport { useSheet } from '../context'\nimport SheetNameBox from './sheet-name-box.vue'\nimport { formulaParts, formulaReferences, partClass } from '../formula/edit'\n\ndefineOptions({ name: 'DouSheetFormulaBar' })\n\nconst sheet = useSheet()\nconst { editor, messages: m } = sheet\n\nconst input = useTemplateRef<HTMLTextAreaElement>('input')\nconst mirror = useTemplateRef<HTMLElement>('mirror')\n\n// The formula box: what the active cell holds, edited along with the cell ----------------------\n\nconst editingHere = computed(() => !!editor.cell.value)\nconst text = computed(() =>\n editingHere.value ? editor.text.value : editor.textAt(sheet.active.value),\n)\nconst marks = computed(() => (editingHere.value ? formulaReferences(text.value) : []))\n/** A formula is shown in its colors, under the box's clear text. */\nconst isFormula = computed(() => text.value.startsWith('='))\nconst parts = computed(() => (isFormula.value ? formulaParts(text.value, marks.value) : []))\n\n/** As many lines as the text has, up to five; more scroll. */\nconst lines = computed(() => Math.min(5, text.value.split('\\n').length))\n\nlet composing = false\nconst setComposing = (value: boolean) => (composing = value)\n\nfunction onInput(event: Event) {\n const el = event.target as HTMLTextAreaElement\n if (!editor.input(el.value, el.selectionStart)) el.value = text.value\n syncMirror()\n}\n\nfunction onKey(event: KeyboardEvent) {\n if (composing || event.isComposing) return\n if (editingHere.value) {\n // Enter, Tab and Escape finish the edit as in the cell; completion and pointing too\n if (editor.key(event) && !editor.cell.value) sheet.focus()\n return\n }\n if (event.key === 'Escape' || event.key === 'Enter') {\n event.preventDefault()\n sheet.focus()\n }\n}\n\nfunction syncCaret() {\n const el = input.value\n if (el && editingHere.value) editor.moveCaret(el.selectionStart)\n syncMirror()\n}\n\nfunction syncMirror() {\n const el = input.value\n const shown = mirror.value\n if (!el || !shown) return\n shown.scrollLeft = el.scrollLeft\n shown.scrollTop = el.scrollTop\n}\n\nfunction onBlur(event: FocusEvent) {\n // a press on a cell finished the edit already; going elsewhere saves it, as leaving the cell does\n const next = event.relatedTarget as Element | null\n if (!editor.cell.value || !document.hasFocus()) return\n if (next?.closest('.dou-sheet__input, .dou-sheet__assist')) return\n editor.commit()\n}\n\nwatch(text, () => void nextTick(syncMirror))\n\nlet detach: (() => void) | undefined\nonMounted(() => {\n if (input.value) detach = editor.attach(input.value)\n})\nonBeforeUnmount(() => detach?.())\n</script>\n\n<template>\n <div class=\"dou-sheet-formula-bar\">\n <SheetNameBox />\n <span class=\"dou-sheet-formula-bar__mark\" aria-hidden=\"true\"><FunctionIcon /></span>\n <div class=\"dou-sheet-formula-bar__box\" :style=\"`--dou-sheet-bar-lines:${lines}`\">\n <div v-if=\"isFormula\" ref=\"mirror\" class=\"dou-sheet-formula-bar__mirror\" aria-hidden=\"true\">\n <span v-for=\"(part, i) in parts\" :key=\"i\" :class=\"partClass(part)\">{{ part.text }}</span>\n </div>\n <textarea\n ref=\"input\"\n class=\"dou-sheet-formula-bar__input\"\n :class=\"{ 'is-formula': isFormula }\"\n :value=\"text\"\n :aria-label=\"m.formulaBox\"\n :aria-autocomplete=\"editingHere ? 'list' : undefined\"\n :aria-controls=\"editingHere ? editor.helpId : undefined\"\n :readonly=\"sheet.readonly.value\"\n rows=\"1\"\n autocomplete=\"off\"\n autocapitalize=\"off\"\n spellcheck=\"false\"\n @input=\"onInput\"\n @keydown=\"onKey\"\n @keyup=\"syncCaret\"\n @click=\"syncCaret\"\n @select=\"syncCaret\"\n @scroll=\"syncMirror\"\n @compositionstart=\"setComposing(true)\"\n @compositionend=\"setComposing(false)\"\n @blur=\"onBlur\"\n />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EASA,MAAM,QAAQ,SAAS;EACvB,MAAM,EAAE,QAAQ,UAAU,MAAM;EAEhC,MAAM,QAAQ,eAAoC,OAAO;EACzD,MAAM,SAAS,eAA4B,QAAQ;EAInD,MAAM,cAAc,eAAe,CAAC,CAAC,OAAO,KAAK,KAAK;EACtD,MAAM,OAAO,eACX,YAAY,QAAQ,OAAO,KAAK,QAAQ,OAAO,OAAO,MAAM,OAAO,KAAK,CAC1E;EACA,MAAM,QAAQ,eAAgB,YAAY,QAAQ,kBAAkB,KAAK,KAAK,IAAI,CAAC,CAAE;;EAErF,MAAM,YAAY,eAAe,KAAK,MAAM,WAAW,GAAG,CAAC;EAC3D,MAAM,QAAQ,eAAgB,UAAU,QAAQ,aAAa,KAAK,OAAO,MAAM,KAAK,IAAI,CAAC,CAAE;;EAG3F,MAAM,QAAQ,eAAe,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;EAEvE,IAAI,YAAY;EAChB,MAAM,gBAAgB,UAAoB,YAAY;EAEtD,SAAS,QAAQ,OAAc;GAC7B,MAAM,KAAK,MAAM;GACjB,IAAI,CAAC,OAAO,MAAM,GAAG,OAAO,GAAG,cAAc,GAAG,GAAG,QAAQ,KAAK;GAChE,WAAW;EACb;EAEA,SAAS,MAAM,OAAsB;GACnC,IAAI,aAAa,MAAM,aAAa;GACpC,IAAI,YAAY,OAAO;IAErB,IAAI,OAAO,IAAI,KAAK,KAAK,CAAC,OAAO,KAAK,OAAO,MAAM,MAAM;IACzD;GACF;GACA,IAAI,MAAM,QAAQ,YAAY,MAAM,QAAQ,SAAS;IACnD,MAAM,eAAe;IACrB,MAAM,MAAM;GACd;EACF;EAEA,SAAS,YAAY;GACnB,MAAM,KAAK,MAAM;GACjB,IAAI,MAAM,YAAY,OAAO,OAAO,UAAU,GAAG,cAAc;GAC/D,WAAW;EACb;EAEA,SAAS,aAAa;GACpB,MAAM,KAAK,MAAM;GACjB,MAAM,QAAQ,OAAO;GACrB,IAAI,CAAC,MAAM,CAAC,OAAO;GACnB,MAAM,aAAa,GAAG;GACtB,MAAM,YAAY,GAAG;EACvB;EAEA,SAAS,OAAO,OAAmB;GAEjC,MAAM,OAAO,MAAM;GACnB,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,SAAS,SAAS,GAAG;GAChD,IAAI,MAAM,QAAQ,uCAAuC,GAAG;GAC5D,OAAO,OAAO;EAChB;EAEA,MAAM,YAAY,KAAK,SAAS,UAAU,CAAC;EAE3C,IAAI;EACJ,gBAAgB;GACd,IAAI,MAAM,OAAO,SAAS,OAAO,OAAO,MAAM,KAAK;EACrD,CAAC;EACD,sBAAsB,SAAS,CAAC;;GAI9B,OAAAA,UAAA,GAAAC,mBA+BM,OA/BN,YA+BM;IA9BJC,YAAgBC,sBAAA;IAChBC,mBAAoF,QAApF,YAAoF,CAAvBF,YAAgBG,MAAA,YAAA,CAAA,C;IAC7ED,mBA2BM,OAAA;KA3BD,OAAM;KAA8B,OAAKE,eAAA,yBAA2B,MAAA,OAAK;I,IACjE,UAAA,SAAXN,UAAA,GAAAC,mBAEM,OAAA;;KAFoB,SAAA;KAAJ,KAAI;KAAS,OAAM;KAAgC,eAAY;I,KACnFD,UAAA,IAAA,GAAAC,mBAAyFM,UAAA,MAAAC,WAA/D,MAAA,QAAZ,MAAM,MAAC;KAArB,OAAAR,UAAA,GAAAC,mBAAyF,QAAA;MAAvD,KAAK;MAAI,OAAKQ,eAAEJ,MAAA,SAAA,CAAS,CAAC,IAAI,CAAA;KAAM,GAAAK,gBAAA,KAAK,IAAI,GAAA,CAAA;I,kDAEjFN,mBAsBE,YAAA;KArBI,SAAA;KAAJ,KAAI;KACJ,OAAKK,eAAA,CAAC,gCAA8B,EAAA,cACZ,UAAA,MAAS,CAAA,CAAA;KAChC,OAAO,KAAA;KACP,cAAYJ,MAAA,CAAA,CAAC,CAAC;KACd,qBAAmB,YAAA,QAAW,SAAY,KAAA;KAC1C,iBAAe,YAAA,QAAcA,MAAA,MAAA,CAAM,CAAC,SAAS,KAAA;KAC7C,UAAUA,MAAA,KAAA,CAAK,CAAC,SAAS;KAC1B,MAAK;KACL,cAAa;KACb,gBAAe;KACf,YAAW;KACH;KACP,WAAS;KACT,SAAO;KACP,SAAO;KACP,UAAQ;KACR,UAAQ;KACR,oBAAgB,OAAA,OAAA,OAAA,MAAA,WAAE,aAAY,IAAA;KAC9B,kBAAc,OAAA,OAAA,OAAA,MAAA,WAAE,aAAY,KAAA;KACtB"}
@@ -0,0 +1,6 @@
1
+ import sheet_link_vue_vue_type_script_setup_true_lang_default from "./sheet-link.vue_vue_type_script_setup_true_lang.js";
2
+ // src/components/sheet-link.vue
3
+ var sheet_link_default = sheet_link_vue_vue_type_script_setup_true_lang_default;
4
+ export { sheet_link_default as default };
5
+
6
+ //# sourceMappingURL=sheet-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-link.js","names":["_sfc_main"],"sources":["../../src/components/sheet-link.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n DouButton,\n DouInput,\n DouTooltip,\n useFloating,\n useZIndex,\n type VirtualElement,\n} from 'dou-ui'\nimport { LinkIcon, PencilIcon, UnlinkIcon } from '@dou-ui/icons'\nimport { computed, nextTick, ref, useId, useTemplateRef, watch } from 'vue'\nimport { linkTarget } from '../core/link'\nimport type { SheetLinkMessages } from '../locale'\n\n/*\n * A cell's link, under the cell: where it goes, with buttons to open it,\n * change it and take it off; or, while it is being edited, the text and\n * address to write.\n */\n\nconst props = defineProps<{\n /** The cell the link belongs to. */\n anchor: VirtualElement\n link: string\n /** What the cell shows; `null` for a formula's cell, whose text isn't edited here. */\n text: string | null\n editing: boolean\n /** At the grid's foot rather than under the cell, so a finger can still reach the cells around it. */\n docked?: boolean\n /** Whether the link can be changed: the grid is editable and the cell isn't locked. */\n editable: boolean\n /** Whether the cell has a link of its own to take off, not only a formula's. */\n removable: boolean\n messages: SheetLinkMessages\n}>()\n\nconst emit = defineEmits<{\n /** Follows the link: opens a web address, or goes to the cells. */\n open: []\n edit: []\n remove: []\n /** `leaving` when focus left the box for something else. */\n save: [link: string, text: string | null, leaving: boolean]\n cancel: [leaving: boolean]\n}>()\n\nconst box = useTemplateRef<HTMLElement>('box')\ntype Focusable = { focus: () => void; select: () => void }\nconst textInput = useTemplateRef<Focusable>('textInput')\nconst addressInput = useTemplateRef<Focusable>('addressInput')\nconst address = ref(props.link)\nconst text = ref(props.text ?? '')\nconst tried = ref(false)\nconst id = useId()\n\nconst { style, placement } = useFloating(() => props.anchor, box, {\n open: true,\n placement: 'bottom-start',\n offset: 6,\n})\nconst zIndex = useZIndex().next()\n\nconst target = computed(() => linkTarget(props.link))\nconst href = computed(() => (target.value?.kind === 'web' ? target.value.href : undefined))\n/** The address as shown: a web address without its scheme's slashes. */\nconst shown = computed(() => props.link.replace(/^https?:\\/\\//i, '').replace(/\\/$/, ''))\nconst bad = computed(() => !!address.value.trim() && !linkTarget(address.value))\n\nwatch(\n () => props.editing,\n async (editing) => {\n address.value = props.link\n text.value = props.text ?? ''\n tried.value = false\n if (!editing) return\n await nextTick()\n const first = textInput.value ?? addressInput.value\n first?.focus()\n first?.select()\n },\n { immediate: true, flush: 'post' },\n)\n\nconst changed = computed(\n () => address.value !== props.link || (props.text !== null && text.value !== props.text),\n)\nlet done = false\n\nfunction save(leaving = false) {\n if (done) return\n if (bad.value) {\n tried.value = true\n if (leaving) cancel(true)\n return\n }\n done = true\n emit('save', address.value.trim(), props.text === null ? null : text.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') {\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\n/** A web address opens through the grid, so the app can take it over. */\nfunction onOpen(event: MouseEvent) {\n event.preventDefault()\n emit('open')\n}\n</script>\n\n<template>\n <Transition name=\"dou-floating\" appear>\n <div\n ref=\"box\"\n class=\"dou-dropdown dou-floating dou-sheet__link\"\n :class=\"{ 'is-editing': editing, 'is-docked': docked }\"\n :style=\"docked ? undefined : [style, { zIndex }]\"\n :data-placement=\"placement\"\n :role=\"editing ? 'dialog' : undefined\"\n :aria-label=\"editing ? messages.label : undefined\"\n @pointerdown.stop\n @focusout=\"editing && onFocusout($event)\"\n @keydown=\"editing && onKeydown($event)\"\n @contextmenu.stop\n @wheel.stop\n >\n <form v-if=\"editing\" class=\"dou-sheet__link-form\" @submit.prevent=\"save()\">\n <label v-if=\"props.text !== null\" class=\"dou-sheet__link-field\">\n <span class=\"dou-sheet__link-label\">{{ messages.text }}</span>\n <DouInput ref=\"textInput\" v-model=\"text\" size=\"sm\" />\n </label>\n <label class=\"dou-sheet__link-field\">\n <span class=\"dou-sheet__link-label\">{{ messages.address }}</span>\n <DouInput\n ref=\"addressInput\"\n v-model=\"address\"\n size=\"sm\"\n type=\"url\"\n :placeholder=\"messages.addressPlaceholder\"\n :invalid=\"tried && bad\"\n :aria-describedby=\"tried && bad ? `${id}-bad` : undefined\"\n />\n </label>\n <p v-if=\"tried && bad\" :id=\"`${id}-bad`\" class=\"dou-sheet__link-problem\">\n {{ messages.badAddress }}\n </p>\n <!-- pressing a button leaves focus in the box, so it isn't taken as leaving -->\n <div class=\"dou-sheet__link-actions\" @mousedown.prevent>\n <DouButton size=\"sm\" variant=\"ghost\" @click=\"cancel()\">{{ messages.cancel }}</DouButton>\n <DouButton size=\"sm\" variant=\"solid\" native-type=\"submit\">{{ messages.save }}</DouButton>\n </div>\n </form>\n <template v-else>\n <span class=\"dou-sheet__link-icon\" aria-hidden=\"true\"><LinkIcon /></span>\n <!-- a place in the workbook isn't a page: a button, so no router takes the click -->\n <a\n v-if=\"href\"\n class=\"dou-sheet__link-address\"\n :href=\"href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n :title=\"`${messages.open}: ${link}`\"\n @click=\"onOpen\"\n >\n {{ shown }}\n </a>\n <button\n v-else\n type=\"button\"\n class=\"dou-sheet__link-address\"\n :title=\"`${messages.open}: ${link}`\"\n @click=\"emit('open')\"\n >\n {{ shown }}\n </button>\n <div v-if=\"editable\" class=\"dou-sheet__link-buttons\">\n <DouTooltip :content=\"messages.edit\" placement=\"top\">\n <DouButton size=\"sm\" variant=\"ghost\" :aria-label=\"messages.edit\" @click=\"emit('edit')\">\n <PencilIcon />\n </DouButton>\n </DouTooltip>\n <DouTooltip v-if=\"removable\" :content=\"messages.remove\" placement=\"top\">\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.remove\"\n @click=\"emit('remove')\"\n >\n <UnlinkIcon />\n </DouButton>\n </DouTooltip>\n </div>\n </template>\n </div>\n </Transition>\n</template>\n"],"mappings":""}
@@ -0,0 +1,249 @@
1
+ import { linkTarget } from "../core/link.js";
2
+ import { DouButton, DouInput, DouTooltip, useFloating, useZIndex } from "dou-ui";
3
+ import { Fragment, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, openBlock, ref, toDisplayString, unref, useId, useTemplateRef, watch, withCtx, withModifiers } from "vue";
4
+ import { LinkIcon, PencilIcon, UnlinkIcon } from "@dou-ui/icons";
5
+ // src/components/sheet-link.vue?vue&type=script&setup=true&lang.ts
6
+ var _hoisted_1 = [
7
+ "data-placement",
8
+ "role",
9
+ "aria-label"
10
+ ];
11
+ var _hoisted_2 = {
12
+ key: 0,
13
+ class: "dou-sheet__link-field"
14
+ };
15
+ var _hoisted_3 = { class: "dou-sheet__link-label" };
16
+ var _hoisted_4 = { class: "dou-sheet__link-field" };
17
+ var _hoisted_5 = { class: "dou-sheet__link-label" };
18
+ var _hoisted_6 = ["id"];
19
+ var _hoisted_7 = {
20
+ class: "dou-sheet__link-icon",
21
+ "aria-hidden": "true"
22
+ };
23
+ var _hoisted_8 = ["href", "title"];
24
+ var _hoisted_9 = ["title"];
25
+ var _hoisted_10 = {
26
+ key: 2,
27
+ class: "dou-sheet__link-buttons"
28
+ };
29
+ var sheet_link_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
30
+ __name: "sheet-link",
31
+ props: {
32
+ anchor: {},
33
+ link: {},
34
+ text: {},
35
+ editing: { type: Boolean },
36
+ docked: { type: Boolean },
37
+ editable: { type: Boolean },
38
+ removable: { type: Boolean },
39
+ messages: {}
40
+ },
41
+ emits: [
42
+ "open",
43
+ "edit",
44
+ "remove",
45
+ "save",
46
+ "cancel"
47
+ ],
48
+ setup(__props, { emit: __emit }) {
49
+ const props = __props;
50
+ const emit = __emit;
51
+ const box = useTemplateRef("box");
52
+ const textInput = useTemplateRef("textInput");
53
+ const addressInput = useTemplateRef("addressInput");
54
+ const address = ref(props.link);
55
+ const text = ref(props.text ?? "");
56
+ const tried = ref(false);
57
+ const id = useId();
58
+ const { style, placement } = useFloating(() => props.anchor, box, {
59
+ open: true,
60
+ placement: "bottom-start",
61
+ offset: 6
62
+ });
63
+ const zIndex = useZIndex().next();
64
+ const target = computed(() => linkTarget(props.link));
65
+ const href = computed(() => target.value?.kind === "web" ? target.value.href : void 0);
66
+ /** The address as shown: a web address without its scheme's slashes. */
67
+ const shown = computed(() => props.link.replace(/^https?:\/\//i, "").replace(/\/$/, ""));
68
+ const bad = computed(() => !!address.value.trim() && !linkTarget(address.value));
69
+ watch(() => props.editing, async (editing) => {
70
+ address.value = props.link;
71
+ text.value = props.text ?? "";
72
+ tried.value = false;
73
+ if (!editing) return;
74
+ await nextTick();
75
+ const first = textInput.value ?? addressInput.value;
76
+ first?.focus();
77
+ first?.select();
78
+ }, {
79
+ immediate: true,
80
+ flush: "post"
81
+ });
82
+ const changed = computed(() => address.value !== props.link || props.text !== null && text.value !== props.text);
83
+ let done = false;
84
+ function save(leaving = false) {
85
+ if (done) return;
86
+ if (bad.value) {
87
+ tried.value = true;
88
+ if (leaving) cancel(true);
89
+ return;
90
+ }
91
+ done = true;
92
+ emit("save", address.value.trim(), props.text === null ? null : text.value, leaving);
93
+ }
94
+ function cancel(leaving = false) {
95
+ if (done) return;
96
+ done = true;
97
+ emit("cancel", leaving);
98
+ }
99
+ function onKeydown(event) {
100
+ event.stopPropagation();
101
+ if (event.isComposing) return;
102
+ if (event.key === "Escape") {
103
+ event.preventDefault();
104
+ cancel();
105
+ } else if (event.key === "Enter") {
106
+ event.preventDefault();
107
+ save();
108
+ }
109
+ }
110
+ /** Focus leaving the box keeps what was written, as clicking another cell does. */
111
+ function onFocusout(event) {
112
+ const next = event.relatedTarget;
113
+ if (next instanceof Node && box.value?.contains(next)) return;
114
+ if (changed.value) save(true);
115
+ else cancel(true);
116
+ }
117
+ /** A web address opens through the grid, so the app can take it over. */
118
+ function onOpen(event) {
119
+ event.preventDefault();
120
+ emit("open");
121
+ }
122
+ return (_ctx, _cache) => {
123
+ return openBlock(), createBlock(Transition, {
124
+ name: "dou-floating",
125
+ appear: ""
126
+ }, {
127
+ default: withCtx(() => [createElementVNode("div", {
128
+ ref_key: "box",
129
+ ref: box,
130
+ class: normalizeClass(["dou-dropdown dou-floating dou-sheet__link", {
131
+ "is-editing": __props.editing,
132
+ "is-docked": __props.docked
133
+ }]),
134
+ style: normalizeStyle(__props.docked ? void 0 : [unref(style), { zIndex: unref(zIndex) }]),
135
+ "data-placement": unref(placement),
136
+ role: __props.editing ? "dialog" : void 0,
137
+ "aria-label": __props.editing ? __props.messages.label : void 0,
138
+ onPointerdown: _cache[8] || (_cache[8] = withModifiers(() => {}, ["stop"])),
139
+ onFocusout: _cache[9] || (_cache[9] = ($event) => __props.editing && onFocusout($event)),
140
+ onKeydown: _cache[10] || (_cache[10] = ($event) => __props.editing && onKeydown($event)),
141
+ onContextmenu: _cache[11] || (_cache[11] = withModifiers(() => {}, ["stop"])),
142
+ onWheel: _cache[12] || (_cache[12] = withModifiers(() => {}, ["stop"]))
143
+ }, [__props.editing ? (openBlock(), createElementBlock("form", {
144
+ key: 0,
145
+ class: "dou-sheet__link-form",
146
+ onSubmit: _cache[4] || (_cache[4] = withModifiers(($event) => save(), ["prevent"]))
147
+ }, [
148
+ props.text !== null ? (openBlock(), createElementBlock("label", _hoisted_2, [createElementVNode("span", _hoisted_3, toDisplayString(__props.messages.text), 1), createVNode(unref(DouInput), {
149
+ ref_key: "textInput",
150
+ ref: textInput,
151
+ modelValue: text.value,
152
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => text.value = $event),
153
+ size: "sm"
154
+ }, null, 8, ["modelValue"])])) : createCommentVNode("", true),
155
+ createElementVNode("label", _hoisted_4, [createElementVNode("span", _hoisted_5, toDisplayString(__props.messages.address), 1), createVNode(unref(DouInput), {
156
+ ref_key: "addressInput",
157
+ ref: addressInput,
158
+ modelValue: address.value,
159
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => address.value = $event),
160
+ size: "sm",
161
+ type: "url",
162
+ placeholder: __props.messages.addressPlaceholder,
163
+ invalid: tried.value && bad.value,
164
+ "aria-describedby": tried.value && bad.value ? `${unref(id)}-bad` : void 0
165
+ }, null, 8, [
166
+ "modelValue",
167
+ "placeholder",
168
+ "invalid",
169
+ "aria-describedby"
170
+ ])]),
171
+ tried.value && bad.value ? (openBlock(), createElementBlock("p", {
172
+ key: 1,
173
+ id: `${unref(id)}-bad`,
174
+ class: "dou-sheet__link-problem"
175
+ }, toDisplayString(__props.messages.badAddress), 9, _hoisted_6)) : createCommentVNode("", true),
176
+ createElementVNode("div", {
177
+ class: "dou-sheet__link-actions",
178
+ onMousedown: _cache[3] || (_cache[3] = withModifiers(() => {}, ["prevent"]))
179
+ }, [createVNode(unref(DouButton), {
180
+ size: "sm",
181
+ variant: "ghost",
182
+ onClick: _cache[2] || (_cache[2] = ($event) => cancel())
183
+ }, {
184
+ default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.cancel), 1)]),
185
+ _: 1
186
+ }), createVNode(unref(DouButton), {
187
+ size: "sm",
188
+ variant: "solid",
189
+ "native-type": "submit"
190
+ }, {
191
+ default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.save), 1)]),
192
+ _: 1
193
+ })], 32)
194
+ ], 32)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
195
+ createElementVNode("span", _hoisted_7, [createVNode(unref(LinkIcon))]),
196
+ href.value ? (openBlock(), createElementBlock("a", {
197
+ key: 0,
198
+ class: "dou-sheet__link-address",
199
+ href: href.value,
200
+ target: "_blank",
201
+ rel: "noopener noreferrer",
202
+ title: `${__props.messages.open}: ${__props.link}`,
203
+ onClick: onOpen
204
+ }, toDisplayString(shown.value), 9, _hoisted_8)) : (openBlock(), createElementBlock("button", {
205
+ key: 1,
206
+ type: "button",
207
+ class: "dou-sheet__link-address",
208
+ title: `${__props.messages.open}: ${__props.link}`,
209
+ onClick: _cache[5] || (_cache[5] = ($event) => emit("open"))
210
+ }, toDisplayString(shown.value), 9, _hoisted_9)),
211
+ __props.editable ? (openBlock(), createElementBlock("div", _hoisted_10, [createVNode(unref(DouTooltip), {
212
+ content: __props.messages.edit,
213
+ placement: "top"
214
+ }, {
215
+ default: withCtx(() => [createVNode(unref(DouButton), {
216
+ size: "sm",
217
+ variant: "ghost",
218
+ "aria-label": __props.messages.edit,
219
+ onClick: _cache[6] || (_cache[6] = ($event) => emit("edit"))
220
+ }, {
221
+ default: withCtx(() => [createVNode(unref(PencilIcon))]),
222
+ _: 1
223
+ }, 8, ["aria-label"])]),
224
+ _: 1
225
+ }, 8, ["content"]), __props.removable ? (openBlock(), createBlock(unref(DouTooltip), {
226
+ key: 0,
227
+ content: __props.messages.remove,
228
+ placement: "top"
229
+ }, {
230
+ default: withCtx(() => [createVNode(unref(DouButton), {
231
+ size: "sm",
232
+ variant: "ghost",
233
+ "aria-label": __props.messages.remove,
234
+ onClick: _cache[7] || (_cache[7] = ($event) => emit("remove"))
235
+ }, {
236
+ default: withCtx(() => [createVNode(unref(UnlinkIcon))]),
237
+ _: 1
238
+ }, 8, ["aria-label"])]),
239
+ _: 1
240
+ }, 8, ["content"])) : createCommentVNode("", true)])) : createCommentVNode("", true)
241
+ ], 64))], 46, _hoisted_1)]),
242
+ _: 1
243
+ });
244
+ };
245
+ }
246
+ });
247
+ export { sheet_link_vue_vue_type_script_setup_true_lang_default as default };
248
+
249
+ //# sourceMappingURL=sheet-link.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-link.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_Transition","_withCtx","_createElementVNode","_normalizeClass","_normalizeStyle","_unref","_withModifiers","_createElementBlock","_toDisplayString","_createVNode","_createCommentVNode","_createTextVNode","_Fragment"],"sources":["../../src/components/sheet-link.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n DouButton,\n DouInput,\n DouTooltip,\n useFloating,\n useZIndex,\n type VirtualElement,\n} from 'dou-ui'\nimport { LinkIcon, PencilIcon, UnlinkIcon } from '@dou-ui/icons'\nimport { computed, nextTick, ref, useId, useTemplateRef, watch } from 'vue'\nimport { linkTarget } from '../core/link'\nimport type { SheetLinkMessages } from '../locale'\n\n/*\n * A cell's link, under the cell: where it goes, with buttons to open it,\n * change it and take it off; or, while it is being edited, the text and\n * address to write.\n */\n\nconst props = defineProps<{\n /** The cell the link belongs to. */\n anchor: VirtualElement\n link: string\n /** What the cell shows; `null` for a formula's cell, whose text isn't edited here. */\n text: string | null\n editing: boolean\n /** At the grid's foot rather than under the cell, so a finger can still reach the cells around it. */\n docked?: boolean\n /** Whether the link can be changed: the grid is editable and the cell isn't locked. */\n editable: boolean\n /** Whether the cell has a link of its own to take off, not only a formula's. */\n removable: boolean\n messages: SheetLinkMessages\n}>()\n\nconst emit = defineEmits<{\n /** Follows the link: opens a web address, or goes to the cells. */\n open: []\n edit: []\n remove: []\n /** `leaving` when focus left the box for something else. */\n save: [link: string, text: string | null, leaving: boolean]\n cancel: [leaving: boolean]\n}>()\n\nconst box = useTemplateRef<HTMLElement>('box')\ntype Focusable = { focus: () => void; select: () => void }\nconst textInput = useTemplateRef<Focusable>('textInput')\nconst addressInput = useTemplateRef<Focusable>('addressInput')\nconst address = ref(props.link)\nconst text = ref(props.text ?? '')\nconst tried = ref(false)\nconst id = useId()\n\nconst { style, placement } = useFloating(() => props.anchor, box, {\n open: true,\n placement: 'bottom-start',\n offset: 6,\n})\nconst zIndex = useZIndex().next()\n\nconst target = computed(() => linkTarget(props.link))\nconst href = computed(() => (target.value?.kind === 'web' ? target.value.href : undefined))\n/** The address as shown: a web address without its scheme's slashes. */\nconst shown = computed(() => props.link.replace(/^https?:\\/\\//i, '').replace(/\\/$/, ''))\nconst bad = computed(() => !!address.value.trim() && !linkTarget(address.value))\n\nwatch(\n () => props.editing,\n async (editing) => {\n address.value = props.link\n text.value = props.text ?? ''\n tried.value = false\n if (!editing) return\n await nextTick()\n const first = textInput.value ?? addressInput.value\n first?.focus()\n first?.select()\n },\n { immediate: true, flush: 'post' },\n)\n\nconst changed = computed(\n () => address.value !== props.link || (props.text !== null && text.value !== props.text),\n)\nlet done = false\n\nfunction save(leaving = false) {\n if (done) return\n if (bad.value) {\n tried.value = true\n if (leaving) cancel(true)\n return\n }\n done = true\n emit('save', address.value.trim(), props.text === null ? null : text.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') {\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\n/** A web address opens through the grid, so the app can take it over. */\nfunction onOpen(event: MouseEvent) {\n event.preventDefault()\n emit('open')\n}\n</script>\n\n<template>\n <Transition name=\"dou-floating\" appear>\n <div\n ref=\"box\"\n class=\"dou-dropdown dou-floating dou-sheet__link\"\n :class=\"{ 'is-editing': editing, 'is-docked': docked }\"\n :style=\"docked ? undefined : [style, { zIndex }]\"\n :data-placement=\"placement\"\n :role=\"editing ? 'dialog' : undefined\"\n :aria-label=\"editing ? messages.label : undefined\"\n @pointerdown.stop\n @focusout=\"editing && onFocusout($event)\"\n @keydown=\"editing && onKeydown($event)\"\n @contextmenu.stop\n @wheel.stop\n >\n <form v-if=\"editing\" class=\"dou-sheet__link-form\" @submit.prevent=\"save()\">\n <label v-if=\"props.text !== null\" class=\"dou-sheet__link-field\">\n <span class=\"dou-sheet__link-label\">{{ messages.text }}</span>\n <DouInput ref=\"textInput\" v-model=\"text\" size=\"sm\" />\n </label>\n <label class=\"dou-sheet__link-field\">\n <span class=\"dou-sheet__link-label\">{{ messages.address }}</span>\n <DouInput\n ref=\"addressInput\"\n v-model=\"address\"\n size=\"sm\"\n type=\"url\"\n :placeholder=\"messages.addressPlaceholder\"\n :invalid=\"tried && bad\"\n :aria-describedby=\"tried && bad ? `${id}-bad` : undefined\"\n />\n </label>\n <p v-if=\"tried && bad\" :id=\"`${id}-bad`\" class=\"dou-sheet__link-problem\">\n {{ messages.badAddress }}\n </p>\n <!-- pressing a button leaves focus in the box, so it isn't taken as leaving -->\n <div class=\"dou-sheet__link-actions\" @mousedown.prevent>\n <DouButton size=\"sm\" variant=\"ghost\" @click=\"cancel()\">{{ messages.cancel }}</DouButton>\n <DouButton size=\"sm\" variant=\"solid\" native-type=\"submit\">{{ messages.save }}</DouButton>\n </div>\n </form>\n <template v-else>\n <span class=\"dou-sheet__link-icon\" aria-hidden=\"true\"><LinkIcon /></span>\n <!-- a place in the workbook isn't a page: a button, so no router takes the click -->\n <a\n v-if=\"href\"\n class=\"dou-sheet__link-address\"\n :href=\"href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n :title=\"`${messages.open}: ${link}`\"\n @click=\"onOpen\"\n >\n {{ shown }}\n </a>\n <button\n v-else\n type=\"button\"\n class=\"dou-sheet__link-address\"\n :title=\"`${messages.open}: ${link}`\"\n @click=\"emit('open')\"\n >\n {{ shown }}\n </button>\n <div v-if=\"editable\" class=\"dou-sheet__link-buttons\">\n <DouTooltip :content=\"messages.edit\" placement=\"top\">\n <DouButton size=\"sm\" variant=\"ghost\" :aria-label=\"messages.edit\" @click=\"emit('edit')\">\n <PencilIcon />\n </DouButton>\n </DouTooltip>\n <DouTooltip v-if=\"removable\" :content=\"messages.remove\" placement=\"top\">\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.remove\"\n @click=\"emit('remove')\"\n >\n <UnlinkIcon />\n </DouButton>\n </DouTooltip>\n </div>\n </template>\n </div>\n </Transition>\n</template>\n"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import sheet_menu_vue_vue_type_script_setup_true_lang_default from "./sheet-menu.vue_vue_type_script_setup_true_lang.js";
2
+ // src/components/sheet-menu.vue
3
+ var sheet_menu_default = sheet_menu_vue_vue_type_script_setup_true_lang_default;
4
+ export { sheet_menu_default as default };
5
+
6
+ //# sourceMappingURL=sheet-menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-menu.js","names":["_sfc_main"],"sources":["../../src/components/sheet-menu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouContextMenu, DouDropdownItem, DouDropdownSub, DouIcon } from 'dou-ui'\nimport { onMounted, ref, useTemplateRef } from 'vue'\nimport type { SheetMenuItem } from '../types'\n\ndefineProps<{ items: SheetMenuItem[] }>()\nconst emit = defineEmits<{ select: [key: unknown] }>()\nconst open = defineModel<boolean>('open', { default: false })\n\n// shortcuts mean nothing without a keyboard\n// Read once mounted, so server-rendered markup matches the first render.\nconst coarse = ref(false)\nonMounted(() => {\n coarse.value = typeof matchMedia !== 'undefined' && matchMedia('(pointer: coarse)').matches\n})\n\nconst menu = useTemplateRef<InstanceType<typeof DouContextMenu>>('menu')\n\ndefineExpose({\n open: (x: number, y: number) => menu.value?.open(x, y),\n close: () => menu.value?.close(),\n})\n</script>\n\n<template>\n <!-- The grid opens the menu itself; the empty anchor only gives it a place in the page. -->\n <DouContextMenu ref=\"menu\" v-model:open=\"open\" @select=\"emit('select', $event)\">\n <span class=\"dou-sheet__menu-anchor\" aria-hidden=\"true\" />\n <template #menu>\n <template v-for=\"item in items\" :key=\"item.key\">\n <DouDropdownSub\n v-if=\"item.children?.length\"\n :title=\"item.label\"\n :disabled=\"item.disabled\"\n :divided=\"item.divided\"\n >\n <template v-if=\"item.icon\" #prefix>\n <DouIcon><component :is=\"item.icon\" /></DouIcon>\n </template>\n <DouDropdownItem\n v-for=\"child in item.children\"\n :key=\"child.key\"\n :value=\"child.key\"\n :disabled=\"child.disabled\"\n :tone=\"child.tone\"\n :divided=\"child.divided\"\n :shortcut=\"coarse ? undefined : child.shortcut\"\n >\n <template v-if=\"child.icon\" #prefix>\n <DouIcon><component :is=\"child.icon\" /></DouIcon>\n </template>\n {{ child.label }}\n </DouDropdownItem>\n </DouDropdownSub>\n <DouDropdownItem\n v-else\n :value=\"item.key\"\n :disabled=\"item.disabled\"\n :tone=\"item.tone\"\n :divided=\"item.divided\"\n :shortcut=\"coarse ? undefined : item.shortcut\"\n >\n <template v-if=\"item.icon\" #prefix>\n <DouIcon><component :is=\"item.icon\" /></DouIcon>\n </template>\n {{ item.label }}\n </DouDropdownItem>\n </template>\n </template>\n </DouContextMenu>\n</template>\n"],"mappings":""}
@@ -0,0 +1,115 @@
1
+ import { DouContextMenu, DouDropdownItem, DouDropdownSub, DouIcon } from "dou-ui";
2
+ import { Fragment, createBlock, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, mergeModels, onMounted, openBlock, ref, renderList, resolveDynamicComponent, toDisplayString, unref, useModel, useTemplateRef, withCtx } from "vue";
3
+ // src/components/sheet-menu.vue?vue&type=script&setup=true&lang.ts
4
+ var sheet_menu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
5
+ __name: "sheet-menu",
6
+ props: /*@__PURE__*/ mergeModels({ items: {} }, {
7
+ "open": {
8
+ type: Boolean,
9
+ default: false
10
+ },
11
+ "openModifiers": {}
12
+ }),
13
+ emits: /*@__PURE__*/ mergeModels(["select"], ["update:open"]),
14
+ setup(__props, { expose: __expose, emit: __emit }) {
15
+ const emit = __emit;
16
+ const open = useModel(__props, "open");
17
+ const coarse = ref(false);
18
+ onMounted(() => {
19
+ coarse.value = typeof matchMedia !== "undefined" && matchMedia("(pointer: coarse)").matches;
20
+ });
21
+ const menu = useTemplateRef("menu");
22
+ __expose({
23
+ open: (x, y) => menu.value?.open(x, y),
24
+ close: () => menu.value?.close()
25
+ });
26
+ return (_ctx, _cache) => {
27
+ return openBlock(), createBlock(unref(DouContextMenu), {
28
+ ref_key: "menu",
29
+ ref: menu,
30
+ open: open.value,
31
+ "onUpdate:open": _cache[0] || (_cache[0] = ($event) => open.value = $event),
32
+ onSelect: _cache[1] || (_cache[1] = ($event) => emit("select", $event))
33
+ }, {
34
+ menu: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item) => {
35
+ return openBlock(), createElementBlock(Fragment, { key: item.key }, [item.children?.length ? (openBlock(), createBlock(unref(DouDropdownSub), {
36
+ key: 0,
37
+ title: item.label,
38
+ disabled: item.disabled,
39
+ divided: item.divided
40
+ }, createSlots({
41
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(item.children, (child) => {
42
+ return openBlock(), createBlock(unref(DouDropdownItem), {
43
+ key: child.key,
44
+ value: child.key,
45
+ disabled: child.disabled,
46
+ tone: child.tone,
47
+ divided: child.divided,
48
+ shortcut: coarse.value ? void 0 : child.shortcut
49
+ }, createSlots({
50
+ default: withCtx(() => [createTextVNode(" " + toDisplayString(child.label), 1)]),
51
+ _: 2
52
+ }, [child.icon ? {
53
+ name: "prefix",
54
+ fn: withCtx(() => [createVNode(unref(DouIcon), null, {
55
+ default: withCtx(() => [(openBlock(), createBlock(resolveDynamicComponent(child.icon)))]),
56
+ _: 2
57
+ }, 1024)]),
58
+ key: "0"
59
+ } : void 0]), 1032, [
60
+ "value",
61
+ "disabled",
62
+ "tone",
63
+ "divided",
64
+ "shortcut"
65
+ ]);
66
+ }), 128))]),
67
+ _: 2
68
+ }, [item.icon ? {
69
+ name: "prefix",
70
+ fn: withCtx(() => [createVNode(unref(DouIcon), null, {
71
+ default: withCtx(() => [(openBlock(), createBlock(resolveDynamicComponent(item.icon)))]),
72
+ _: 2
73
+ }, 1024)]),
74
+ key: "0"
75
+ } : void 0]), 1032, [
76
+ "title",
77
+ "disabled",
78
+ "divided"
79
+ ])) : (openBlock(), createBlock(unref(DouDropdownItem), {
80
+ key: 1,
81
+ value: item.key,
82
+ disabled: item.disabled,
83
+ tone: item.tone,
84
+ divided: item.divided,
85
+ shortcut: coarse.value ? void 0 : item.shortcut
86
+ }, createSlots({
87
+ default: withCtx(() => [createTextVNode(" " + toDisplayString(item.label), 1)]),
88
+ _: 2
89
+ }, [item.icon ? {
90
+ name: "prefix",
91
+ fn: withCtx(() => [createVNode(unref(DouIcon), null, {
92
+ default: withCtx(() => [(openBlock(), createBlock(resolveDynamicComponent(item.icon)))]),
93
+ _: 2
94
+ }, 1024)]),
95
+ key: "0"
96
+ } : void 0]), 1032, [
97
+ "value",
98
+ "disabled",
99
+ "tone",
100
+ "divided",
101
+ "shortcut"
102
+ ]))], 64);
103
+ }), 128))]),
104
+ default: withCtx(() => [_cache[2] || (_cache[2] = createElementVNode("span", {
105
+ class: "dou-sheet__menu-anchor",
106
+ "aria-hidden": "true"
107
+ }, null, -1))]),
108
+ _: 1
109
+ }, 8, ["open"]);
110
+ };
111
+ }
112
+ });
113
+ export { sheet_menu_vue_vue_type_script_setup_true_lang_default as default };
114
+
115
+ //# sourceMappingURL=sheet-menu.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-menu.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createBlock","_unref","_withCtx","_createElementBlock","_Fragment","_renderList","_createSlots","_createTextVNode","_toDisplayString","_createVNode","_resolveDynamicComponent","_createElementVNode"],"sources":["../../src/components/sheet-menu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouContextMenu, DouDropdownItem, DouDropdownSub, DouIcon } from 'dou-ui'\nimport { onMounted, ref, useTemplateRef } from 'vue'\nimport type { SheetMenuItem } from '../types'\n\ndefineProps<{ items: SheetMenuItem[] }>()\nconst emit = defineEmits<{ select: [key: unknown] }>()\nconst open = defineModel<boolean>('open', { default: false })\n\n// shortcuts mean nothing without a keyboard\n// Read once mounted, so server-rendered markup matches the first render.\nconst coarse = ref(false)\nonMounted(() => {\n coarse.value = typeof matchMedia !== 'undefined' && matchMedia('(pointer: coarse)').matches\n})\n\nconst menu = useTemplateRef<InstanceType<typeof DouContextMenu>>('menu')\n\ndefineExpose({\n open: (x: number, y: number) => menu.value?.open(x, y),\n close: () => menu.value?.close(),\n})\n</script>\n\n<template>\n <!-- The grid opens the menu itself; the empty anchor only gives it a place in the page. -->\n <DouContextMenu ref=\"menu\" v-model:open=\"open\" @select=\"emit('select', $event)\">\n <span class=\"dou-sheet__menu-anchor\" aria-hidden=\"true\" />\n <template #menu>\n <template v-for=\"item in items\" :key=\"item.key\">\n <DouDropdownSub\n v-if=\"item.children?.length\"\n :title=\"item.label\"\n :disabled=\"item.disabled\"\n :divided=\"item.divided\"\n >\n <template v-if=\"item.icon\" #prefix>\n <DouIcon><component :is=\"item.icon\" /></DouIcon>\n </template>\n <DouDropdownItem\n v-for=\"child in item.children\"\n :key=\"child.key\"\n :value=\"child.key\"\n :disabled=\"child.disabled\"\n :tone=\"child.tone\"\n :divided=\"child.divided\"\n :shortcut=\"coarse ? undefined : child.shortcut\"\n >\n <template v-if=\"child.icon\" #prefix>\n <DouIcon><component :is=\"child.icon\" /></DouIcon>\n </template>\n {{ child.label }}\n </DouDropdownItem>\n </DouDropdownSub>\n <DouDropdownItem\n v-else\n :value=\"item.key\"\n :disabled=\"item.disabled\"\n :tone=\"item.tone\"\n :divided=\"item.divided\"\n :shortcut=\"coarse ? undefined : item.shortcut\"\n >\n <template v-if=\"item.icon\" #prefix>\n <DouIcon><component :is=\"item.icon\" /></DouIcon>\n </template>\n {{ item.label }}\n </DouDropdownItem>\n </template>\n </template>\n </DouContextMenu>\n</template>\n"],"mappings":";;;;;;;;;;;;;;EAMA,MAAM,OAAO;EACb,MAAM,OAAOA,SAAoB,SAAC,MAA0B;EAI5D,MAAM,SAAS,IAAI,KAAK;EACxB,gBAAgB;GACd,OAAO,QAAQ,OAAO,eAAe,eAAe,WAAW,mBAAmB,CAAC,CAAC;EACtF,CAAC;EAED,MAAM,OAAO,eAAoD,MAAM;EAEvE,SAAa;GACX,OAAO,GAAW,MAAc,KAAK,OAAO,KAAK,GAAG,CAAC;GACrD,aAAa,KAAK,OAAO,MAAM;EACjC,CAAC;;GAKC,OAAAC,UAAA,GAAAC,YA2CiBC,MAAA,cAAA,GAAA;IA3CG,SAAA;IAAJ,KAAI;IAAe,MAAM,KAAA;IAAA,iBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,KAAI,QAAA;IAAG,UAAM,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,UAAW,MAAM;;IAEhE,MAAIC,cACkB,EAA/BH,UAAA,IAAA,GAAAI,mBAsCWC,UAAA,MAAAC,WAtCc,QAAA,QAAR,SAAI;K,mDAAiB,KAAA,KAAK,I,IAEjC,KAAK,UAAU,UADvBN,UAAA,GAAAC,YAuBiBC,MAAA,cAAA,GAAA;;MArBd,OAAO,KAAK;MACZ,UAAU,KAAK;MACf,SAAS,KAAK;;MAMb,SAAAC,cAA8B,EADhCH,UAAA,IAAA,GAAAI,mBAakBC,UAAA,MAAAC,WAZA,KAAK,WAAd,UAAK;OADd,OAAAN,UAAA,GAAAC,YAakBC,MAAA,eAAA,GAAA;QAXf,KAAK,MAAM;QACX,OAAO,MAAM;QACb,UAAU,MAAM;QAChB,MAAM,MAAM;QACZ,SAAS,MAAM;QACf,UAAU,OAAA,QAAS,KAAA,IAAY,MAAM;;QAI3B,SAAAC,cACX,CADWK,gBAAA,MACXC,gBAAG,MAAM,KAAK,GAAA,CAAA,C;;O,IAHE,MAAM,O;QAAO,MAAA;QAC3B,IAAAN,cAAiD,CAAjDO,YAAiDR,MAAA,OAAA,GAAA,MAAA;SAAxC,SAAAC,cAA8B,EAA9BH,UAAA,GAAAC,YAA8BU,wBAAd,MAAM,IAAI,CAAA,E;;;;;;;;;;;;;K,IAbvB,KAAK,O;MAAO,MAAA;MAC1B,IAAAR,cAAgD,CAAhDO,YAAgDR,MAAA,OAAA,GAAA,MAAA;OAAvC,SAAAC,cAA6B,EAA7BH,UAAA,GAAAC,YAA6BU,wBAAb,KAAK,IAAI,CAAA,E;;;;;;;;K,OAiBtCX,UAAA,GAAAC,YAYkBC,MAAA,eAAA,GAAA;;MAVf,OAAO,KAAK;MACZ,UAAU,KAAK;MACf,MAAM,KAAK;MACX,SAAS,KAAK;MACd,UAAU,OAAA,QAAS,KAAA,IAAY,KAAK;;MAI1B,SAAAC,cACX,CADWK,gBAAA,MACXC,gBAAG,KAAK,KAAK,GAAA,CAAA,C;;K,IAHG,KAAK,O;MAAO,MAAA;MAC1B,IAAAN,cAAgD,CAAhDO,YAAgDR,MAAA,OAAA,GAAA,MAAA;OAAvC,SAAAC,cAA6B,EAA7BH,UAAA,GAAAC,YAA6BU,wBAAb,KAAK,IAAI,CAAA,E;;;;;;;;;;;;IApC1C,SAAAR,cAA0D,CAA1D,OAAA,OAAA,OAAA,KAAAS,mBAA0D,QAAA;KAApD,OAAM;KAAyB,eAAY"}
@@ -0,0 +1,6 @@
1
+ import sheet_name_box_vue_vue_type_script_setup_true_lang_default from "./sheet-name-box.vue_vue_type_script_setup_true_lang.js";
2
+ // src/components/sheet-name-box.vue
3
+ var sheet_name_box_default = sheet_name_box_vue_vue_type_script_setup_true_lang_default;
4
+ export { sheet_name_box_default as default };
5
+
6
+ //# sourceMappingURL=sheet-name-box.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-name-box.js","names":["_sfc_main"],"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":""}