@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.
- package/LICENSE +21 -0
- package/README.md +10 -2
- package/dist/cell-types.js +20 -0
- package/dist/cell-types.js.map +1 -0
- package/dist/code/code-formula-bar.js +6 -0
- package/dist/code/code-formula-bar.js.map +1 -0
- package/dist/code/code-formula-bar.vue_vue_type_script_setup_true_lang.js +192 -0
- package/dist/code/code-formula-bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/code/index.js +12 -0
- package/dist/code/index.js.map +1 -0
- package/dist/code/language.js +51 -0
- package/dist/code/language.js.map +1 -0
- package/dist/code/style.d.ts +1 -0
- package/dist/code/style.js +2 -0
- package/dist/collaboration/anchor.js +143 -0
- package/dist/collaboration/anchor.js.map +1 -0
- package/dist/collaboration/index.js +770 -0
- package/dist/collaboration/index.js.map +1 -0
- package/dist/collaboration/peers.js +87 -0
- package/dist/collaboration/peers.js.map +1 -0
- package/dist/collaboration/shared.js +450 -0
- package/dist/collaboration/shared.js.map +1 -0
- package/dist/components/cell-panel.js +6 -0
- package/dist/components/cell-panel.js.map +1 -0
- package/dist/components/cell-panel.vue_vue_type_script_setup_true_lang.js +70 -0
- package/dist/components/cell-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/cell-renders.js +40 -0
- package/dist/components/cell-renders.js.map +1 -0
- package/dist/components/date-panel.js +6 -0
- package/dist/components/date-panel.js.map +1 -0
- package/dist/components/date-panel.vue_vue_type_script_setup_true_lang.js +48 -0
- package/dist/components/date-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/filter-panel.js +6 -0
- package/dist/components/filter-panel.js.map +1 -0
- package/dist/components/filter-panel.vue_vue_type_script_setup_true_lang.js +259 -0
- package/dist/components/filter-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/format-dialog.js +6 -0
- package/dist/components/format-dialog.js.map +1 -0
- package/dist/components/format-dialog.vue_vue_type_script_setup_true_lang.js +432 -0
- package/dist/components/format-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/format-list.js +6 -0
- package/dist/components/format-list.js.map +1 -0
- package/dist/components/format-list.vue_vue_type_script_setup_true_lang.js +187 -0
- package/dist/components/format-list.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/format-presets.js +97 -0
- package/dist/components/format-presets.js.map +1 -0
- package/dist/components/option-panel.js +6 -0
- package/dist/components/option-panel.js.map +1 -0
- package/dist/components/option-panel.vue_vue_type_script_setup_true_lang.js +117 -0
- package/dist/components/option-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/sheet-comment.js +6 -0
- package/dist/components/sheet-comment.js.map +1 -0
- package/dist/components/sheet-comment.vue_vue_type_script_setup_true_lang.js +104 -0
- package/dist/components/sheet-comment.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/sheet-formula-bar.js +6 -0
- package/dist/components/sheet-formula-bar.js.map +1 -0
- package/dist/components/sheet-formula-bar.vue_vue_type_script_setup_true_lang.js +124 -0
- package/dist/components/sheet-formula-bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/sheet-link.js +6 -0
- package/dist/components/sheet-link.js.map +1 -0
- package/dist/components/sheet-link.vue_vue_type_script_setup_true_lang.js +249 -0
- package/dist/components/sheet-link.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/sheet-menu.js +6 -0
- package/dist/components/sheet-menu.js.map +1 -0
- package/dist/components/sheet-menu.vue_vue_type_script_setup_true_lang.js +115 -0
- package/dist/components/sheet-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/sheet-name-box.js +6 -0
- package/dist/components/sheet-name-box.js.map +1 -0
- package/dist/components/sheet-name-box.vue_vue_type_script_setup_true_lang.js +91 -0
- package/dist/components/sheet-name-box.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/sheet-note.js +6 -0
- package/dist/components/sheet-note.js.map +1 -0
- package/dist/components/sheet-note.vue_vue_type_script_setup_true_lang.js +146 -0
- package/dist/components/sheet-note.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/sheet-outline.js +6 -0
- package/dist/components/sheet-outline.js.map +1 -0
- package/dist/components/sheet-outline.vue_vue_type_script_setup_true_lang.js +237 -0
- package/dist/components/sheet-outline.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/sheet-tabs.js +6 -0
- package/dist/components/sheet-tabs.js.map +1 -0
- package/dist/components/sheet-tabs.vue_vue_type_script_setup_true_lang.js +487 -0
- package/dist/components/sheet-tabs.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/sheet-toolbar.js +6 -0
- package/dist/components/sheet-toolbar.js.map +1 -0
- package/dist/components/sheet-toolbar.vue_vue_type_script_setup_true_lang.js +1562 -0
- package/dist/components/sheet-toolbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/validation-dialog.js +6 -0
- package/dist/components/validation-dialog.js.map +1 -0
- package/dist/components/validation-dialog.vue_vue_type_script_setup_true_lang.js +370 -0
- package/dist/components/validation-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/context.js +12 -0
- package/dist/context.js.map +1 -0
- package/dist/core/address.js +256 -0
- package/dist/core/address.js.map +1 -0
- package/dist/core/axis.js +72 -0
- package/dist/core/axis.js.map +1 -0
- package/dist/core/cell-type.js +30 -0
- package/dist/core/cell-type.js.map +1 -0
- package/dist/core/clipboard.js +141 -0
- package/dist/core/clipboard.js.map +1 -0
- package/dist/core/commands.js +63 -0
- package/dist/core/commands.js.map +1 -0
- package/dist/core/comments.js +74 -0
- package/dist/core/comments.js.map +1 -0
- package/dist/core/conditional.js +362 -0
- package/dist/core/conditional.js.map +1 -0
- package/dist/core/csv.js +191 -0
- package/dist/core/csv.js.map +1 -0
- package/dist/core/data.js +118 -0
- package/dist/core/data.js.map +1 -0
- package/dist/core/document.js +187 -0
- package/dist/core/document.js.map +1 -0
- package/dist/core/extension.js +60 -0
- package/dist/core/extension.js.map +1 -0
- package/dist/core/file.js +336 -0
- package/dist/core/file.js.map +1 -0
- package/dist/core/fill.js +153 -0
- package/dist/core/fill.js.map +1 -0
- package/dist/core/find.js +42 -0
- package/dist/core/find.js.map +1 -0
- package/dist/core/format.js +404 -0
- package/dist/core/format.js.map +1 -0
- package/dist/core/group.js +134 -0
- package/dist/core/group.js.map +1 -0
- package/dist/core/history.js +68 -0
- package/dist/core/history.js.map +1 -0
- package/dist/core/index.js +17 -0
- package/dist/core/link.js +34 -0
- package/dist/core/link.js.map +1 -0
- package/dist/core/merge.js +105 -0
- package/dist/core/merge.js.map +1 -0
- package/dist/core/model.js +48 -0
- package/dist/core/model.js.map +1 -0
- package/dist/core/nav.js +44 -0
- package/dist/core/nav.js.map +1 -0
- package/dist/core/paint.js +106 -0
- package/dist/core/paint.js.map +1 -0
- package/dist/core/plain-cell-types.js +54 -0
- package/dist/core/plain-cell-types.js.map +1 -0
- package/dist/core/protect.js +246 -0
- package/dist/core/protect.js.map +1 -0
- package/dist/core/selection.js +37 -0
- package/dist/core/selection.js.map +1 -0
- package/dist/core/transaction.js +1582 -0
- package/dist/core/transaction.js.map +1 -0
- package/dist/core/validation.js +135 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/core/versions.js +161 -0
- package/dist/core/versions.js.map +1 -0
- package/dist/export/color.js +36 -0
- package/dist/export/color.js.map +1 -0
- package/dist/export/draw.js +316 -0
- package/dist/export/draw.js.map +1 -0
- package/dist/export/index.js +390 -0
- package/dist/export/index.js.map +1 -0
- package/dist/formula/edit.js +210 -0
- package/dist/formula/edit.js.map +1 -0
- package/dist/formula/engine.js +526 -0
- package/dist/formula/engine.js.map +1 -0
- package/dist/formula/error.js +39 -0
- package/dist/formula/error.js.map +1 -0
- package/dist/formula/functions.js +1493 -0
- package/dist/formula/functions.js.map +1 -0
- package/dist/formula/help.js +408 -0
- package/dist/formula/help.js.map +1 -0
- package/dist/formula/index.js +7 -0
- package/dist/formula/parse.js +369 -0
- package/dist/formula/parse.js.map +1 -0
- package/dist/formula/values.js +123 -0
- package/dist/formula/values.js.map +1 -0
- package/dist/formulas.js +30 -0
- package/dist/formulas.js.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/locale.js +1312 -0
- package/dist/locale.js.map +1 -0
- package/dist/sheet.js +6 -0
- package/dist/sheet.js.map +1 -0
- package/dist/sheet.vue_vue_type_script_setup_true_lang.js +7166 -0
- package/dist/sheet.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/style.d.ts +1 -0
- package/dist/style.js +17 -0
- package/dist/types/cell-types.d.ts +2 -0
- package/dist/types/code/code-formula-bar.vue.d.ts +3 -0
- package/dist/types/code/index.d.ts +12 -0
- package/dist/types/code/language.d.ts +13 -0
- package/dist/types/collaboration/anchor.d.ts +65 -0
- package/dist/types/collaboration/index.d.ts +59 -0
- package/dist/types/collaboration/peers.d.ts +21 -0
- package/dist/types/collaboration/shared.d.ts +75 -0
- package/dist/types/components/cell-panel.vue.d.ts +20 -0
- package/dist/types/components/cell-renders.d.ts +9 -0
- package/dist/types/components/date-panel.vue.d.ts +9 -0
- package/dist/types/components/filter-panel.vue.d.ts +21 -0
- package/dist/types/components/format-dialog.vue.d.ts +24 -0
- package/dist/types/components/format-list.vue.d.ts +25 -0
- package/dist/types/components/format-presets.d.ts +30 -0
- package/dist/types/components/option-panel.vue.d.ts +13 -0
- package/dist/types/components/sheet-comment.vue.d.ts +29 -0
- package/dist/types/components/sheet-formula-bar.vue.d.ts +3 -0
- package/dist/types/components/sheet-link.vue.d.ts +32 -0
- package/dist/types/components/sheet-menu.vue.d.ts +20 -0
- package/dist/types/components/sheet-name-box.vue.d.ts +3 -0
- package/dist/types/components/sheet-note.vue.d.ts +22 -0
- package/dist/types/components/sheet-outline.vue.d.ts +36 -0
- package/dist/types/components/sheet-tabs.vue.d.ts +9 -0
- package/dist/types/components/sheet-toolbar.vue.d.ts +11 -0
- package/dist/types/components/validation-dialog.vue.d.ts +25 -0
- package/dist/types/context.d.ts +189 -0
- package/dist/types/core/address.d.ts +109 -0
- package/dist/types/core/axis.d.ts +23 -0
- package/dist/types/core/cell-type.d.ts +157 -0
- package/dist/types/core/clipboard.d.ts +48 -0
- package/dist/types/core/commands.d.ts +76 -0
- package/dist/types/core/comments.d.ts +22 -0
- package/dist/types/core/conditional.d.ts +114 -0
- package/dist/types/core/csv.d.ts +93 -0
- package/dist/types/core/data.d.ts +26 -0
- package/dist/types/core/document.d.ts +49 -0
- package/dist/types/core/extension.d.ts +177 -0
- package/dist/types/core/file.d.ts +301 -0
- package/dist/types/core/fill.d.ts +23 -0
- package/dist/types/core/find.d.ts +39 -0
- package/dist/types/core/format.d.ts +47 -0
- package/dist/types/core/group.d.ts +76 -0
- package/dist/types/core/history.d.ts +27 -0
- package/dist/types/core/index.d.ts +33 -0
- package/dist/types/core/link.d.ts +14 -0
- package/dist/types/core/merge.d.ts +26 -0
- package/dist/types/core/model.d.ts +363 -0
- package/dist/types/core/nav.d.ts +15 -0
- package/dist/types/core/paint.d.ts +19 -0
- package/dist/types/core/plain-cell-types.d.ts +6 -0
- package/dist/types/core/protect.d.ts +34 -0
- package/dist/types/core/selection.d.ts +25 -0
- package/dist/types/core/transaction.d.ts +470 -0
- package/dist/types/core/validation.d.ts +55 -0
- package/dist/types/core/versions.d.ts +38 -0
- package/dist/types/export/color.d.ts +7 -0
- package/dist/types/export/draw.d.ts +98 -0
- package/dist/types/export/index.d.ts +47 -0
- package/dist/types/formula/edit.d.ts +62 -0
- package/dist/types/formula/engine.d.ts +99 -0
- package/dist/types/formula/error.d.ts +30 -0
- package/dist/types/formula/functions.d.ts +62 -0
- package/dist/types/formula/help.d.ts +12 -0
- package/dist/types/formula/index.d.ts +13 -0
- package/dist/types/formula/parse.d.ts +92 -0
- package/dist/types/formula/values.d.ts +65 -0
- package/dist/types/formulas.d.ts +32 -0
- package/dist/types/index.d.ts +225 -0
- package/dist/types/locale.d.ts +531 -0
- package/dist/types/sheet.vue.d.ts +60 -0
- package/dist/types/types.d.ts +498 -0
- package/dist/types/use-comments.d.ts +47 -0
- package/dist/types/use-messages.d.ts +7 -0
- package/dist/use-comments.js +130 -0
- package/dist/use-comments.js.map +1 -0
- package/dist/use-messages.js +29 -0
- package/dist/use-messages.js.map +1 -0
- package/package.json +93 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet-tabs.js","names":["_sfc_main"],"sources":["../../src/components/sheet-tabs.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ArrowLeftIcon,\n ArrowRightIcon,\n CopyPlusIcon,\n LockIcon,\n PencilIcon,\n PlusIcon,\n TrashIcon,\n} from '@dou-ui/icons'\nimport { DouButton, isComposing, matchesHotkey, useSortable } from 'dou-ui'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n shallowRef,\n useId,\n useTemplateRef,\n watch,\n} from 'vue'\nimport { useSheet } from '../context'\nimport { sheetKey } from '../core/transaction'\nimport { format } from '../locale'\nimport type { SheetMenuItem } from '../types'\nimport SheetMenu from './sheet-menu.vue'\n\ndefineOptions({ name: 'DouSheetTabs' })\n\nwithDefaults(\n defineProps<{\n /** Whether to show the button that adds a sheet; `true` by default. */\n addable?: boolean\n }>(),\n { addable: true },\n)\n\nconst sheet = useSheet()\nconst { doc, sheetIndex, messages } = sheet\nconst uid = useId()\nconst hint = `${uid}-keys`\n\nconst editable = computed(() => !sheet.readonly.value)\n/** Whether sheets can be added, removed, moved and renamed: not while the workbook is protected. */\nconst structural = computed(() => editable.value && !doc.value.protect)\nconst isProtected = (key: string) => !!doc.value.sheets.find((s) => sheetKey(s) === key)?.protect\nconst keys = computed(() => doc.value.sheets.map(sheetKey))\n\n// Dragging tabs into another order --------------------------------------------------------\n\nconst order = computed({\n get: () => keys.value,\n set: () => {},\n})\nconst { container, list, listAttrs, itemAttrs, dragging } = useSortable<string>({\n items: order,\n key: (key) => key,\n direction: () => 'horizontal',\n disabled: () => !structural.value || renaming.value != null,\n label: (key) => nameOf(key),\n messages: () => ({\n item: messages.value.sheets,\n lifted: (label) => label,\n moved: (label, index, count) =>\n format(messages.value.sheetMoved, { name: label, index, count }),\n dropped: (label, index, count) =>\n format(messages.value.sheetMoved, { name: label, index, count }),\n canceled: (label) => label,\n }),\n // the copy that follows the pointer sits outside the grid: it takes the tab's font along\n ghost: (el) => {\n const copy = el.cloneNode(true) as HTMLElement\n const style = getComputedStyle(el)\n for (const name of ['font-family', 'font-size', 'font-weight', 'line-height', 'color'])\n copy.style.setProperty(name, style.getPropertyValue(name))\n copy.style.backgroundColor = 'var(--dou-color-bg-surface)'\n copy.style.borderColor = 'var(--dou-color-border)'\n return copy\n },\n onSort: ({ item, newIndex }) => {\n sheet.transact((tr) => tr.moveSheet(item, newIndex), { action: 'sheet' })\n },\n})\n\nconst nameOf = (key: string) => doc.value.sheets.find((s) => sheetKey(s) === key)?.name ?? key\nconst indexOf = (key: string) => keys.value.indexOf(key)\n\n/**\n * What sortable puts on each tab, but its keys: the tabs keep their own, and\n * the press goes through `onPointerDown`.\n */\nfunction dragAttrs(key: string, index: number) {\n const {\n onKeydown: _keys,\n onPointerdown: _press,\n tabindex: _tabindex,\n 'aria-roledescription': _role,\n ...rest\n } = itemAttrs(key, index)\n return rest\n}\n\n// Tabs past either side fade out there, so it shows that the strip scrolls\n\nconst more = ref({ start: false, end: false })\nfunction measureMore() {\n const el = container.value\n if (!el) return\n const start = el.scrollLeft > 1\n const end = el.scrollLeft + el.clientWidth < el.scrollWidth - 1\n if (start !== more.value.start || end !== more.value.end) more.value = { start, end }\n}\nlet resize: ResizeObserver | undefined\nonMounted(() => {\n measureMore()\n if (typeof ResizeObserver === 'undefined' || !container.value) return\n resize = new ResizeObserver(measureMore)\n resize.observe(container.value)\n})\nonBeforeUnmount(() => resize?.disconnect())\nwatch(keys, () => void nextTick(measureMore))\n\n// Switching ------------------------------------------------------------------------------\n\nconst tabs = useTemplateRef<HTMLElement[]>('tab')\nconst tabOf = (index: number) =>\n tabs.value?.find((el) => el.dataset.index === String(index)) ?? null\n\nfunction show(index: number, focusTab = false) {\n if (index < 0 || index >= keys.value.length) return\n if (index !== sheetIndex.value) {\n sheet.showSheet(index)\n sheet.announce(format(messages.value.sheetShown, { name: doc.value.sheets[index]!.name }))\n }\n if (focusTab) void nextTick(() => tabOf(index)?.focus())\n}\n\n// the tab shown is kept in view\nwatch(\n sheetIndex,\n (index) => {\n void nextTick(() => tabOf(index)?.scrollIntoView({ block: 'nearest', inline: 'nearest' }))\n },\n { flush: 'post' },\n)\n\nlet lastPointer = 'mouse'\n/** When a finger last switched sheets: a tap right after is the same double tap. */\nlet switchedAt = 0\n/** A finger held still on a tab opens its menu; the click that follows is then spent. */\nlet holdTimer: ReturnType<typeof setTimeout> | undefined\nlet held = false\nconst HOLD = 500\n\nfunction onPointerDown(event: PointerEvent, key: string, index: number) {\n lastPointer = event.pointerType\n held = false\n itemAttrs(key, index).onPointerdown(event)\n if (event.pointerType !== 'touch' || !editable.value) return\n const el = event.currentTarget as HTMLElement\n const x0 = event.clientX\n const y0 = event.clientY\n const stop = () => {\n clearTimeout(holdTimer)\n window.removeEventListener('pointermove', onMove)\n window.removeEventListener('pointerup', stop)\n window.removeEventListener('pointercancel', stop)\n }\n const onMove = (e: PointerEvent) => {\n if (Math.hypot(e.clientX - x0, e.clientY - y0) > 8) stop()\n }\n window.addEventListener('pointermove', onMove)\n window.addEventListener('pointerup', stop)\n window.addEventListener('pointercancel', stop)\n holdTimer = setTimeout(() => {\n stop()\n if (dragging.value != null || renaming.value != null) return\n held = true\n navigator.vibrate?.(8)\n const rect = el.getBoundingClientRect()\n openMenu(indexOf(key), rect.left + rect.width / 2, rect.top)\n }, HOLD)\n}\n\nfunction onClick(index: number, event: MouseEvent) {\n if (renaming.value != null) return\n if (held) {\n held = false\n return\n }\n if (lastPointer === 'touch' && index === sheetIndex.value) {\n // a finger on the tab already shown opens its menu: phones have no right click\n if (!editable.value || Date.now() - switchedAt < 400) return\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()\n return openMenu(index, rect.left + rect.width / 2, rect.top)\n }\n show(index)\n if (lastPointer === 'touch') switchedAt = Date.now()\n else sheet.focus()\n}\n\n/** A double click renames; a finger renames from the menu, as two taps also switch and open it. */\nfunction onDblClick(index: number) {\n if (lastPointer !== 'touch') startRename(index)\n}\n\nfunction onKeydown(event: KeyboardEvent, index: number) {\n if (isComposing(event)) return\n const count = keys.value.length\n const key = event.key\n let to = -1\n if (key === 'ArrowLeft') to = (index - 1 + count) % count\n else if (key === 'ArrowRight') to = (index + 1) % count\n else if (key === 'Home') to = 0\n else if (key === 'End') to = count - 1\n if (to !== -1) {\n event.preventDefault()\n return show(to, true)\n }\n if (key === 'F2' && editable.value) {\n event.preventDefault()\n return startRename(index)\n }\n if (key === 'ContextMenu' || (key === 'F10' && event.shiftKey)) {\n event.preventDefault()\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()\n return openMenu(index, rect.left + rect.width / 2, rect.top)\n }\n // what was just done to the tabs can be taken back from here too\n if (matchesHotkey(event, 'mod+z')) {\n event.preventDefault()\n sheet.undo()\n return keepFocus()\n }\n if (matchesHotkey(event, 'mod+shift+z') || matchesHotkey(event, 'mod+y')) {\n event.preventDefault()\n sheet.redo()\n return keepFocus()\n }\n if (key === 'Enter' || key === 'ArrowUp') {\n // into the grid of the sheet shown\n event.preventDefault()\n show(index)\n sheet.focus()\n }\n}\n\n/** Keeps the focus on the tabs, on the tab shown, after the tabs changed under it. */\nfunction keepFocus() {\n void nextTick(() => tabOf(sheetIndex.value)?.focus())\n}\n\n// Adding ---------------------------------------------------------------------------------\n\n/** The first free name like `工作表3`. */\nfunction freeName() {\n const taken = new Set(doc.value.sheets.map((s) => s.name))\n let n = doc.value.sheets.length + 1\n while (taken.has(format(messages.value.sheetName, { n }))) n++\n return format(messages.value.sheetName, { n })\n}\n\nfunction addSheet() {\n const name = freeName()\n const at = sheetIndex.value + 1\n const done = sheet.transact((tr) => tr.addSheet({ name }, at), { action: 'sheet' })\n if (!done) return\n show(at)\n sheet.announce(format(messages.value.sheetAdded, { name }))\n sheet.focus()\n}\n\n// Renaming -------------------------------------------------------------------------------\n\n/** The index of the tab being renamed, and what is typed. */\nconst renaming = ref<number | null>(null)\nconst draft = ref('')\nconst problem = ref('')\nconst input = useTemplateRef<HTMLInputElement[]>('input')\n\nfunction startRename(index: number) {\n if (!structural.value) return\n show(index)\n renaming.value = index\n draft.value = doc.value.sheets[index]!.name\n problem.value = ''\n void nextTick(() => {\n const el = input.value?.[0]\n el?.focus()\n el?.select()\n })\n}\n\nfunction check(name: string, index: number) {\n if (!name) return messages.value.sheetNameEmpty\n const taken = doc.value.sheets.some((s, i) => i !== index && s.name === name)\n return taken ? format(messages.value.sheetNameTaken, { name }) : ''\n}\n\n/** Writes the new name; with `keep`, a name that won't do keeps the field open. */\nfunction finishRename(keep: boolean) {\n const index = renaming.value\n if (index == null) return\n const name = draft.value.trim()\n const wrong = check(name, index)\n if (wrong && keep) {\n problem.value = wrong\n sheet.announce(wrong)\n return\n }\n renaming.value = null\n problem.value = ''\n if (!wrong && name !== doc.value.sheets[index]!.name)\n sheet.transact((tr) => tr.renameSheet(index, name), { action: 'sheet' })\n if (keep) void nextTick(() => tabOf(index)?.focus())\n}\n\nfunction cancelRename() {\n const index = renaming.value\n renaming.value = null\n problem.value = ''\n if (index != null) void nextTick(() => tabOf(index)?.focus())\n}\n\nfunction onInputKey(event: KeyboardEvent) {\n if (isComposing(event)) return\n if (event.key === 'Enter') {\n event.preventDefault()\n finishRename(true)\n } else if (event.key === 'Escape') {\n event.preventDefault()\n cancelRename()\n }\n // the tab's own keys are for the tabs, not the text\n event.stopPropagation()\n}\n\nwatch(draft, () => (problem.value = ''))\n\n// The menu -------------------------------------------------------------------------------\n\nconst menu = useTemplateRef<InstanceType<typeof SheetMenu>>('menu')\nconst menuOpen = ref(false)\nconst menuItems = shallowRef<SheetMenuItem[]>([])\n\nfunction openMenu(index: number, x: number, y: number) {\n if (!editable.value) return\n show(index)\n const m = messages.value\n const count = keys.value.length\n const name = doc.value.sheets[index]!.name\n menuItems.value = [\n {\n key: 'rename',\n label: m.renameSheet,\n icon: PencilIcon,\n disabled: !structural.value,\n run: () => startRename(index),\n },\n {\n key: 'duplicate',\n label: m.duplicateSheet,\n icon: CopyPlusIcon,\n disabled: !structural.value,\n run: () => {\n const done = sheet.transact((tr) => tr.duplicateSheet(index), { action: 'sheet' })\n if (done) show(index + 1)\n },\n },\n {\n key: 'left',\n label: m.moveSheetLeft,\n icon: ArrowLeftIcon,\n divided: true,\n disabled: !structural.value || index === 0,\n run: () => moveTo(index, index - 1),\n },\n {\n key: 'right',\n label: m.moveSheetRight,\n icon: ArrowRightIcon,\n disabled: !structural.value || index === count - 1,\n run: () => moveTo(index, index + 1),\n },\n {\n key: 'delete',\n label: m.deleteSheet,\n icon: TrashIcon,\n tone: 'danger',\n divided: true,\n disabled: !structural.value || count < 2,\n run: () => {\n const done = sheet.transact((tr) => tr.removeSheet(index), { action: 'sheet' })\n if (done) sheet.announce(format(m.sheetDeleted, { name }))\n },\n },\n ...(['protect.sheet', 'protect.workbook'] as const).map((command, i): SheetMenuItem => {\n const info = sheet.commands.get(command)!\n return {\n key: command,\n label: info.label,\n icon: info.icon,\n divided: i === 0,\n disabled: !sheet.commands.can(command),\n run: () => void sheet.commands.run(command),\n }\n }),\n ]\n menu.value?.open(x, y)\n}\n\nfunction moveTo(index: number, to: number) {\n const name = doc.value.sheets[index]!.name\n const done = sheet.transact((tr) => tr.moveSheet(index, to), { action: 'sheet' })\n if (!done) return\n sheet.announce(\n format(messages.value.sheetMoved, { name, index: to + 1, count: keys.value.length }),\n )\n void nextTick(() => tabOf(to)?.focus())\n}\n\nfunction onMenuSelect(key: unknown) {\n menuItems.value.find((item) => item.key === key)?.run?.()\n}\n\nfunction onContextMenu(event: MouseEvent, index: number) {\n event.preventDefault()\n if (lastPointer === 'touch' || renaming.value != null) return\n openMenu(index, event.clientX, event.clientY)\n}\n</script>\n\n<template>\n <div class=\"dou-sheet-tabs\">\n <DouButton\n v-if=\"addable && structural\"\n class=\"dou-sheet-tabs__add\"\n variant=\"ghost\"\n size=\"sm\"\n :aria-label=\"messages.addSheet\"\n :title=\"messages.addSheet\"\n @click=\"addSheet\"\n >\n <PlusIcon />\n </DouButton>\n <div\n ref=\"container\"\n class=\"dou-sheet-tabs__list\"\n :class=\"{ 'has-more-start': more.start, 'has-more-end': more.end }\"\n role=\"tablist\"\n :aria-label=\"messages.sheets\"\n v-bind=\"listAttrs\"\n @scroll.passive=\"measureMore\"\n >\n <div\n v-for=\"(key, index) in list\"\n :key=\"key\"\n ref=\"tab\"\n class=\"dou-sheet-tabs__tab\"\n :class=\"{\n 'is-active': indexOf(key) === sheetIndex,\n 'is-renaming': renaming === indexOf(key),\n }\"\n role=\"tab\"\n :data-index=\"indexOf(key)\"\n :aria-selected=\"indexOf(key) === sheetIndex\"\n :tabindex=\"indexOf(key) === sheetIndex ? 0 : -1\"\n :aria-describedby=\"hint\"\n v-bind=\"dragAttrs(key, index)\"\n @pointerdown=\"onPointerDown($event, key, index)\"\n @click=\"onClick(indexOf(key), $event)\"\n @dblclick=\"onDblClick(indexOf(key))\"\n @keydown=\"onKeydown($event, indexOf(key))\"\n @contextmenu=\"onContextMenu($event, indexOf(key))\"\n >\n <template v-if=\"renaming === indexOf(key)\">\n <!-- the hidden copy sizes the field to its text -->\n <span class=\"dou-sheet-tabs__size\" aria-hidden=\"true\">{{ draft || ' ' }}</span>\n <input\n ref=\"input\"\n v-model=\"draft\"\n class=\"dou-sheet-tabs__input\"\n :aria-label=\"messages.renameSheet\"\n :aria-invalid=\"problem ? true : undefined\"\n :title=\"problem || undefined\"\n maxlength=\"100\"\n spellcheck=\"false\"\n @keydown=\"onInputKey\"\n @blur=\"finishRename(false)\"\n @pointerdown.stop\n @click.stop\n @dblclick.stop\n />\n </template>\n <template v-else>\n <LockIcon v-if=\"isProtected(key)\" class=\"dou-sheet-tabs__lock\" aria-hidden=\"true\" />\n <span class=\"dou-sheet-tabs__name\">{{ nameOf(key) }}</span>\n <span v-if=\"isProtected(key)\" class=\"dou-sheet__sr-only\">\n {{ messages.protect.protectedSheet }}\n </span>\n </template>\n </div>\n </div>\n <span :id=\"hint\" class=\"dou-sheet__sr-only\">{{ messages.sheetTabKeys }}</span>\n <div v-if=\"problem\" class=\"dou-sheet-tabs__problem\" role=\"alert\">{{ problem }}</div>\n <SheetMenu ref=\"menu\" v-model:open=\"menuOpen\" :items=\"menuItems\" @select=\"onMenuSelect\" />\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import { sheetKey } from "../core/transaction.js";
|
|
2
|
+
import { format } from "../locale.js";
|
|
3
|
+
import sheet_menu_default from "./sheet-menu.js";
|
|
4
|
+
import { useSheet } from "../context.js";
|
|
5
|
+
import { DouButton, isComposing, matchesHotkey, useSortable } from "dou-ui";
|
|
6
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, mergeProps, nextTick, onBeforeUnmount, onMounted, openBlock, ref, renderList, shallowRef, toDisplayString, unref, useId, useTemplateRef, vModelText, watch, withCtx, withDirectives, withModifiers } from "vue";
|
|
7
|
+
import { ArrowLeftIcon, ArrowRightIcon, CopyPlusIcon, LockIcon, PencilIcon, PlusIcon, TrashIcon } from "@dou-ui/icons";
|
|
8
|
+
// src/components/sheet-tabs.vue?vue&type=script&setup=true&lang.ts
|
|
9
|
+
var _hoisted_1 = { class: "dou-sheet-tabs" };
|
|
10
|
+
var _hoisted_2 = ["aria-label"];
|
|
11
|
+
var _hoisted_3 = [
|
|
12
|
+
"data-index",
|
|
13
|
+
"aria-selected",
|
|
14
|
+
"tabindex",
|
|
15
|
+
"onPointerdown",
|
|
16
|
+
"onClick",
|
|
17
|
+
"onDblclick",
|
|
18
|
+
"onKeydown",
|
|
19
|
+
"onContextmenu"
|
|
20
|
+
];
|
|
21
|
+
var _hoisted_4 = {
|
|
22
|
+
class: "dou-sheet-tabs__size",
|
|
23
|
+
"aria-hidden": "true"
|
|
24
|
+
};
|
|
25
|
+
var _hoisted_5 = [
|
|
26
|
+
"aria-label",
|
|
27
|
+
"aria-invalid",
|
|
28
|
+
"title"
|
|
29
|
+
];
|
|
30
|
+
var _hoisted_6 = { class: "dou-sheet-tabs__name" };
|
|
31
|
+
var _hoisted_7 = {
|
|
32
|
+
key: 1,
|
|
33
|
+
class: "dou-sheet__sr-only"
|
|
34
|
+
};
|
|
35
|
+
var _hoisted_8 = {
|
|
36
|
+
key: 1,
|
|
37
|
+
class: "dou-sheet-tabs__problem",
|
|
38
|
+
role: "alert"
|
|
39
|
+
};
|
|
40
|
+
var HOLD = 500;
|
|
41
|
+
var sheet_tabs_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
42
|
+
name: "DouSheetTabs",
|
|
43
|
+
__name: "sheet-tabs",
|
|
44
|
+
props: { addable: {
|
|
45
|
+
type: Boolean,
|
|
46
|
+
default: true
|
|
47
|
+
} },
|
|
48
|
+
setup(__props) {
|
|
49
|
+
const sheet = useSheet();
|
|
50
|
+
const { doc, sheetIndex, messages } = sheet;
|
|
51
|
+
const hint = `${useId()}-keys`;
|
|
52
|
+
const editable = computed(() => !sheet.readonly.value);
|
|
53
|
+
/** Whether sheets can be added, removed, moved and renamed: not while the workbook is protected. */
|
|
54
|
+
const structural = computed(() => editable.value && !doc.value.protect);
|
|
55
|
+
const isProtected = (key) => !!doc.value.sheets.find((s) => sheetKey(s) === key)?.protect;
|
|
56
|
+
const keys = computed(() => doc.value.sheets.map(sheetKey));
|
|
57
|
+
const order = computed({
|
|
58
|
+
get: () => keys.value,
|
|
59
|
+
set: () => {}
|
|
60
|
+
});
|
|
61
|
+
const { container, list, listAttrs, itemAttrs, dragging } = useSortable({
|
|
62
|
+
items: order,
|
|
63
|
+
key: (key) => key,
|
|
64
|
+
direction: () => "horizontal",
|
|
65
|
+
disabled: () => !structural.value || renaming.value != null,
|
|
66
|
+
label: (key) => nameOf(key),
|
|
67
|
+
messages: () => ({
|
|
68
|
+
item: messages.value.sheets,
|
|
69
|
+
lifted: (label) => label,
|
|
70
|
+
moved: (label, index, count) => format(messages.value.sheetMoved, {
|
|
71
|
+
name: label,
|
|
72
|
+
index,
|
|
73
|
+
count
|
|
74
|
+
}),
|
|
75
|
+
dropped: (label, index, count) => format(messages.value.sheetMoved, {
|
|
76
|
+
name: label,
|
|
77
|
+
index,
|
|
78
|
+
count
|
|
79
|
+
}),
|
|
80
|
+
canceled: (label) => label
|
|
81
|
+
}),
|
|
82
|
+
ghost: (el) => {
|
|
83
|
+
const copy = el.cloneNode(true);
|
|
84
|
+
const style = getComputedStyle(el);
|
|
85
|
+
for (const name of [
|
|
86
|
+
"font-family",
|
|
87
|
+
"font-size",
|
|
88
|
+
"font-weight",
|
|
89
|
+
"line-height",
|
|
90
|
+
"color"
|
|
91
|
+
]) copy.style.setProperty(name, style.getPropertyValue(name));
|
|
92
|
+
copy.style.backgroundColor = "var(--dou-color-bg-surface)";
|
|
93
|
+
copy.style.borderColor = "var(--dou-color-border)";
|
|
94
|
+
return copy;
|
|
95
|
+
},
|
|
96
|
+
onSort: ({ item, newIndex }) => {
|
|
97
|
+
sheet.transact((tr) => tr.moveSheet(item, newIndex), { action: "sheet" });
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
const nameOf = (key) => doc.value.sheets.find((s) => sheetKey(s) === key)?.name ?? key;
|
|
101
|
+
const indexOf = (key) => keys.value.indexOf(key);
|
|
102
|
+
/**
|
|
103
|
+
* What sortable puts on each tab, but its keys: the tabs keep their own, and
|
|
104
|
+
* the press goes through `onPointerDown`.
|
|
105
|
+
*/
|
|
106
|
+
function dragAttrs(key, index) {
|
|
107
|
+
const { onKeydown: _keys, onPointerdown: _press, tabindex: _tabindex, "aria-roledescription": _role, ...rest } = itemAttrs(key, index);
|
|
108
|
+
return rest;
|
|
109
|
+
}
|
|
110
|
+
const more = ref({
|
|
111
|
+
start: false,
|
|
112
|
+
end: false
|
|
113
|
+
});
|
|
114
|
+
function measureMore() {
|
|
115
|
+
const el = container.value;
|
|
116
|
+
if (!el) return;
|
|
117
|
+
const start = el.scrollLeft > 1;
|
|
118
|
+
const end = el.scrollLeft + el.clientWidth < el.scrollWidth - 1;
|
|
119
|
+
if (start !== more.value.start || end !== more.value.end) more.value = {
|
|
120
|
+
start,
|
|
121
|
+
end
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
let resize;
|
|
125
|
+
onMounted(() => {
|
|
126
|
+
measureMore();
|
|
127
|
+
if (typeof ResizeObserver === "undefined" || !container.value) return;
|
|
128
|
+
resize = new ResizeObserver(measureMore);
|
|
129
|
+
resize.observe(container.value);
|
|
130
|
+
});
|
|
131
|
+
onBeforeUnmount(() => resize?.disconnect());
|
|
132
|
+
watch(keys, () => void nextTick(measureMore));
|
|
133
|
+
const tabs = useTemplateRef("tab");
|
|
134
|
+
const tabOf = (index) => tabs.value?.find((el) => el.dataset.index === String(index)) ?? null;
|
|
135
|
+
function show(index, focusTab = false) {
|
|
136
|
+
if (index < 0 || index >= keys.value.length) return;
|
|
137
|
+
if (index !== sheetIndex.value) {
|
|
138
|
+
sheet.showSheet(index);
|
|
139
|
+
sheet.announce(format(messages.value.sheetShown, { name: doc.value.sheets[index].name }));
|
|
140
|
+
}
|
|
141
|
+
if (focusTab) nextTick(() => tabOf(index)?.focus());
|
|
142
|
+
}
|
|
143
|
+
watch(sheetIndex, (index) => {
|
|
144
|
+
nextTick(() => tabOf(index)?.scrollIntoView({
|
|
145
|
+
block: "nearest",
|
|
146
|
+
inline: "nearest"
|
|
147
|
+
}));
|
|
148
|
+
}, { flush: "post" });
|
|
149
|
+
let lastPointer = "mouse";
|
|
150
|
+
/** When a finger last switched sheets: a tap right after is the same double tap. */
|
|
151
|
+
let switchedAt = 0;
|
|
152
|
+
/** A finger held still on a tab opens its menu; the click that follows is then spent. */
|
|
153
|
+
let holdTimer;
|
|
154
|
+
let held = false;
|
|
155
|
+
function onPointerDown(event, key, index) {
|
|
156
|
+
lastPointer = event.pointerType;
|
|
157
|
+
held = false;
|
|
158
|
+
itemAttrs(key, index).onPointerdown(event);
|
|
159
|
+
if (event.pointerType !== "touch" || !editable.value) return;
|
|
160
|
+
const el = event.currentTarget;
|
|
161
|
+
const x0 = event.clientX;
|
|
162
|
+
const y0 = event.clientY;
|
|
163
|
+
const stop = () => {
|
|
164
|
+
clearTimeout(holdTimer);
|
|
165
|
+
window.removeEventListener("pointermove", onMove);
|
|
166
|
+
window.removeEventListener("pointerup", stop);
|
|
167
|
+
window.removeEventListener("pointercancel", stop);
|
|
168
|
+
};
|
|
169
|
+
const onMove = (e) => {
|
|
170
|
+
if (Math.hypot(e.clientX - x0, e.clientY - y0) > 8) stop();
|
|
171
|
+
};
|
|
172
|
+
window.addEventListener("pointermove", onMove);
|
|
173
|
+
window.addEventListener("pointerup", stop);
|
|
174
|
+
window.addEventListener("pointercancel", stop);
|
|
175
|
+
holdTimer = setTimeout(() => {
|
|
176
|
+
stop();
|
|
177
|
+
if (dragging.value != null || renaming.value != null) return;
|
|
178
|
+
held = true;
|
|
179
|
+
navigator.vibrate?.(8);
|
|
180
|
+
const rect = el.getBoundingClientRect();
|
|
181
|
+
openMenu(indexOf(key), rect.left + rect.width / 2, rect.top);
|
|
182
|
+
}, HOLD);
|
|
183
|
+
}
|
|
184
|
+
function onClick(index, event) {
|
|
185
|
+
if (renaming.value != null) return;
|
|
186
|
+
if (held) {
|
|
187
|
+
held = false;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (lastPointer === "touch" && index === sheetIndex.value) {
|
|
191
|
+
if (!editable.value || Date.now() - switchedAt < 400) return;
|
|
192
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
193
|
+
return openMenu(index, rect.left + rect.width / 2, rect.top);
|
|
194
|
+
}
|
|
195
|
+
show(index);
|
|
196
|
+
if (lastPointer === "touch") switchedAt = Date.now();
|
|
197
|
+
else sheet.focus();
|
|
198
|
+
}
|
|
199
|
+
/** A double click renames; a finger renames from the menu, as two taps also switch and open it. */
|
|
200
|
+
function onDblClick(index) {
|
|
201
|
+
if (lastPointer !== "touch") startRename(index);
|
|
202
|
+
}
|
|
203
|
+
function onKeydown(event, index) {
|
|
204
|
+
if (isComposing(event)) return;
|
|
205
|
+
const count = keys.value.length;
|
|
206
|
+
const key = event.key;
|
|
207
|
+
let to = -1;
|
|
208
|
+
if (key === "ArrowLeft") to = (index - 1 + count) % count;
|
|
209
|
+
else if (key === "ArrowRight") to = (index + 1) % count;
|
|
210
|
+
else if (key === "Home") to = 0;
|
|
211
|
+
else if (key === "End") to = count - 1;
|
|
212
|
+
if (to !== -1) {
|
|
213
|
+
event.preventDefault();
|
|
214
|
+
return show(to, true);
|
|
215
|
+
}
|
|
216
|
+
if (key === "F2" && editable.value) {
|
|
217
|
+
event.preventDefault();
|
|
218
|
+
return startRename(index);
|
|
219
|
+
}
|
|
220
|
+
if (key === "ContextMenu" || key === "F10" && event.shiftKey) {
|
|
221
|
+
event.preventDefault();
|
|
222
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
223
|
+
return openMenu(index, rect.left + rect.width / 2, rect.top);
|
|
224
|
+
}
|
|
225
|
+
if (matchesHotkey(event, "mod+z")) {
|
|
226
|
+
event.preventDefault();
|
|
227
|
+
sheet.undo();
|
|
228
|
+
return keepFocus();
|
|
229
|
+
}
|
|
230
|
+
if (matchesHotkey(event, "mod+shift+z") || matchesHotkey(event, "mod+y")) {
|
|
231
|
+
event.preventDefault();
|
|
232
|
+
sheet.redo();
|
|
233
|
+
return keepFocus();
|
|
234
|
+
}
|
|
235
|
+
if (key === "Enter" || key === "ArrowUp") {
|
|
236
|
+
event.preventDefault();
|
|
237
|
+
show(index);
|
|
238
|
+
sheet.focus();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** Keeps the focus on the tabs, on the tab shown, after the tabs changed under it. */
|
|
242
|
+
function keepFocus() {
|
|
243
|
+
nextTick(() => tabOf(sheetIndex.value)?.focus());
|
|
244
|
+
}
|
|
245
|
+
/** The first free name like `工作表3`. */
|
|
246
|
+
function freeName() {
|
|
247
|
+
const taken = new Set(doc.value.sheets.map((s) => s.name));
|
|
248
|
+
let n = doc.value.sheets.length + 1;
|
|
249
|
+
while (taken.has(format(messages.value.sheetName, { n }))) n++;
|
|
250
|
+
return format(messages.value.sheetName, { n });
|
|
251
|
+
}
|
|
252
|
+
function addSheet() {
|
|
253
|
+
const name = freeName();
|
|
254
|
+
const at = sheetIndex.value + 1;
|
|
255
|
+
if (!sheet.transact((tr) => tr.addSheet({ name }, at), { action: "sheet" })) return;
|
|
256
|
+
show(at);
|
|
257
|
+
sheet.announce(format(messages.value.sheetAdded, { name }));
|
|
258
|
+
sheet.focus();
|
|
259
|
+
}
|
|
260
|
+
/** The index of the tab being renamed, and what is typed. */
|
|
261
|
+
const renaming = ref(null);
|
|
262
|
+
const draft = ref("");
|
|
263
|
+
const problem = ref("");
|
|
264
|
+
const input = useTemplateRef("input");
|
|
265
|
+
function startRename(index) {
|
|
266
|
+
if (!structural.value) return;
|
|
267
|
+
show(index);
|
|
268
|
+
renaming.value = index;
|
|
269
|
+
draft.value = doc.value.sheets[index].name;
|
|
270
|
+
problem.value = "";
|
|
271
|
+
nextTick(() => {
|
|
272
|
+
const el = input.value?.[0];
|
|
273
|
+
el?.focus();
|
|
274
|
+
el?.select();
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function check(name, index) {
|
|
278
|
+
if (!name) return messages.value.sheetNameEmpty;
|
|
279
|
+
return doc.value.sheets.some((s, i) => i !== index && s.name === name) ? format(messages.value.sheetNameTaken, { name }) : "";
|
|
280
|
+
}
|
|
281
|
+
/** Writes the new name; with `keep`, a name that won't do keeps the field open. */
|
|
282
|
+
function finishRename(keep) {
|
|
283
|
+
const index = renaming.value;
|
|
284
|
+
if (index == null) return;
|
|
285
|
+
const name = draft.value.trim();
|
|
286
|
+
const wrong = check(name, index);
|
|
287
|
+
if (wrong && keep) {
|
|
288
|
+
problem.value = wrong;
|
|
289
|
+
sheet.announce(wrong);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
renaming.value = null;
|
|
293
|
+
problem.value = "";
|
|
294
|
+
if (!wrong && name !== doc.value.sheets[index].name) sheet.transact((tr) => tr.renameSheet(index, name), { action: "sheet" });
|
|
295
|
+
if (keep) nextTick(() => tabOf(index)?.focus());
|
|
296
|
+
}
|
|
297
|
+
function cancelRename() {
|
|
298
|
+
const index = renaming.value;
|
|
299
|
+
renaming.value = null;
|
|
300
|
+
problem.value = "";
|
|
301
|
+
if (index != null) nextTick(() => tabOf(index)?.focus());
|
|
302
|
+
}
|
|
303
|
+
function onInputKey(event) {
|
|
304
|
+
if (isComposing(event)) return;
|
|
305
|
+
if (event.key === "Enter") {
|
|
306
|
+
event.preventDefault();
|
|
307
|
+
finishRename(true);
|
|
308
|
+
} else if (event.key === "Escape") {
|
|
309
|
+
event.preventDefault();
|
|
310
|
+
cancelRename();
|
|
311
|
+
}
|
|
312
|
+
event.stopPropagation();
|
|
313
|
+
}
|
|
314
|
+
watch(draft, () => problem.value = "");
|
|
315
|
+
const menu = useTemplateRef("menu");
|
|
316
|
+
const menuOpen = ref(false);
|
|
317
|
+
const menuItems = shallowRef([]);
|
|
318
|
+
function openMenu(index, x, y) {
|
|
319
|
+
if (!editable.value) return;
|
|
320
|
+
show(index);
|
|
321
|
+
const m = messages.value;
|
|
322
|
+
const count = keys.value.length;
|
|
323
|
+
const name = doc.value.sheets[index].name;
|
|
324
|
+
menuItems.value = [
|
|
325
|
+
{
|
|
326
|
+
key: "rename",
|
|
327
|
+
label: m.renameSheet,
|
|
328
|
+
icon: PencilIcon,
|
|
329
|
+
disabled: !structural.value,
|
|
330
|
+
run: () => startRename(index)
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
key: "duplicate",
|
|
334
|
+
label: m.duplicateSheet,
|
|
335
|
+
icon: CopyPlusIcon,
|
|
336
|
+
disabled: !structural.value,
|
|
337
|
+
run: () => {
|
|
338
|
+
if (sheet.transact((tr) => tr.duplicateSheet(index), { action: "sheet" })) show(index + 1);
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
key: "left",
|
|
343
|
+
label: m.moveSheetLeft,
|
|
344
|
+
icon: ArrowLeftIcon,
|
|
345
|
+
divided: true,
|
|
346
|
+
disabled: !structural.value || index === 0,
|
|
347
|
+
run: () => moveTo(index, index - 1)
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
key: "right",
|
|
351
|
+
label: m.moveSheetRight,
|
|
352
|
+
icon: ArrowRightIcon,
|
|
353
|
+
disabled: !structural.value || index === count - 1,
|
|
354
|
+
run: () => moveTo(index, index + 1)
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
key: "delete",
|
|
358
|
+
label: m.deleteSheet,
|
|
359
|
+
icon: TrashIcon,
|
|
360
|
+
tone: "danger",
|
|
361
|
+
divided: true,
|
|
362
|
+
disabled: !structural.value || count < 2,
|
|
363
|
+
run: () => {
|
|
364
|
+
if (sheet.transact((tr) => tr.removeSheet(index), { action: "sheet" })) sheet.announce(format(m.sheetDeleted, { name }));
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
...["protect.sheet", "protect.workbook"].map((command, i) => {
|
|
368
|
+
const info = sheet.commands.get(command);
|
|
369
|
+
return {
|
|
370
|
+
key: command,
|
|
371
|
+
label: info.label,
|
|
372
|
+
icon: info.icon,
|
|
373
|
+
divided: i === 0,
|
|
374
|
+
disabled: !sheet.commands.can(command),
|
|
375
|
+
run: () => void sheet.commands.run(command)
|
|
376
|
+
};
|
|
377
|
+
})
|
|
378
|
+
];
|
|
379
|
+
menu.value?.open(x, y);
|
|
380
|
+
}
|
|
381
|
+
function moveTo(index, to) {
|
|
382
|
+
const name = doc.value.sheets[index].name;
|
|
383
|
+
if (!sheet.transact((tr) => tr.moveSheet(index, to), { action: "sheet" })) return;
|
|
384
|
+
sheet.announce(format(messages.value.sheetMoved, {
|
|
385
|
+
name,
|
|
386
|
+
index: to + 1,
|
|
387
|
+
count: keys.value.length
|
|
388
|
+
}));
|
|
389
|
+
nextTick(() => tabOf(to)?.focus());
|
|
390
|
+
}
|
|
391
|
+
function onMenuSelect(key) {
|
|
392
|
+
menuItems.value.find((item) => item.key === key)?.run?.();
|
|
393
|
+
}
|
|
394
|
+
function onContextMenu(event, index) {
|
|
395
|
+
event.preventDefault();
|
|
396
|
+
if (lastPointer === "touch" || renaming.value != null) return;
|
|
397
|
+
openMenu(index, event.clientX, event.clientY);
|
|
398
|
+
}
|
|
399
|
+
return (_ctx, _cache) => {
|
|
400
|
+
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
401
|
+
__props.addable && structural.value ? (openBlock(), createBlock(unref(DouButton), {
|
|
402
|
+
key: 0,
|
|
403
|
+
class: "dou-sheet-tabs__add",
|
|
404
|
+
variant: "ghost",
|
|
405
|
+
size: "sm",
|
|
406
|
+
"aria-label": unref(messages).addSheet,
|
|
407
|
+
title: unref(messages).addSheet,
|
|
408
|
+
onClick: addSheet
|
|
409
|
+
}, {
|
|
410
|
+
default: withCtx(() => [createVNode(unref(PlusIcon))]),
|
|
411
|
+
_: 1
|
|
412
|
+
}, 8, ["aria-label", "title"])) : createCommentVNode("", true),
|
|
413
|
+
createElementVNode("div", mergeProps({
|
|
414
|
+
ref_key: "container",
|
|
415
|
+
ref: container,
|
|
416
|
+
class: ["dou-sheet-tabs__list", {
|
|
417
|
+
"has-more-start": more.value.start,
|
|
418
|
+
"has-more-end": more.value.end
|
|
419
|
+
}],
|
|
420
|
+
role: "tablist",
|
|
421
|
+
"aria-label": unref(messages).sheets
|
|
422
|
+
}, unref(listAttrs), { onScrollPassive: measureMore }), [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(list), (key, index) => {
|
|
423
|
+
return openBlock(), createElementBlock("div", mergeProps({
|
|
424
|
+
key,
|
|
425
|
+
ref_for: true,
|
|
426
|
+
ref: "tab",
|
|
427
|
+
class: ["dou-sheet-tabs__tab", {
|
|
428
|
+
"is-active": indexOf(key) === unref(sheetIndex),
|
|
429
|
+
"is-renaming": renaming.value === indexOf(key)
|
|
430
|
+
}],
|
|
431
|
+
role: "tab",
|
|
432
|
+
"data-index": indexOf(key),
|
|
433
|
+
"aria-selected": indexOf(key) === unref(sheetIndex),
|
|
434
|
+
tabindex: indexOf(key) === unref(sheetIndex) ? 0 : -1,
|
|
435
|
+
"aria-describedby": hint
|
|
436
|
+
}, { ref_for: true }, dragAttrs(key, index), {
|
|
437
|
+
onPointerdown: ($event) => onPointerDown($event, key, index),
|
|
438
|
+
onClick: ($event) => onClick(indexOf(key), $event),
|
|
439
|
+
onDblclick: ($event) => onDblClick(indexOf(key)),
|
|
440
|
+
onKeydown: ($event) => onKeydown($event, indexOf(key)),
|
|
441
|
+
onContextmenu: ($event) => onContextMenu($event, indexOf(key))
|
|
442
|
+
}), [renaming.value === indexOf(key) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("span", _hoisted_4, toDisplayString(draft.value || " "), 1), withDirectives(createElementVNode("input", {
|
|
443
|
+
ref_for: true,
|
|
444
|
+
ref_key: "input",
|
|
445
|
+
ref: input,
|
|
446
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => draft.value = $event),
|
|
447
|
+
class: "dou-sheet-tabs__input",
|
|
448
|
+
"aria-label": unref(messages).renameSheet,
|
|
449
|
+
"aria-invalid": problem.value ? true : void 0,
|
|
450
|
+
title: problem.value || void 0,
|
|
451
|
+
maxlength: "100",
|
|
452
|
+
spellcheck: "false",
|
|
453
|
+
onKeydown: onInputKey,
|
|
454
|
+
onBlur: _cache[1] || (_cache[1] = ($event) => finishRename(false)),
|
|
455
|
+
onPointerdown: _cache[2] || (_cache[2] = withModifiers(() => {}, ["stop"])),
|
|
456
|
+
onClick: _cache[3] || (_cache[3] = withModifiers(() => {}, ["stop"])),
|
|
457
|
+
onDblclick: _cache[4] || (_cache[4] = withModifiers(() => {}, ["stop"]))
|
|
458
|
+
}, null, 40, _hoisted_5), [[vModelText, draft.value]])], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
459
|
+
isProtected(key) ? (openBlock(), createBlock(unref(LockIcon), {
|
|
460
|
+
key: 0,
|
|
461
|
+
class: "dou-sheet-tabs__lock",
|
|
462
|
+
"aria-hidden": "true"
|
|
463
|
+
})) : createCommentVNode("", true),
|
|
464
|
+
createElementVNode("span", _hoisted_6, toDisplayString(nameOf(key)), 1),
|
|
465
|
+
isProtected(key) ? (openBlock(), createElementBlock("span", _hoisted_7, toDisplayString(unref(messages).protect.protectedSheet), 1)) : createCommentVNode("", true)
|
|
466
|
+
], 64))], 16, _hoisted_3);
|
|
467
|
+
}), 128))], 16, _hoisted_2),
|
|
468
|
+
createElementVNode("span", {
|
|
469
|
+
id: hint,
|
|
470
|
+
class: "dou-sheet__sr-only"
|
|
471
|
+
}, toDisplayString(unref(messages).sheetTabKeys), 1),
|
|
472
|
+
problem.value ? (openBlock(), createElementBlock("div", _hoisted_8, toDisplayString(problem.value), 1)) : createCommentVNode("", true),
|
|
473
|
+
createVNode(sheet_menu_default, {
|
|
474
|
+
ref_key: "menu",
|
|
475
|
+
ref: menu,
|
|
476
|
+
open: menuOpen.value,
|
|
477
|
+
"onUpdate:open": _cache[5] || (_cache[5] = ($event) => menuOpen.value = $event),
|
|
478
|
+
items: menuItems.value,
|
|
479
|
+
onSelect: onMenuSelect
|
|
480
|
+
}, null, 8, ["open", "items"])
|
|
481
|
+
]);
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
export { sheet_tabs_vue_vue_type_script_setup_true_lang_default as default };
|
|
486
|
+
|
|
487
|
+
//# sourceMappingURL=sheet-tabs.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet-tabs.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_createBlock","_unref","_withCtx","_createVNode","_createCommentVNode","_createElementVNode","_mergeProps","_Fragment","_renderList","_toDisplayString","_withDirectives","_withModifiers","_vModelText","SheetMenu"],"sources":["../../src/components/sheet-tabs.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ArrowLeftIcon,\n ArrowRightIcon,\n CopyPlusIcon,\n LockIcon,\n PencilIcon,\n PlusIcon,\n TrashIcon,\n} from '@dou-ui/icons'\nimport { DouButton, isComposing, matchesHotkey, useSortable } from 'dou-ui'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n shallowRef,\n useId,\n useTemplateRef,\n watch,\n} from 'vue'\nimport { useSheet } from '../context'\nimport { sheetKey } from '../core/transaction'\nimport { format } from '../locale'\nimport type { SheetMenuItem } from '../types'\nimport SheetMenu from './sheet-menu.vue'\n\ndefineOptions({ name: 'DouSheetTabs' })\n\nwithDefaults(\n defineProps<{\n /** Whether to show the button that adds a sheet; `true` by default. */\n addable?: boolean\n }>(),\n { addable: true },\n)\n\nconst sheet = useSheet()\nconst { doc, sheetIndex, messages } = sheet\nconst uid = useId()\nconst hint = `${uid}-keys`\n\nconst editable = computed(() => !sheet.readonly.value)\n/** Whether sheets can be added, removed, moved and renamed: not while the workbook is protected. */\nconst structural = computed(() => editable.value && !doc.value.protect)\nconst isProtected = (key: string) => !!doc.value.sheets.find((s) => sheetKey(s) === key)?.protect\nconst keys = computed(() => doc.value.sheets.map(sheetKey))\n\n// Dragging tabs into another order --------------------------------------------------------\n\nconst order = computed({\n get: () => keys.value,\n set: () => {},\n})\nconst { container, list, listAttrs, itemAttrs, dragging } = useSortable<string>({\n items: order,\n key: (key) => key,\n direction: () => 'horizontal',\n disabled: () => !structural.value || renaming.value != null,\n label: (key) => nameOf(key),\n messages: () => ({\n item: messages.value.sheets,\n lifted: (label) => label,\n moved: (label, index, count) =>\n format(messages.value.sheetMoved, { name: label, index, count }),\n dropped: (label, index, count) =>\n format(messages.value.sheetMoved, { name: label, index, count }),\n canceled: (label) => label,\n }),\n // the copy that follows the pointer sits outside the grid: it takes the tab's font along\n ghost: (el) => {\n const copy = el.cloneNode(true) as HTMLElement\n const style = getComputedStyle(el)\n for (const name of ['font-family', 'font-size', 'font-weight', 'line-height', 'color'])\n copy.style.setProperty(name, style.getPropertyValue(name))\n copy.style.backgroundColor = 'var(--dou-color-bg-surface)'\n copy.style.borderColor = 'var(--dou-color-border)'\n return copy\n },\n onSort: ({ item, newIndex }) => {\n sheet.transact((tr) => tr.moveSheet(item, newIndex), { action: 'sheet' })\n },\n})\n\nconst nameOf = (key: string) => doc.value.sheets.find((s) => sheetKey(s) === key)?.name ?? key\nconst indexOf = (key: string) => keys.value.indexOf(key)\n\n/**\n * What sortable puts on each tab, but its keys: the tabs keep their own, and\n * the press goes through `onPointerDown`.\n */\nfunction dragAttrs(key: string, index: number) {\n const {\n onKeydown: _keys,\n onPointerdown: _press,\n tabindex: _tabindex,\n 'aria-roledescription': _role,\n ...rest\n } = itemAttrs(key, index)\n return rest\n}\n\n// Tabs past either side fade out there, so it shows that the strip scrolls\n\nconst more = ref({ start: false, end: false })\nfunction measureMore() {\n const el = container.value\n if (!el) return\n const start = el.scrollLeft > 1\n const end = el.scrollLeft + el.clientWidth < el.scrollWidth - 1\n if (start !== more.value.start || end !== more.value.end) more.value = { start, end }\n}\nlet resize: ResizeObserver | undefined\nonMounted(() => {\n measureMore()\n if (typeof ResizeObserver === 'undefined' || !container.value) return\n resize = new ResizeObserver(measureMore)\n resize.observe(container.value)\n})\nonBeforeUnmount(() => resize?.disconnect())\nwatch(keys, () => void nextTick(measureMore))\n\n// Switching ------------------------------------------------------------------------------\n\nconst tabs = useTemplateRef<HTMLElement[]>('tab')\nconst tabOf = (index: number) =>\n tabs.value?.find((el) => el.dataset.index === String(index)) ?? null\n\nfunction show(index: number, focusTab = false) {\n if (index < 0 || index >= keys.value.length) return\n if (index !== sheetIndex.value) {\n sheet.showSheet(index)\n sheet.announce(format(messages.value.sheetShown, { name: doc.value.sheets[index]!.name }))\n }\n if (focusTab) void nextTick(() => tabOf(index)?.focus())\n}\n\n// the tab shown is kept in view\nwatch(\n sheetIndex,\n (index) => {\n void nextTick(() => tabOf(index)?.scrollIntoView({ block: 'nearest', inline: 'nearest' }))\n },\n { flush: 'post' },\n)\n\nlet lastPointer = 'mouse'\n/** When a finger last switched sheets: a tap right after is the same double tap. */\nlet switchedAt = 0\n/** A finger held still on a tab opens its menu; the click that follows is then spent. */\nlet holdTimer: ReturnType<typeof setTimeout> | undefined\nlet held = false\nconst HOLD = 500\n\nfunction onPointerDown(event: PointerEvent, key: string, index: number) {\n lastPointer = event.pointerType\n held = false\n itemAttrs(key, index).onPointerdown(event)\n if (event.pointerType !== 'touch' || !editable.value) return\n const el = event.currentTarget as HTMLElement\n const x0 = event.clientX\n const y0 = event.clientY\n const stop = () => {\n clearTimeout(holdTimer)\n window.removeEventListener('pointermove', onMove)\n window.removeEventListener('pointerup', stop)\n window.removeEventListener('pointercancel', stop)\n }\n const onMove = (e: PointerEvent) => {\n if (Math.hypot(e.clientX - x0, e.clientY - y0) > 8) stop()\n }\n window.addEventListener('pointermove', onMove)\n window.addEventListener('pointerup', stop)\n window.addEventListener('pointercancel', stop)\n holdTimer = setTimeout(() => {\n stop()\n if (dragging.value != null || renaming.value != null) return\n held = true\n navigator.vibrate?.(8)\n const rect = el.getBoundingClientRect()\n openMenu(indexOf(key), rect.left + rect.width / 2, rect.top)\n }, HOLD)\n}\n\nfunction onClick(index: number, event: MouseEvent) {\n if (renaming.value != null) return\n if (held) {\n held = false\n return\n }\n if (lastPointer === 'touch' && index === sheetIndex.value) {\n // a finger on the tab already shown opens its menu: phones have no right click\n if (!editable.value || Date.now() - switchedAt < 400) return\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()\n return openMenu(index, rect.left + rect.width / 2, rect.top)\n }\n show(index)\n if (lastPointer === 'touch') switchedAt = Date.now()\n else sheet.focus()\n}\n\n/** A double click renames; a finger renames from the menu, as two taps also switch and open it. */\nfunction onDblClick(index: number) {\n if (lastPointer !== 'touch') startRename(index)\n}\n\nfunction onKeydown(event: KeyboardEvent, index: number) {\n if (isComposing(event)) return\n const count = keys.value.length\n const key = event.key\n let to = -1\n if (key === 'ArrowLeft') to = (index - 1 + count) % count\n else if (key === 'ArrowRight') to = (index + 1) % count\n else if (key === 'Home') to = 0\n else if (key === 'End') to = count - 1\n if (to !== -1) {\n event.preventDefault()\n return show(to, true)\n }\n if (key === 'F2' && editable.value) {\n event.preventDefault()\n return startRename(index)\n }\n if (key === 'ContextMenu' || (key === 'F10' && event.shiftKey)) {\n event.preventDefault()\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()\n return openMenu(index, rect.left + rect.width / 2, rect.top)\n }\n // what was just done to the tabs can be taken back from here too\n if (matchesHotkey(event, 'mod+z')) {\n event.preventDefault()\n sheet.undo()\n return keepFocus()\n }\n if (matchesHotkey(event, 'mod+shift+z') || matchesHotkey(event, 'mod+y')) {\n event.preventDefault()\n sheet.redo()\n return keepFocus()\n }\n if (key === 'Enter' || key === 'ArrowUp') {\n // into the grid of the sheet shown\n event.preventDefault()\n show(index)\n sheet.focus()\n }\n}\n\n/** Keeps the focus on the tabs, on the tab shown, after the tabs changed under it. */\nfunction keepFocus() {\n void nextTick(() => tabOf(sheetIndex.value)?.focus())\n}\n\n// Adding ---------------------------------------------------------------------------------\n\n/** The first free name like `工作表3`. */\nfunction freeName() {\n const taken = new Set(doc.value.sheets.map((s) => s.name))\n let n = doc.value.sheets.length + 1\n while (taken.has(format(messages.value.sheetName, { n }))) n++\n return format(messages.value.sheetName, { n })\n}\n\nfunction addSheet() {\n const name = freeName()\n const at = sheetIndex.value + 1\n const done = sheet.transact((tr) => tr.addSheet({ name }, at), { action: 'sheet' })\n if (!done) return\n show(at)\n sheet.announce(format(messages.value.sheetAdded, { name }))\n sheet.focus()\n}\n\n// Renaming -------------------------------------------------------------------------------\n\n/** The index of the tab being renamed, and what is typed. */\nconst renaming = ref<number | null>(null)\nconst draft = ref('')\nconst problem = ref('')\nconst input = useTemplateRef<HTMLInputElement[]>('input')\n\nfunction startRename(index: number) {\n if (!structural.value) return\n show(index)\n renaming.value = index\n draft.value = doc.value.sheets[index]!.name\n problem.value = ''\n void nextTick(() => {\n const el = input.value?.[0]\n el?.focus()\n el?.select()\n })\n}\n\nfunction check(name: string, index: number) {\n if (!name) return messages.value.sheetNameEmpty\n const taken = doc.value.sheets.some((s, i) => i !== index && s.name === name)\n return taken ? format(messages.value.sheetNameTaken, { name }) : ''\n}\n\n/** Writes the new name; with `keep`, a name that won't do keeps the field open. */\nfunction finishRename(keep: boolean) {\n const index = renaming.value\n if (index == null) return\n const name = draft.value.trim()\n const wrong = check(name, index)\n if (wrong && keep) {\n problem.value = wrong\n sheet.announce(wrong)\n return\n }\n renaming.value = null\n problem.value = ''\n if (!wrong && name !== doc.value.sheets[index]!.name)\n sheet.transact((tr) => tr.renameSheet(index, name), { action: 'sheet' })\n if (keep) void nextTick(() => tabOf(index)?.focus())\n}\n\nfunction cancelRename() {\n const index = renaming.value\n renaming.value = null\n problem.value = ''\n if (index != null) void nextTick(() => tabOf(index)?.focus())\n}\n\nfunction onInputKey(event: KeyboardEvent) {\n if (isComposing(event)) return\n if (event.key === 'Enter') {\n event.preventDefault()\n finishRename(true)\n } else if (event.key === 'Escape') {\n event.preventDefault()\n cancelRename()\n }\n // the tab's own keys are for the tabs, not the text\n event.stopPropagation()\n}\n\nwatch(draft, () => (problem.value = ''))\n\n// The menu -------------------------------------------------------------------------------\n\nconst menu = useTemplateRef<InstanceType<typeof SheetMenu>>('menu')\nconst menuOpen = ref(false)\nconst menuItems = shallowRef<SheetMenuItem[]>([])\n\nfunction openMenu(index: number, x: number, y: number) {\n if (!editable.value) return\n show(index)\n const m = messages.value\n const count = keys.value.length\n const name = doc.value.sheets[index]!.name\n menuItems.value = [\n {\n key: 'rename',\n label: m.renameSheet,\n icon: PencilIcon,\n disabled: !structural.value,\n run: () => startRename(index),\n },\n {\n key: 'duplicate',\n label: m.duplicateSheet,\n icon: CopyPlusIcon,\n disabled: !structural.value,\n run: () => {\n const done = sheet.transact((tr) => tr.duplicateSheet(index), { action: 'sheet' })\n if (done) show(index + 1)\n },\n },\n {\n key: 'left',\n label: m.moveSheetLeft,\n icon: ArrowLeftIcon,\n divided: true,\n disabled: !structural.value || index === 0,\n run: () => moveTo(index, index - 1),\n },\n {\n key: 'right',\n label: m.moveSheetRight,\n icon: ArrowRightIcon,\n disabled: !structural.value || index === count - 1,\n run: () => moveTo(index, index + 1),\n },\n {\n key: 'delete',\n label: m.deleteSheet,\n icon: TrashIcon,\n tone: 'danger',\n divided: true,\n disabled: !structural.value || count < 2,\n run: () => {\n const done = sheet.transact((tr) => tr.removeSheet(index), { action: 'sheet' })\n if (done) sheet.announce(format(m.sheetDeleted, { name }))\n },\n },\n ...(['protect.sheet', 'protect.workbook'] as const).map((command, i): SheetMenuItem => {\n const info = sheet.commands.get(command)!\n return {\n key: command,\n label: info.label,\n icon: info.icon,\n divided: i === 0,\n disabled: !sheet.commands.can(command),\n run: () => void sheet.commands.run(command),\n }\n }),\n ]\n menu.value?.open(x, y)\n}\n\nfunction moveTo(index: number, to: number) {\n const name = doc.value.sheets[index]!.name\n const done = sheet.transact((tr) => tr.moveSheet(index, to), { action: 'sheet' })\n if (!done) return\n sheet.announce(\n format(messages.value.sheetMoved, { name, index: to + 1, count: keys.value.length }),\n )\n void nextTick(() => tabOf(to)?.focus())\n}\n\nfunction onMenuSelect(key: unknown) {\n menuItems.value.find((item) => item.key === key)?.run?.()\n}\n\nfunction onContextMenu(event: MouseEvent, index: number) {\n event.preventDefault()\n if (lastPointer === 'touch' || renaming.value != null) return\n openMenu(index, event.clientX, event.clientY)\n}\n</script>\n\n<template>\n <div class=\"dou-sheet-tabs\">\n <DouButton\n v-if=\"addable && structural\"\n class=\"dou-sheet-tabs__add\"\n variant=\"ghost\"\n size=\"sm\"\n :aria-label=\"messages.addSheet\"\n :title=\"messages.addSheet\"\n @click=\"addSheet\"\n >\n <PlusIcon />\n </DouButton>\n <div\n ref=\"container\"\n class=\"dou-sheet-tabs__list\"\n :class=\"{ 'has-more-start': more.start, 'has-more-end': more.end }\"\n role=\"tablist\"\n :aria-label=\"messages.sheets\"\n v-bind=\"listAttrs\"\n @scroll.passive=\"measureMore\"\n >\n <div\n v-for=\"(key, index) in list\"\n :key=\"key\"\n ref=\"tab\"\n class=\"dou-sheet-tabs__tab\"\n :class=\"{\n 'is-active': indexOf(key) === sheetIndex,\n 'is-renaming': renaming === indexOf(key),\n }\"\n role=\"tab\"\n :data-index=\"indexOf(key)\"\n :aria-selected=\"indexOf(key) === sheetIndex\"\n :tabindex=\"indexOf(key) === sheetIndex ? 0 : -1\"\n :aria-describedby=\"hint\"\n v-bind=\"dragAttrs(key, index)\"\n @pointerdown=\"onPointerDown($event, key, index)\"\n @click=\"onClick(indexOf(key), $event)\"\n @dblclick=\"onDblClick(indexOf(key))\"\n @keydown=\"onKeydown($event, indexOf(key))\"\n @contextmenu=\"onContextMenu($event, indexOf(key))\"\n >\n <template v-if=\"renaming === indexOf(key)\">\n <!-- the hidden copy sizes the field to its text -->\n <span class=\"dou-sheet-tabs__size\" aria-hidden=\"true\">{{ draft || ' ' }}</span>\n <input\n ref=\"input\"\n v-model=\"draft\"\n class=\"dou-sheet-tabs__input\"\n :aria-label=\"messages.renameSheet\"\n :aria-invalid=\"problem ? true : undefined\"\n :title=\"problem || undefined\"\n maxlength=\"100\"\n spellcheck=\"false\"\n @keydown=\"onInputKey\"\n @blur=\"finishRename(false)\"\n @pointerdown.stop\n @click.stop\n @dblclick.stop\n />\n </template>\n <template v-else>\n <LockIcon v-if=\"isProtected(key)\" class=\"dou-sheet-tabs__lock\" aria-hidden=\"true\" />\n <span class=\"dou-sheet-tabs__name\">{{ nameOf(key) }}</span>\n <span v-if=\"isProtected(key)\" class=\"dou-sheet__sr-only\">\n {{ messages.protect.protectedSheet }}\n </span>\n </template>\n </div>\n </div>\n <span :id=\"hint\" class=\"dou-sheet__sr-only\">{{ messages.sheetTabKeys }}</span>\n <div v-if=\"problem\" class=\"dou-sheet-tabs__problem\" role=\"alert\">{{ problem }}</div>\n <SheetMenu ref=\"menu\" v-model:open=\"menuOpen\" :items=\"menuItems\" @select=\"onMenuSelect\" />\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import sheet_toolbar_vue_vue_type_script_setup_true_lang_default from "./sheet-toolbar.vue_vue_type_script_setup_true_lang.js";
|
|
2
|
+
// src/components/sheet-toolbar.vue
|
|
3
|
+
var sheet_toolbar_default = sheet_toolbar_vue_vue_type_script_setup_true_lang_default;
|
|
4
|
+
export { sheet_toolbar_default as default };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=sheet-toolbar.js.map
|