@veltra/desktop 1.0.9 → 1.0.11
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/dist/components/action/action-group.vue.d.ts +1 -1
- package/dist/components/action/action.vue.d.ts +3 -3
- package/dist/components/auto-complete/auto-complete.vue.d.ts +1 -1
- package/dist/components/batch-edit/batch-edit.js.map +1 -1
- package/dist/components/batch-edit/style.js +2 -2
- package/dist/components/batch-edit/use-edit.js.map +1 -1
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/button/button.vue.d.ts +1 -1
- package/dist/components/cascade/cascade.vue.d.ts +6 -6
- package/dist/components/cascade/use-select.js.map +1 -1
- package/dist/components/checkbox-group/checkbox-group.js.map +1 -1
- package/dist/components/code-editor/code-editor.js +2 -0
- package/dist/components/code-editor/code-editor.js.map +1 -1
- package/dist/components/date-panel/date-panel.js.map +1 -1
- package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
- package/dist/components/date-picker/date-picker.vue.d.ts +1 -1
- package/dist/components/date-range-picker/date-range-picker.vue.d.ts +1 -1
- package/dist/components/drawer/drawer.js.map +1 -1
- package/dist/components/expression-editor/expression-editor.js.map +1 -1
- package/dist/components/expression-editor/internal/editor-runtime/create-runtime.js.map +1 -1
- package/dist/components/expression-editor/internal/features/commands/register-command-packs.js.map +1 -1
- package/dist/components/expression-editor/internal/features/insertion/insertion-service.js.map +1 -1
- package/dist/components/expression-editor/use-decorators.js.map +1 -1
- package/dist/components/expression-editor/use-expression-drag-drop.js.map +1 -1
- package/dist/components/file-picker/file-picker.js.map +1 -1
- package/dist/components/file-picker/file-picker.vue.d.ts +1 -1
- package/dist/components/file-viewer/file-viewer.js +195 -30
- package/dist/components/file-viewer/file-viewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/docx-previewer.js +7 -5
- package/dist/components/file-viewer/previewers/docx-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/image-previewer.js +6 -6
- package/dist/components/file-viewer/previewers/image-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/pdf-previewer.js +5 -3
- package/dist/components/file-viewer/previewers/pdf-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/sheet-previewer.js.map +1 -1
- package/dist/components/file-viewer/style2.css +387 -136
- package/dist/components/form/form-model.js +2 -1
- package/dist/components/form/form-model.js.map +1 -1
- package/dist/components/grid/grid.js.map +1 -1
- package/dist/components/grid/use-responsive.js.map +1 -1
- package/dist/components/grid-input/grid-input.vue.d.ts +1 -1
- package/dist/components/input/input.vue.d.ts +3 -3
- package/dist/components/list/list.js.map +1 -1
- package/dist/components/loading/directive.js.map +1 -1
- package/dist/components/menu/menu-item.js.map +1 -1
- package/dist/components/message/message2.js.map +1 -1
- package/dist/components/multi-select/multi-select.js.map +1 -1
- package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
- package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +6 -6
- package/dist/components/notification/index.js.map +1 -1
- package/dist/components/notification/notification.vue.d.ts +1 -1
- package/dist/components/number-input/number-input.js.map +1 -1
- package/dist/components/number-input/number-input.vue.d.ts +1 -1
- package/dist/components/number-range-input/number-range-input.vue.d.ts +2 -2
- package/dist/components/palette/color-transform.js.map +1 -1
- package/dist/components/palette/palette-sv.js.map +1 -1
- package/dist/components/password-input/password-input.vue.d.ts +1 -1
- package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
- package/dist/components/progress/progress.js +1 -1
- package/dist/components/progress/progress.js.map +1 -1
- package/dist/components/progress-nodes/progress-nodes.js.map +1 -1
- package/dist/components/progress-nodes/progress-nodes.vue.d.ts +3 -3
- package/dist/components/rich-text-editor/rich-text-editor.js.map +1 -1
- package/dist/components/rich-text-editor/rich-text-editor.vue.d.ts +2 -2
- package/dist/components/rich-text-editor/toolbar.js.map +1 -1
- package/dist/components/scroll/scroll.js.map +1 -1
- package/dist/components/select/select.vue.d.ts +2 -2
- package/dist/components/slider/slider-thumb.js.map +1 -1
- package/dist/components/table/di.js.map +1 -1
- package/dist/components/table/style.js +1 -1
- package/dist/components/table/table-row.js +1 -2
- package/dist/components/table/table-row.js.map +1 -1
- package/dist/components/table/table.js +1 -2
- package/dist/components/table/table.js.map +1 -1
- package/dist/components/table/use-columns.js +4 -0
- package/dist/components/table/use-columns.js.map +1 -1
- package/dist/components/table/use-table.js +25 -0
- package/dist/components/table/use-table.js.map +1 -1
- package/dist/components/tabs/style2.css +3 -2
- package/dist/components/tabs/tabs-horizontal.js +2 -2
- package/dist/components/tabs/tabs-horizontal.js.map +1 -1
- package/dist/components/tabs/tabs-horizontal.vue.d.ts +14 -3
- package/dist/components/tabs/tabs-vertical.js +2 -2
- package/dist/components/tabs/tabs-vertical.js.map +1 -1
- package/dist/components/tabs/tabs-vertical.vue.d.ts +13 -3
- package/dist/components/tabs/tabs.vue.d.ts +2 -2
- package/dist/components/text/text.js.map +1 -1
- package/dist/components/textarea/textarea.js.map +1 -1
- package/dist/components/textarea/textarea.vue.d.ts +3 -3
- package/dist/components/theme/theme.js.map +1 -1
- package/dist/components/tip/tip.vue.d.ts +2 -2
- package/dist/components/tree/tree-node2.js.map +1 -1
- package/dist/components/tree/tree.vue.d.ts +2 -2
- package/dist/components/tree/use-tree-nodes.js.map +1 -1
- package/dist/components/tree-select/tree-select.vue.d.ts +4 -4
- package/dist/components/watermark/watermark.vue.d.ts +1 -1
- package/package.json +13 -12
- package/src/components/code-editor/code-editor.vue +2 -0
- package/src/components/file-viewer/file-viewer.vue +250 -24
- package/src/components/file-viewer/previewers/docx-previewer.vue +4 -3
- package/src/components/file-viewer/previewers/image-previewer.vue +4 -5
- package/src/components/file-viewer/previewers/pdf-previewer.vue +4 -3
- package/src/components/file-viewer/style.scss +503 -161
- package/src/components/progress/progress.vue +1 -1
- package/src/components/table/di.ts +51 -53
- package/src/components/table/table.vue +0 -1
- package/src/components/tabs/style.scss +7 -4
- package/src/components/tabs/tabs-horizontal.vue +10 -7
- package/src/components/tabs/tabs-vertical.vue +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-expression-drag-drop.js","names":[],"sources":["../../../src/components/expression-editor/use-expression-drag-drop.ts"],"sourcesContent":["import { $getNodeByKey, $getRoot, type LexicalEditor, type LexicalNode } from 'lexical'\n\nimport {\n EXPRESSION_DROP_SCOPE_ATTR,\n EXPRESSION_VARIABLE_DRAG_KEY_ATTR,\n EXPRESSION_VARIABLE_DRAG_MARKER_ATTR,\n EXPRESSION_VARIABLE_DRAG_TYPE\n} from './constants'\nimport { VariableNode } from './nodes/variable-node'\n\ntype Direction = -1 | 1\n\ninterface DragVisualState {\n indicatorEl: HTMLDivElement | null\n sourceEl: HTMLElement | null\n cleanupDragEnd: (() => void) | null\n activePayload: InternalDragPayload | null\n}\n\ninterface DropAnchor {\n x: number\n y: number\n height: number\n}\n\nexport interface VariableNodeDescriptor {\n key: string\n variable: string\n label: string\n}\n\nexport interface InternalDragPayload {\n sourceKey: string\n scopeId: string\n action: 'move-variable'\n}\n\nexport interface ApplyDropReorderOptions {\n payloadText: string | null\n scopeId: string\n targetSlot: number\n focusMovedNode?: boolean\n}\n\nconst DROP_INDICATOR_CLASS = 'expression-editor__drop-indicator'\nconst DRAG_SOURCE_CLASS = 'is-dragging'\n\nconst dragVisualStateMap = new WeakMap<LexicalEditor, DragVisualState>()\n\nfunction getDragVisualState(editor: LexicalEditor): DragVisualState {\n const existing = dragVisualStateMap.get(editor)\n if (existing) return existing\n\n const created: DragVisualState = {\n indicatorEl: null,\n sourceEl: null,\n cleanupDragEnd: null,\n activePayload: null\n }\n dragVisualStateMap.set(editor, created)\n return created\n}\n\nfunction isHTMLElement(target: EventTarget | null): target is HTMLElement {\n return target instanceof HTMLElement\n}\n\nfunction hasChildren(\n node: LexicalNode\n): node is LexicalNode & { getChildren: () => LexicalNode[] } {\n return typeof (node as { getChildren?: unknown }).getChildren === 'function'\n}\n\nfunction traverseVariableNodes(node: LexicalNode, collector: VariableNodeDescriptor[]): void {\n if (node instanceof VariableNode) {\n collector.push({ key: node.getKey(), variable: node.getVariable(), label: node.getLabel() })\n return\n }\n\n if (!hasChildren(node)) return\n node.getChildren().forEach((child) => traverseVariableNodes(child, collector))\n}\n\nfunction $collectVariableNodeDescriptors(): VariableNodeDescriptor[] {\n const collector: VariableNodeDescriptor[] = []\n const root = $getRoot()\n traverseVariableNodes(root, collector)\n return collector\n}\n\nfunction getDropIndicator(rootElement: HTMLElement): HTMLDivElement {\n const existing = rootElement.querySelector<HTMLDivElement>(`.${DROP_INDICATOR_CLASS}`)\n if (existing) return existing\n\n const indicator = document.createElement('div')\n indicator.className = DROP_INDICATOR_CLASS\n indicator.style.opacity = '0'\n rootElement.appendChild(indicator)\n return indicator\n}\n\nfunction getDropAnchors(editor: LexicalEditor): DropAnchor[] {\n const descriptors = collectVariableNodeDescriptors(editor)\n if (descriptors.length === 0) return []\n\n const rects = descriptors\n .map((descriptor) => editor.getElementByKey(descriptor.key))\n .filter((element): element is HTMLElement => element instanceof HTMLElement)\n .map((element) => element.getBoundingClientRect())\n\n if (rects.length === 0) return []\n\n const anchors: DropAnchor[] = []\n const first = rects[0]!\n anchors.push({ x: first.left, y: first.top, height: first.height })\n\n for (let index = 0; index < rects.length - 1; index++) {\n const currentRect = rects[index]!\n const nextRect = rects[index + 1]!\n anchors.push({\n x: (currentRect.right + nextRect.left) / 2,\n y: (currentRect.top + nextRect.top) / 2,\n height: Math.max(currentRect.height, nextRect.height)\n })\n }\n\n const last = rects[rects.length - 1]!\n anchors.push({ x: last.right, y: last.top, height: last.height })\n\n return anchors\n}\n\nfunction getDistance(pointerX: number, pointerY: number, anchor: DropAnchor): number {\n const dx = pointerX - anchor.x\n const dy = pointerY - (anchor.y + anchor.height / 2)\n return dx * dx + dy * dy\n}\n\nexport function supportsNativeDnD(): boolean {\n if (typeof window === 'undefined') return false\n\n const probe = document.createElement('span')\n const hasDragApi = 'draggable' in probe && typeof DataTransfer !== 'undefined'\n const coarsePointer = window.matchMedia?.('(pointer: coarse)').matches ?? false\n\n return hasDragApi && !coarsePointer\n}\n\nexport function collectVariableNodeDescriptors(editor: LexicalEditor): VariableNodeDescriptor[] {\n let descriptors: VariableNodeDescriptor[] = []\n editor.getEditorState().read(() => {\n descriptors = $collectVariableNodeDescriptors()\n })\n return descriptors\n}\n\nexport function ensureDropScopeId(editor: LexicalEditor): string {\n const rootElement = editor.getRootElement()\n if (!rootElement) return ''\n\n const existing = rootElement.getAttribute(EXPRESSION_DROP_SCOPE_ATTR)\n if (existing) return existing\n\n const generated = `scope-${Math.random().toString(36).slice(2)}`\n rootElement.setAttribute(EXPRESSION_DROP_SCOPE_ATTR, generated)\n return generated\n}\n\nexport function findVariableDragSource(target: EventTarget | null): HTMLElement | null {\n if (!isHTMLElement(target)) return null\n\n return target.closest<HTMLElement>(`[${EXPRESSION_VARIABLE_DRAG_MARKER_ATTR}=\"true\"]`)\n}\n\nexport function readDragSourceKey(target: EventTarget | null): string | null {\n const source = findVariableDragSource(target)\n if (!source) return null\n\n return source.getAttribute(EXPRESSION_VARIABLE_DRAG_KEY_ATTR)\n}\n\nexport function createInternalDragPayload(payload: InternalDragPayload): string {\n return JSON.stringify(payload)\n}\n\nexport function writeInternalDragPayload(\n dataTransfer: DataTransfer | null,\n payload: InternalDragPayload\n): void {\n if (!dataTransfer) return\n dataTransfer.setData(EXPRESSION_VARIABLE_DRAG_TYPE, createInternalDragPayload(payload))\n}\n\nexport function parseInternalDragPayload(payloadText: string | null): InternalDragPayload | null {\n if (!payloadText) return null\n\n try {\n const parsed = JSON.parse(payloadText) as Partial<InternalDragPayload>\n if (\n parsed.action !== 'move-variable' ||\n typeof parsed.scopeId !== 'string' ||\n parsed.scopeId.length === 0 ||\n typeof parsed.sourceKey !== 'string' ||\n parsed.sourceKey.length === 0\n ) {\n return null\n }\n\n return { action: parsed.action, scopeId: parsed.scopeId, sourceKey: parsed.sourceKey }\n } catch {\n return null\n }\n}\n\nexport function readInternalDragPayload(\n dataTransfer: DataTransfer | null\n): InternalDragPayload | null {\n if (!dataTransfer) return null\n return parseInternalDragPayload(dataTransfer.getData(EXPRESSION_VARIABLE_DRAG_TYPE))\n}\n\nexport function beginDragVisualState(\n editor: LexicalEditor,\n sourceEl: HTMLElement | null,\n payload?: InternalDragPayload\n): void {\n const state = getDragVisualState(editor)\n clearDragVisualState(editor)\n state.activePayload = payload ?? null\n\n if (!sourceEl) return\n sourceEl.classList.add(DRAG_SOURCE_CLASS)\n state.sourceEl = sourceEl\n\n const onDragEnd = () => {\n clearDragVisualState(editor)\n }\n window.addEventListener('dragend', onDragEnd, true)\n state.cleanupDragEnd = () => {\n window.removeEventListener('dragend', onDragEnd, true)\n }\n}\n\nexport function getActiveInternalDragPayload(editor: LexicalEditor): InternalDragPayload | null {\n return getDragVisualState(editor).activePayload\n}\n\nexport function showDropIndicator(editor: LexicalEditor, slot: number): void {\n const rootElement = editor.getRootElement()\n if (!rootElement) return\n\n const anchors = getDropAnchors(editor)\n if (slot < 0 || slot >= anchors.length) {\n clearDropIndicator(editor)\n return\n }\n\n const anchor = anchors[slot]!\n const indicator = getDropIndicator(rootElement)\n const rootRect = rootElement.getBoundingClientRect()\n\n indicator.style.left = `${anchor.x - rootRect.left}px`\n indicator.style.top = `${anchor.y - rootRect.top}px`\n indicator.style.height = `${anchor.height}px`\n indicator.style.opacity = '1'\n\n const state = getDragVisualState(editor)\n state.indicatorEl = indicator\n}\n\nexport function clearDropIndicator(editor: LexicalEditor): void {\n const state = getDragVisualState(editor)\n if (!state.indicatorEl) return\n state.indicatorEl.style.opacity = '0'\n}\n\nexport function clearDragVisualState(editor: LexicalEditor): void {\n const state = getDragVisualState(editor)\n\n if (state.sourceEl) {\n state.sourceEl.classList.remove(DRAG_SOURCE_CLASS)\n state.sourceEl = null\n }\n\n if (state.indicatorEl) {\n state.indicatorEl.style.opacity = '0'\n state.indicatorEl = null\n }\n\n if (state.cleanupDragEnd) {\n state.cleanupDragEnd()\n state.cleanupDragEnd = null\n }\n\n state.activePayload = null\n}\n\nexport function autoScrollWhenNearEdge(container: HTMLElement, pointerY: number): void {\n const rect = container.getBoundingClientRect()\n const threshold = 24\n const step = 10\n\n if (pointerY < rect.top + threshold) {\n container.scrollBy({ top: -step, behavior: 'auto' })\n return\n }\n\n if (pointerY > rect.bottom - threshold) {\n container.scrollBy({ top: step, behavior: 'auto' })\n }\n}\n\nexport function resolveDropSlot(editor: LexicalEditor, event: DragEvent): number | null {\n const rootElement = editor.getRootElement()\n if (!rootElement || !isHTMLElement(event.target)) return null\n if (!rootElement.contains(event.target)) return null\n\n const anchors = getDropAnchors(editor)\n if (anchors.length === 0) return null\n\n let nearestSlot = 0\n let nearestDistance = Number.POSITIVE_INFINITY\n for (let slot = 0; slot < anchors.length; slot++) {\n const anchor = anchors[slot]!\n const distance = getDistance(event.clientX, event.clientY, anchor)\n if (distance < nearestDistance) {\n nearestDistance = distance\n nearestSlot = slot\n }\n }\n\n return nearestSlot\n}\n\nexport function reorderVariableNode(\n sourceKey: string,\n targetSlot: number,\n focusMovedNode = true\n): boolean {\n const nodes = $collectVariableNodeDescriptors()\n if (nodes.length <= 1) return false\n\n const sourceIndex = nodes.findIndex((item) => item.key === sourceKey)\n if (sourceIndex < 0) return false\n if (targetSlot < 0 || targetSlot > nodes.length) return false\n if (targetSlot === sourceIndex || targetSlot === sourceIndex + 1) return false\n\n const sourceNode = $getNodeByKey(sourceKey)\n if (!(sourceNode instanceof VariableNode)) return false\n\n const remaining = nodes.filter((item) => item.key !== sourceKey)\n const insertionIndex = targetSlot > sourceIndex ? targetSlot - 1 : targetSlot\n const reference = remaining[insertionIndex]\n\n if (reference) {\n const referenceNode = $getNodeByKey(reference.key)\n if (!(referenceNode instanceof VariableNode)) return false\n referenceNode.insertBefore(sourceNode)\n } else {\n const last = remaining[remaining.length - 1]\n if (!last) return false\n const lastNode = $getNodeByKey(last.key)\n if (!(lastNode instanceof VariableNode)) return false\n lastNode.insertAfter(sourceNode)\n }\n\n if (focusMovedNode) {\n sourceNode.selectEnd()\n }\n\n return true\n}\n\nexport function moveVariableByDirection(\n sourceKey: string,\n direction: Direction,\n focusMovedNode = true\n): boolean {\n const nodes = $collectVariableNodeDescriptors()\n const sourceIndex = nodes.findIndex((item) => item.key === sourceKey)\n if (sourceIndex < 0) return false\n\n const targetIndex = sourceIndex + direction\n if (targetIndex < 0 || targetIndex >= nodes.length) return false\n\n const targetSlot = direction === -1 ? targetIndex : targetIndex + 1\n return reorderVariableNode(sourceKey, targetSlot, focusMovedNode)\n}\n\nexport function applyDropReorder(options: ApplyDropReorderOptions): boolean {\n const payload = parseInternalDragPayload(options.payloadText)\n if (!payload) return false\n if (payload.scopeId !== options.scopeId) return false\n\n return reorderVariableNode(payload.sourceKey, options.targetSlot, options.focusMovedNode ?? true)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-expression-drag-drop.js","names":[],"sources":["../../../src/components/expression-editor/use-expression-drag-drop.ts"],"sourcesContent":["import { $getNodeByKey, $getRoot, type LexicalEditor, type LexicalNode } from 'lexical'\n\nimport {\n EXPRESSION_DROP_SCOPE_ATTR,\n EXPRESSION_VARIABLE_DRAG_KEY_ATTR,\n EXPRESSION_VARIABLE_DRAG_MARKER_ATTR,\n EXPRESSION_VARIABLE_DRAG_TYPE\n} from './constants'\nimport { VariableNode } from './nodes/variable-node'\n\ntype Direction = -1 | 1\n\ninterface DragVisualState {\n indicatorEl: HTMLDivElement | null\n sourceEl: HTMLElement | null\n cleanupDragEnd: (() => void) | null\n activePayload: InternalDragPayload | null\n}\n\ninterface DropAnchor {\n x: number\n y: number\n height: number\n}\n\nexport interface VariableNodeDescriptor {\n key: string\n variable: string\n label: string\n}\n\nexport interface InternalDragPayload {\n sourceKey: string\n scopeId: string\n action: 'move-variable'\n}\n\nexport interface ApplyDropReorderOptions {\n payloadText: string | null\n scopeId: string\n targetSlot: number\n focusMovedNode?: boolean\n}\n\nconst DROP_INDICATOR_CLASS = 'expression-editor__drop-indicator'\nconst DRAG_SOURCE_CLASS = 'is-dragging'\n\nconst dragVisualStateMap = new WeakMap<LexicalEditor, DragVisualState>()\n\nfunction getDragVisualState(editor: LexicalEditor): DragVisualState {\n const existing = dragVisualStateMap.get(editor)\n if (existing) return existing\n\n const created: DragVisualState = {\n indicatorEl: null,\n sourceEl: null,\n cleanupDragEnd: null,\n activePayload: null\n }\n dragVisualStateMap.set(editor, created)\n return created\n}\n\nfunction isHTMLElement(target: EventTarget | null): target is HTMLElement {\n return target instanceof HTMLElement\n}\n\nfunction hasChildren(\n node: LexicalNode\n): node is LexicalNode & { getChildren: () => LexicalNode[] } {\n return typeof (node as { getChildren?: unknown }).getChildren === 'function'\n}\n\nfunction traverseVariableNodes(node: LexicalNode, collector: VariableNodeDescriptor[]): void {\n if (node instanceof VariableNode) {\n collector.push({ key: node.getKey(), variable: node.getVariable(), label: node.getLabel() })\n return\n }\n\n if (!hasChildren(node)) return\n node.getChildren().forEach((child) => traverseVariableNodes(child, collector))\n}\n\nfunction $collectVariableNodeDescriptors(): VariableNodeDescriptor[] {\n const collector: VariableNodeDescriptor[] = []\n const root = $getRoot()\n traverseVariableNodes(root, collector)\n return collector\n}\n\nfunction getDropIndicator(rootElement: HTMLElement): HTMLDivElement {\n const existing = rootElement.querySelector<HTMLDivElement>(`.${DROP_INDICATOR_CLASS}`)\n if (existing) return existing\n\n const indicator = document.createElement('div')\n indicator.className = DROP_INDICATOR_CLASS\n indicator.style.opacity = '0'\n rootElement.appendChild(indicator)\n return indicator\n}\n\nfunction getDropAnchors(editor: LexicalEditor): DropAnchor[] {\n const descriptors = collectVariableNodeDescriptors(editor)\n if (descriptors.length === 0) return []\n\n const rects = descriptors\n .map((descriptor) => editor.getElementByKey(descriptor.key))\n .filter((element): element is HTMLElement => element instanceof HTMLElement)\n .map((element) => element.getBoundingClientRect())\n\n if (rects.length === 0) return []\n\n const anchors: DropAnchor[] = []\n const first = rects[0]!\n anchors.push({ x: first.left, y: first.top, height: first.height })\n\n for (let index = 0; index < rects.length - 1; index++) {\n const currentRect = rects[index]!\n const nextRect = rects[index + 1]!\n anchors.push({\n x: (currentRect.right + nextRect.left) / 2,\n y: (currentRect.top + nextRect.top) / 2,\n height: Math.max(currentRect.height, nextRect.height)\n })\n }\n\n const last = rects[rects.length - 1]!\n anchors.push({ x: last.right, y: last.top, height: last.height })\n\n return anchors\n}\n\nfunction getDistance(pointerX: number, pointerY: number, anchor: DropAnchor): number {\n const dx = pointerX - anchor.x\n const dy = pointerY - (anchor.y + anchor.height / 2)\n return dx * dx + dy * dy\n}\n\nexport function supportsNativeDnD(): boolean {\n if (typeof window === 'undefined') return false\n\n const probe = document.createElement('span')\n const hasDragApi = 'draggable' in probe && typeof DataTransfer !== 'undefined'\n const coarsePointer = window.matchMedia?.('(pointer: coarse)').matches ?? false\n\n return hasDragApi && !coarsePointer\n}\n\nexport function collectVariableNodeDescriptors(editor: LexicalEditor): VariableNodeDescriptor[] {\n let descriptors: VariableNodeDescriptor[] = []\n editor.getEditorState().read(() => {\n descriptors = $collectVariableNodeDescriptors()\n })\n return descriptors\n}\n\nexport function ensureDropScopeId(editor: LexicalEditor): string {\n const rootElement = editor.getRootElement()\n if (!rootElement) return ''\n\n const existing = rootElement.getAttribute(EXPRESSION_DROP_SCOPE_ATTR)\n if (existing) return existing\n\n const generated = `scope-${Math.random().toString(36).slice(2)}`\n rootElement.setAttribute(EXPRESSION_DROP_SCOPE_ATTR, generated)\n return generated\n}\n\nexport function findVariableDragSource(target: EventTarget | null): HTMLElement | null {\n if (!isHTMLElement(target)) return null\n\n return target.closest<HTMLElement>(`[${EXPRESSION_VARIABLE_DRAG_MARKER_ATTR}=\"true\"]`)\n}\n\nexport function readDragSourceKey(target: EventTarget | null): string | null {\n const source = findVariableDragSource(target)\n if (!source) return null\n\n return source.getAttribute(EXPRESSION_VARIABLE_DRAG_KEY_ATTR)\n}\n\nexport function createInternalDragPayload(payload: InternalDragPayload): string {\n return JSON.stringify(payload)\n}\n\nexport function writeInternalDragPayload(\n dataTransfer: DataTransfer | null,\n payload: InternalDragPayload\n): void {\n if (!dataTransfer) return\n dataTransfer.setData(EXPRESSION_VARIABLE_DRAG_TYPE, createInternalDragPayload(payload))\n}\n\nexport function parseInternalDragPayload(payloadText: string | null): InternalDragPayload | null {\n if (!payloadText) return null\n\n try {\n const parsed = JSON.parse(payloadText) as Partial<InternalDragPayload>\n if (\n parsed.action !== 'move-variable' ||\n typeof parsed.scopeId !== 'string' ||\n parsed.scopeId.length === 0 ||\n typeof parsed.sourceKey !== 'string' ||\n parsed.sourceKey.length === 0\n ) {\n return null\n }\n\n return { action: parsed.action, scopeId: parsed.scopeId, sourceKey: parsed.sourceKey }\n } catch {\n return null\n }\n}\n\nexport function readInternalDragPayload(\n dataTransfer: DataTransfer | null\n): InternalDragPayload | null {\n if (!dataTransfer) return null\n return parseInternalDragPayload(dataTransfer.getData(EXPRESSION_VARIABLE_DRAG_TYPE))\n}\n\nexport function beginDragVisualState(\n editor: LexicalEditor,\n sourceEl: HTMLElement | null,\n payload?: InternalDragPayload\n): void {\n const state = getDragVisualState(editor)\n clearDragVisualState(editor)\n state.activePayload = payload ?? null\n\n if (!sourceEl) return\n sourceEl.classList.add(DRAG_SOURCE_CLASS)\n state.sourceEl = sourceEl\n\n const onDragEnd = () => {\n clearDragVisualState(editor)\n }\n window.addEventListener('dragend', onDragEnd, true)\n state.cleanupDragEnd = () => {\n window.removeEventListener('dragend', onDragEnd, true)\n }\n}\n\nexport function getActiveInternalDragPayload(editor: LexicalEditor): InternalDragPayload | null {\n return getDragVisualState(editor).activePayload\n}\n\nexport function showDropIndicator(editor: LexicalEditor, slot: number): void {\n const rootElement = editor.getRootElement()\n if (!rootElement) return\n\n const anchors = getDropAnchors(editor)\n if (slot < 0 || slot >= anchors.length) {\n clearDropIndicator(editor)\n return\n }\n\n const anchor = anchors[slot]!\n const indicator = getDropIndicator(rootElement)\n const rootRect = rootElement.getBoundingClientRect()\n\n indicator.style.left = `${anchor.x - rootRect.left}px`\n indicator.style.top = `${anchor.y - rootRect.top}px`\n indicator.style.height = `${anchor.height}px`\n indicator.style.opacity = '1'\n\n const state = getDragVisualState(editor)\n state.indicatorEl = indicator\n}\n\nexport function clearDropIndicator(editor: LexicalEditor): void {\n const state = getDragVisualState(editor)\n if (!state.indicatorEl) return\n state.indicatorEl.style.opacity = '0'\n}\n\nexport function clearDragVisualState(editor: LexicalEditor): void {\n const state = getDragVisualState(editor)\n\n if (state.sourceEl) {\n state.sourceEl.classList.remove(DRAG_SOURCE_CLASS)\n state.sourceEl = null\n }\n\n if (state.indicatorEl) {\n state.indicatorEl.style.opacity = '0'\n state.indicatorEl = null\n }\n\n if (state.cleanupDragEnd) {\n state.cleanupDragEnd()\n state.cleanupDragEnd = null\n }\n\n state.activePayload = null\n}\n\nexport function autoScrollWhenNearEdge(container: HTMLElement, pointerY: number): void {\n const rect = container.getBoundingClientRect()\n const threshold = 24\n const step = 10\n\n if (pointerY < rect.top + threshold) {\n container.scrollBy({ top: -step, behavior: 'auto' })\n return\n }\n\n if (pointerY > rect.bottom - threshold) {\n container.scrollBy({ top: step, behavior: 'auto' })\n }\n}\n\nexport function resolveDropSlot(editor: LexicalEditor, event: DragEvent): number | null {\n const rootElement = editor.getRootElement()\n if (!rootElement || !isHTMLElement(event.target)) return null\n if (!rootElement.contains(event.target)) return null\n\n const anchors = getDropAnchors(editor)\n if (anchors.length === 0) return null\n\n let nearestSlot = 0\n let nearestDistance = Number.POSITIVE_INFINITY\n for (let slot = 0; slot < anchors.length; slot++) {\n const anchor = anchors[slot]!\n const distance = getDistance(event.clientX, event.clientY, anchor)\n if (distance < nearestDistance) {\n nearestDistance = distance\n nearestSlot = slot\n }\n }\n\n return nearestSlot\n}\n\nexport function reorderVariableNode(\n sourceKey: string,\n targetSlot: number,\n focusMovedNode = true\n): boolean {\n const nodes = $collectVariableNodeDescriptors()\n if (nodes.length <= 1) return false\n\n const sourceIndex = nodes.findIndex((item) => item.key === sourceKey)\n if (sourceIndex < 0) return false\n if (targetSlot < 0 || targetSlot > nodes.length) return false\n if (targetSlot === sourceIndex || targetSlot === sourceIndex + 1) return false\n\n const sourceNode = $getNodeByKey(sourceKey)\n if (!(sourceNode instanceof VariableNode)) return false\n\n const remaining = nodes.filter((item) => item.key !== sourceKey)\n const insertionIndex = targetSlot > sourceIndex ? targetSlot - 1 : targetSlot\n const reference = remaining[insertionIndex]\n\n if (reference) {\n const referenceNode = $getNodeByKey(reference.key)\n if (!(referenceNode instanceof VariableNode)) return false\n referenceNode.insertBefore(sourceNode)\n } else {\n const last = remaining[remaining.length - 1]\n if (!last) return false\n const lastNode = $getNodeByKey(last.key)\n if (!(lastNode instanceof VariableNode)) return false\n lastNode.insertAfter(sourceNode)\n }\n\n if (focusMovedNode) {\n sourceNode.selectEnd()\n }\n\n return true\n}\n\nexport function moveVariableByDirection(\n sourceKey: string,\n direction: Direction,\n focusMovedNode = true\n): boolean {\n const nodes = $collectVariableNodeDescriptors()\n const sourceIndex = nodes.findIndex((item) => item.key === sourceKey)\n if (sourceIndex < 0) return false\n\n const targetIndex = sourceIndex + direction\n if (targetIndex < 0 || targetIndex >= nodes.length) return false\n\n const targetSlot = direction === -1 ? targetIndex : targetIndex + 1\n return reorderVariableNode(sourceKey, targetSlot, focusMovedNode)\n}\n\nexport function applyDropReorder(options: ApplyDropReorderOptions): boolean {\n const payload = parseInternalDragPayload(options.payloadText)\n if (!payload) return false\n if (payload.scopeId !== options.scopeId) return false\n\n return reorderVariableNode(payload.sourceKey, options.targetSlot, options.focusMovedNode ?? true)\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-picker.js","names":[],"sources":["../../../src/components/file-picker/file-picker.vue"],"sourcesContent":["<template>\n <component\n :is=\"tag\"\n :class=\"cls.b\"\n @click.stop=\"handleClickPicker\"\n @dragover.prevent=\"handleDragover\"\n @dragleave=\"handleDragLeave\"\n @drop.prevent=\"handleDrop\"\n >\n <input\n :multiple=\"multiple\"\n :class=\"cls.e('native')\"\n type=\"file\"\n :accept=\"accept\"\n hidden\n placeholder=\"选择文件\"\n ref=\"fileRef\"\n @change=\"handleChange\"\n capture=\"environment\"\n />\n <slot :is-dragover=\"isDragover\" />\n </component>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { shallowRef, ref } from 'vue'\n\nimport type { UploaderProps, UploaderEmits } from '../../types'\nimport { matchAccept } from './helper'\n\ndefineOptions({\n name: 'FilePicker'\n})\n\nconst props = withDefaults(defineProps<UploaderProps>(), {\n tag: 'div',\n multiple: false\n})\n\nconst emit = defineEmits<UploaderEmits>()\n\nconst cls = bem('file-picker')\n\nconst fileRef = shallowRef<HTMLInputElement>()\nconst isDragover = ref(false)\n\nconst processFiles = (files: File[]) => {\n const filteredFiles = files.filter((file) => matchAccept(file, props.accept))\n emit('pick', filteredFiles)\n}\n\nconst handleChange = (e: Event) => {\n const target = e.target as HTMLInputElement\n const files = Array.from(target.files || [])\n processFiles(files)\n target.value = ''\n}\n\nconst handleDragover = (e: DragEvent) => {\n if (props.disabled) return\n isDragover.value = true\n}\n\nconst handleDragLeave = (e: DragEvent) => {\n if (props.disabled) return\n const currentTarget = e.currentTarget as HTMLElement\n const relatedTarget = e.relatedTarget as HTMLElement | null\n\n if (currentTarget.contains(relatedTarget)) return\n isDragover.value = false\n}\n\nconst handleDrop = (e: DragEvent) => {\n if (props.disabled) return\n isDragover.value = false\n const files = Array.from(e.dataTransfer?.files || [])\n processFiles(files)\n}\n\nfunction handleClickPicker() {\n if (props.disabled) return\n fileRef.value?.click()\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;EAmCA,MAAM,QAAQ;EAKd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,cAAa;EAE7B,MAAM,UAAU,YAA6B;EAC7C,MAAM,aAAa,IAAI,MAAK;EAE5B,MAAM,gBAAgB,UAAkB;AAEtC,QAAK,QADiB,MAAM,QAAQ,SAAS,YAAY,MAAM,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"file-picker.js","names":[],"sources":["../../../src/components/file-picker/file-picker.vue"],"sourcesContent":["<template>\n <component\n :is=\"tag\"\n :class=\"cls.b\"\n @click.stop=\"handleClickPicker\"\n @dragover.prevent=\"handleDragover\"\n @dragleave=\"handleDragLeave\"\n @drop.prevent=\"handleDrop\"\n >\n <input\n :multiple=\"multiple\"\n :class=\"cls.e('native')\"\n type=\"file\"\n :accept=\"accept\"\n hidden\n placeholder=\"选择文件\"\n ref=\"fileRef\"\n @change=\"handleChange\"\n capture=\"environment\"\n />\n <slot :is-dragover=\"isDragover\" />\n </component>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { shallowRef, ref } from 'vue'\n\nimport type { UploaderProps, UploaderEmits } from '../../types'\nimport { matchAccept } from './helper'\n\ndefineOptions({\n name: 'FilePicker'\n})\n\nconst props = withDefaults(defineProps<UploaderProps>(), {\n tag: 'div',\n multiple: false\n})\n\nconst emit = defineEmits<UploaderEmits>()\n\nconst cls = bem('file-picker')\n\nconst fileRef = shallowRef<HTMLInputElement>()\nconst isDragover = ref(false)\n\nconst processFiles = (files: File[]) => {\n const filteredFiles = files.filter((file) => matchAccept(file, props.accept))\n emit('pick', filteredFiles)\n}\n\nconst handleChange = (e: Event) => {\n const target = e.target as HTMLInputElement\n const files = Array.from(target.files || [])\n processFiles(files)\n target.value = ''\n}\n\nconst handleDragover = (e: DragEvent) => {\n if (props.disabled) return\n isDragover.value = true\n}\n\nconst handleDragLeave = (e: DragEvent) => {\n if (props.disabled) return\n const currentTarget = e.currentTarget as HTMLElement\n const relatedTarget = e.relatedTarget as HTMLElement | null\n\n if (currentTarget.contains(relatedTarget)) return\n isDragover.value = false\n}\n\nconst handleDrop = (e: DragEvent) => {\n if (props.disabled) return\n isDragover.value = false\n const files = Array.from(e.dataTransfer?.files || [])\n processFiles(files)\n}\n\nfunction handleClickPicker() {\n if (props.disabled) return\n fileRef.value?.click()\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;EAmCA,MAAM,QAAQ;EAKd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,cAAa;EAE7B,MAAM,UAAU,YAA6B;EAC7C,MAAM,aAAa,IAAI,MAAK;EAE5B,MAAM,gBAAgB,UAAkB;AAEtC,QAAK,QADiB,MAAM,QAAQ,SAAS,YAAY,MAAM,MAAM,OAAO,CAC/D,CAAa;;EAG5B,MAAM,gBAAgB,MAAa;GACjC,MAAM,SAAS,EAAE;AAEjB,gBADc,MAAM,KAAK,OAAO,SAAS,EAAE,CAC9B,CAAK;AAClB,UAAO,QAAQ;;EAGjB,MAAM,kBAAkB,MAAiB;AACvC,OAAI,MAAM,SAAU;AACpB,cAAW,QAAQ;;EAGrB,MAAM,mBAAmB,MAAiB;AACxC,OAAI,MAAM,SAAU;GACpB,MAAM,gBAAgB,EAAE;GACxB,MAAM,gBAAgB,EAAE;AAExB,OAAI,cAAc,SAAS,cAAc,CAAE;AAC3C,cAAW,QAAQ;;EAGrB,MAAM,cAAc,MAAiB;AACnC,OAAI,MAAM,SAAU;AACpB,cAAW,QAAQ;AAEnB,gBADc,MAAM,KAAK,EAAE,cAAc,SAAS,EAAE,CACvC,CAAK;;EAGpB,SAAS,oBAAoB;AAC3B,OAAI,MAAM,SAAU;AACpB,WAAQ,OAAO,OAAM;;;uBAjFrB,YAoBY,wBAnBL,QAAA,IAAG,EAAA;IACP,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC;IACZ,SAAK,cAAO,mBAAiB,CAAA,OAAA,CAAA;IAC7B,YAAQ,cAAU,gBAAc,CAAA,UAAA,CAAA;IAChC,aAAW;IACX,QAAI,cAAU,YAAU,CAAA,UAAA,CAAA;;2BAYvB,CAVF,mBAUE,SAAA;KATC,UAAU,QAAA;KACV,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,SAAA,CAAA;KACb,MAAK;KACJ,QAAQ,QAAA;KACT,QAAA;KACA,aAAY;cACR;KAAJ,KAAI;KACH,UAAQ;KACT,SAAQ;8BAEV,WAAkC,KAAA,QAAA,WAAA,EAA3B,YAAa,WAAA,OAAU,CAAA,CAAA,CAAA"}
|
|
@@ -13,8 +13,8 @@ declare const __VLS_base: _$vue.DefineComponent<UploaderProps, {}, {}, {}, {}, _
|
|
|
13
13
|
}, string, _$vue.PublicProps, Readonly<UploaderProps> & Readonly<{
|
|
14
14
|
onPick?: ((files: File[]) => any) | undefined;
|
|
15
15
|
}>, {
|
|
16
|
-
tag: string;
|
|
17
16
|
multiple: boolean;
|
|
17
|
+
tag: string;
|
|
18
18
|
}, {}, {}, {}, string, _$vue.ComponentProvideOptions, false, {}, any>;
|
|
19
19
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
20
20
|
declare const _default: typeof __VLS_export;
|
|
@@ -2,15 +2,23 @@ import _sfc_main$1 from "../icon/icon.js";
|
|
|
2
2
|
import _sfc_main$2 from "../scroll/scroll.js";
|
|
3
3
|
import _sfc_main$3 from "../empty/empty.js";
|
|
4
4
|
import { FILE_VIEWER_KIND_LABEL, downloadFile, formatBytes, inferKind } from "./helper.js";
|
|
5
|
-
import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineAsyncComponent, defineComponent, mergeModels, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, openBlock, renderList, resolveDynamicComponent, shallowRef, toDisplayString, unref, useModel, watch, withCtx, withModifiers } from "vue";
|
|
5
|
+
import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineAsyncComponent, defineComponent, mergeModels, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, openBlock, ref, renderList, resolveDynamicComponent, shallowRef, toDisplayString, unref, useModel, watch, withCtx, withModifiers } from "vue";
|
|
6
6
|
import { bem, withUnit } from "@veltra/utils";
|
|
7
|
-
import { Close } from "@veltra/icons/normal";
|
|
7
|
+
import { ArrowLeft, ArrowRight, Close, Download, Refresh, ZoomIn, ZoomOut } from "@veltra/icons/normal";
|
|
8
8
|
//#region src/components/file-viewer/file-viewer.vue
|
|
9
9
|
const _hoisted_1 = ["tabindex"];
|
|
10
|
-
const _hoisted_2 = ["onClick"];
|
|
10
|
+
const _hoisted_2 = ["title", "onClick"];
|
|
11
11
|
const _hoisted_3 = ["title"];
|
|
12
|
-
const _hoisted_4 = ["
|
|
13
|
-
const _hoisted_5 =
|
|
12
|
+
const _hoisted_4 = ["title"];
|
|
13
|
+
const _hoisted_5 = { key: 0 };
|
|
14
|
+
const _hoisted_6 = ["disabled"];
|
|
15
|
+
const _hoisted_7 = ["disabled"];
|
|
16
|
+
const _hoisted_8 = ["disabled"];
|
|
17
|
+
const _hoisted_9 = ["disabled"];
|
|
18
|
+
const _hoisted_10 = ["disabled"];
|
|
19
|
+
const MIN_SCALE = .5;
|
|
20
|
+
const MAX_SCALE = 3;
|
|
21
|
+
const SCALE_STEP = .25;
|
|
14
22
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
15
23
|
name: "FileViewer",
|
|
16
24
|
inheritAttrs: false,
|
|
@@ -62,9 +70,19 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
62
70
|
const props = __props;
|
|
63
71
|
const emit = __emit;
|
|
64
72
|
const cls = bem("file-viewer");
|
|
73
|
+
const TRANSFORMABLE_KINDS = new Set([
|
|
74
|
+
"image",
|
|
75
|
+
"pdf",
|
|
76
|
+
"docx"
|
|
77
|
+
]);
|
|
65
78
|
const activeId = useModel(__props, "modelValue");
|
|
66
79
|
const openModel = useModel(__props, "open");
|
|
67
80
|
const rootRef = shallowRef();
|
|
81
|
+
const scale = ref(1);
|
|
82
|
+
const offsetX = ref(0);
|
|
83
|
+
const offsetY = ref(0);
|
|
84
|
+
const isDragging = ref(false);
|
|
85
|
+
let dragState;
|
|
68
86
|
const PreviewerMap = {
|
|
69
87
|
image: defineAsyncComponent(() => import("./previewers/image-previewer.js")),
|
|
70
88
|
video: defineAsyncComponent(() => import("./previewers/video-previewer.js")),
|
|
@@ -90,6 +108,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
90
108
|
});
|
|
91
109
|
/** 是否启用模态模式:只要父组件显式传入 open(含 v-model:open),即进入模态 */
|
|
92
110
|
const isModal = computed(() => openModel.value !== void 0);
|
|
111
|
+
const activeIndexLabel = computed(() => activeIndex.value >= 0 ? `${activeIndex.value + 1} / ${normalizedFiles.value.length}` : "");
|
|
112
|
+
const isTransformable = computed(() => !!activeFile.value && TRANSFORMABLE_KINDS.has(activeFile.value.kind));
|
|
113
|
+
const canPan = computed(() => isTransformable.value && scale.value > 1);
|
|
114
|
+
const zoomPercent = computed(() => `${Math.round(scale.value * 100)}%`);
|
|
115
|
+
const zoomInDisabled = computed(() => !isTransformable.value || scale.value >= MAX_SCALE);
|
|
116
|
+
const zoomOutDisabled = computed(() => !isTransformable.value || scale.value <= MIN_SCALE);
|
|
117
|
+
const isTransformReset = computed(() => scale.value === 1 && offsetX.value === 0 && offsetY.value === 0);
|
|
118
|
+
const previewerStyle = computed(() => {
|
|
119
|
+
if (!isTransformable.value) return void 0;
|
|
120
|
+
return { transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value})` };
|
|
121
|
+
});
|
|
93
122
|
function label(kind) {
|
|
94
123
|
return FILE_VIEWER_KIND_LABEL[kind];
|
|
95
124
|
}
|
|
@@ -111,6 +140,65 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
111
140
|
const target = normalizedFiles.value[i + 1];
|
|
112
141
|
if (target) activate(target.id);
|
|
113
142
|
}
|
|
143
|
+
function normalizeScale(value) {
|
|
144
|
+
return Math.round(Math.min(MAX_SCALE, Math.max(MIN_SCALE, value)) * 100) / 100;
|
|
145
|
+
}
|
|
146
|
+
function setScale(value) {
|
|
147
|
+
scale.value = normalizeScale(value);
|
|
148
|
+
if (scale.value <= 1) {
|
|
149
|
+
offsetX.value = 0;
|
|
150
|
+
offsetY.value = 0;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function zoomIn() {
|
|
154
|
+
if (!isTransformable.value) return;
|
|
155
|
+
setScale(scale.value + SCALE_STEP);
|
|
156
|
+
}
|
|
157
|
+
function zoomOut() {
|
|
158
|
+
if (!isTransformable.value) return;
|
|
159
|
+
setScale(scale.value - SCALE_STEP);
|
|
160
|
+
}
|
|
161
|
+
function resetTransform() {
|
|
162
|
+
scale.value = 1;
|
|
163
|
+
offsetX.value = 0;
|
|
164
|
+
offsetY.value = 0;
|
|
165
|
+
dragState = void 0;
|
|
166
|
+
isDragging.value = false;
|
|
167
|
+
}
|
|
168
|
+
function isInteractiveTarget(target) {
|
|
169
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
170
|
+
return !!target.closest("button, a, input, textarea, select, video, [contenteditable=\"true\"]");
|
|
171
|
+
}
|
|
172
|
+
function handleViewportPointerDown(e) {
|
|
173
|
+
if (!canPan.value || e.button !== 0 || isInteractiveTarget(e.target)) return;
|
|
174
|
+
dragState = {
|
|
175
|
+
pointerId: e.pointerId,
|
|
176
|
+
startX: e.clientX,
|
|
177
|
+
startY: e.clientY,
|
|
178
|
+
originX: offsetX.value,
|
|
179
|
+
originY: offsetY.value
|
|
180
|
+
};
|
|
181
|
+
isDragging.value = true;
|
|
182
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
183
|
+
e.preventDefault();
|
|
184
|
+
}
|
|
185
|
+
function handleViewportPointerMove(e) {
|
|
186
|
+
if (!dragState || dragState.pointerId !== e.pointerId) return;
|
|
187
|
+
offsetX.value = dragState.originX + e.clientX - dragState.startX;
|
|
188
|
+
offsetY.value = dragState.originY + e.clientY - dragState.startY;
|
|
189
|
+
}
|
|
190
|
+
function handleViewportPointerEnd(e) {
|
|
191
|
+
if (!dragState || dragState.pointerId !== e.pointerId) return;
|
|
192
|
+
const el = e.currentTarget;
|
|
193
|
+
if (el.hasPointerCapture(e.pointerId)) el.releasePointerCapture(e.pointerId);
|
|
194
|
+
dragState = void 0;
|
|
195
|
+
isDragging.value = false;
|
|
196
|
+
}
|
|
197
|
+
function handleViewportDblclick() {
|
|
198
|
+
if (!isTransformable.value) return;
|
|
199
|
+
if (scale.value === 1) setScale(2);
|
|
200
|
+
else resetTransform();
|
|
201
|
+
}
|
|
114
202
|
async function download() {
|
|
115
203
|
if (!activeFile.value) return;
|
|
116
204
|
try {
|
|
@@ -152,6 +240,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
152
240
|
}
|
|
153
241
|
if (!activeId.value || !files.some((f) => f.id === activeId.value)) activeId.value = files[0].id;
|
|
154
242
|
}, { immediate: true });
|
|
243
|
+
watch(() => activeFile.value?.id, () => resetTransform());
|
|
155
244
|
let previousBodyOverflow = "";
|
|
156
245
|
let isBodyLocked = false;
|
|
157
246
|
function lockBody() {
|
|
@@ -215,11 +304,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
215
304
|
return openBlock(), createElementBlock("li", {
|
|
216
305
|
key: f.id,
|
|
217
306
|
class: normalizeClass([unref(cls).e("item"), unref(bem).is("active", f.id === activeId.value)]),
|
|
307
|
+
title: f.name,
|
|
218
308
|
onClick: ($event) => activate(f.id)
|
|
219
|
-
}, [createElementVNode("span", { class: normalizeClass(
|
|
309
|
+
}, [createElementVNode("span", { class: normalizeClass(unref(cls).e("item-meta")) }, [createElementVNode("span", {
|
|
220
310
|
class: normalizeClass(unref(cls).e("item-name")),
|
|
221
311
|
title: f.name
|
|
222
|
-
}, toDisplayString(f.name), 11, _hoisted_3), createElementVNode("span", { class: normalizeClass(unref(cls).e("item-size")) }, toDisplayString(unref(formatBytes)(f.size)), 3)], 2)], 10, _hoisted_2);
|
|
312
|
+
}, toDisplayString(f.name), 11, _hoisted_3), createElementVNode("span", { class: normalizeClass(unref(cls).e("item-size")) }, toDisplayString(unref(formatBytes)(f.size)), 3)], 2), createElementVNode("span", { class: normalizeClass(unref(cls).e("item-kind")) }, toDisplayString(label(f.kind)), 3)], 10, _hoisted_2);
|
|
223
313
|
}), 128)), !normalizedFiles.value.length ? (openBlock(), createElementBlock("li", {
|
|
224
314
|
key: 0,
|
|
225
315
|
class: normalizeClass(unref(cls).e("list-empty"))
|
|
@@ -228,37 +318,93 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
228
318
|
size: 32
|
|
229
319
|
})], 2)) : createCommentVNode("v-if", true)]),
|
|
230
320
|
_: 1
|
|
231
|
-
}, 8, ["class"])], 6)) : createCommentVNode("v-if", true), createElementVNode("section", { class: normalizeClass(unref(cls).e("stage")) }, [createElementVNode("header", { class: normalizeClass(unref(cls).e("stage-head")) }, [createElementVNode("div", { class: normalizeClass(unref(cls).e("stage-title")) }, [
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
class: normalizeClass(unref(cls).e("action")),
|
|
321
|
+
}, 8, ["class"])], 6)) : createCommentVNode("v-if", true), createElementVNode("section", { class: normalizeClass(unref(cls).e("stage")) }, [createElementVNode("header", { class: normalizeClass(unref(cls).e("stage-head")) }, [createElementVNode("div", { class: normalizeClass(unref(cls).e("stage-title")) }, [activeFile.value ? (openBlock(), createElementBlock("span", {
|
|
322
|
+
key: 0,
|
|
323
|
+
class: normalizeClass([unref(cls).e("badge"), unref(cls).em("badge", activeFile.value.kind)])
|
|
324
|
+
}, toDisplayString(label(activeFile.value.kind)), 3)) : createCommentVNode("v-if", true), createElementVNode("span", { class: normalizeClass(unref(cls).e("stage-copy")) }, [createElementVNode("span", {
|
|
325
|
+
class: normalizeClass(unref(cls).e("stage-name")),
|
|
326
|
+
title: activeFile.value?.name
|
|
327
|
+
}, toDisplayString(activeFile.value?.name ?? "—"), 11, _hoisted_4), activeFile.value ? (openBlock(), createElementBlock("span", {
|
|
328
|
+
key: 0,
|
|
329
|
+
class: normalizeClass(unref(cls).e("stage-sub"))
|
|
330
|
+
}, [createElementVNode("span", null, toDisplayString(activeIndexLabel.value), 1), activeFile.value.size ? (openBlock(), createElementBlock("span", _hoisted_5, toDisplayString(unref(formatBytes)(activeFile.value.size)), 1)) : createCommentVNode("v-if", true)], 2)) : createCommentVNode("v-if", true)], 2)], 2), createElementVNode("div", { class: normalizeClass(unref(cls).e("stage-actions")) }, [
|
|
331
|
+
createElementVNode("span", { class: normalizeClass(unref(cls).e("action-group")) }, [createElementVNode("button", {
|
|
332
|
+
class: normalizeClass([unref(cls).e("action"), unref(cls).em("action", "icon")]),
|
|
244
333
|
disabled: !hasPrev.value,
|
|
245
334
|
type: "button",
|
|
335
|
+
"aria-label": "上一个",
|
|
336
|
+
title: "上一个",
|
|
246
337
|
onClick: prev
|
|
247
|
-
},
|
|
248
|
-
|
|
249
|
-
|
|
338
|
+
}, [createVNode(unref(_sfc_main$1), { size: 15 }, {
|
|
339
|
+
default: withCtx(() => [createVNode(unref(ArrowLeft))]),
|
|
340
|
+
_: 1
|
|
341
|
+
})], 10, _hoisted_6), createElementVNode("button", {
|
|
342
|
+
class: normalizeClass([unref(cls).e("action"), unref(cls).em("action", "icon")]),
|
|
250
343
|
disabled: !hasNext.value,
|
|
251
344
|
type: "button",
|
|
345
|
+
"aria-label": "下一个",
|
|
346
|
+
title: "下一个",
|
|
252
347
|
onClick: next
|
|
253
|
-
},
|
|
254
|
-
|
|
348
|
+
}, [createVNode(unref(_sfc_main$1), { size: 15 }, {
|
|
349
|
+
default: withCtx(() => [createVNode(unref(ArrowRight))]),
|
|
350
|
+
_: 1
|
|
351
|
+
})], 10, _hoisted_7)], 2),
|
|
352
|
+
isTransformable.value ? (openBlock(), createElementBlock("span", {
|
|
255
353
|
key: 0,
|
|
256
|
-
class: normalizeClass(
|
|
354
|
+
class: normalizeClass(unref(cls).e("action-group"))
|
|
355
|
+
}, [
|
|
356
|
+
createElementVNode("button", {
|
|
357
|
+
class: normalizeClass([unref(cls).e("action"), unref(cls).em("action", "icon")]),
|
|
358
|
+
disabled: zoomOutDisabled.value,
|
|
359
|
+
type: "button",
|
|
360
|
+
"aria-label": "缩小",
|
|
361
|
+
title: "缩小",
|
|
362
|
+
onClick: zoomOut
|
|
363
|
+
}, [createVNode(unref(_sfc_main$1), { size: 15 }, {
|
|
364
|
+
default: withCtx(() => [createVNode(unref(ZoomOut))]),
|
|
365
|
+
_: 1
|
|
366
|
+
})], 10, _hoisted_8),
|
|
367
|
+
createElementVNode("span", { class: normalizeClass(unref(cls).e("zoom-value")) }, toDisplayString(zoomPercent.value), 3),
|
|
368
|
+
createElementVNode("button", {
|
|
369
|
+
class: normalizeClass([unref(cls).e("action"), unref(cls).em("action", "icon")]),
|
|
370
|
+
disabled: zoomInDisabled.value,
|
|
371
|
+
type: "button",
|
|
372
|
+
"aria-label": "放大",
|
|
373
|
+
title: "放大",
|
|
374
|
+
onClick: zoomIn
|
|
375
|
+
}, [createVNode(unref(_sfc_main$1), { size: 15 }, {
|
|
376
|
+
default: withCtx(() => [createVNode(unref(ZoomIn))]),
|
|
377
|
+
_: 1
|
|
378
|
+
})], 10, _hoisted_9),
|
|
379
|
+
createElementVNode("button", {
|
|
380
|
+
class: normalizeClass([unref(cls).e("action"), unref(cls).em("action", "icon")]),
|
|
381
|
+
disabled: isTransformReset.value,
|
|
382
|
+
type: "button",
|
|
383
|
+
"aria-label": "重置视图",
|
|
384
|
+
title: "重置视图",
|
|
385
|
+
onClick: resetTransform
|
|
386
|
+
}, [createVNode(unref(_sfc_main$1), { size: 15 }, {
|
|
387
|
+
default: withCtx(() => [createVNode(unref(Refresh))]),
|
|
388
|
+
_: 1
|
|
389
|
+
})], 10, _hoisted_10)
|
|
390
|
+
], 2)) : createCommentVNode("v-if", true),
|
|
391
|
+
__props.downloadable && activeFile.value ? (openBlock(), createElementBlock("button", {
|
|
392
|
+
key: 1,
|
|
393
|
+
class: normalizeClass([
|
|
394
|
+
unref(cls).e("action"),
|
|
395
|
+
unref(cls).em("action", "primary"),
|
|
396
|
+
unref(cls).em("action", "icon")
|
|
397
|
+
]),
|
|
257
398
|
type: "button",
|
|
399
|
+
"aria-label": "下载",
|
|
400
|
+
title: "下载",
|
|
258
401
|
onClick: download
|
|
259
|
-
},
|
|
402
|
+
}, [createVNode(unref(_sfc_main$1), { size: 15 }, {
|
|
403
|
+
default: withCtx(() => [createVNode(unref(Download))]),
|
|
404
|
+
_: 1
|
|
405
|
+
})], 2)) : createCommentVNode("v-if", true),
|
|
260
406
|
isModal.value ? (openBlock(), createElementBlock("button", {
|
|
261
|
-
key:
|
|
407
|
+
key: 2,
|
|
262
408
|
class: normalizeClass([unref(cls).e("action"), unref(cls).em("action", "icon")]),
|
|
263
409
|
type: "button",
|
|
264
410
|
"aria-label": "关闭预览",
|
|
@@ -272,12 +418,31 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
272
418
|
name: "u-file-viewer-fade",
|
|
273
419
|
mode: "out-in"
|
|
274
420
|
}, {
|
|
275
|
-
default: withCtx(() => [activeFile.value ? (openBlock(),
|
|
421
|
+
default: withCtx(() => [activeFile.value ? (openBlock(), createElementBlock("div", {
|
|
276
422
|
key: activeFile.value.id,
|
|
423
|
+
class: normalizeClass([
|
|
424
|
+
unref(cls).e("viewport"),
|
|
425
|
+
unref(bem).is("transformable", isTransformable.value),
|
|
426
|
+
unref(bem).is("pannable", canPan.value),
|
|
427
|
+
unref(bem).is("dragging", isDragging.value)
|
|
428
|
+
]),
|
|
429
|
+
onPointerdown: handleViewportPointerDown,
|
|
430
|
+
onPointermove: handleViewportPointerMove,
|
|
431
|
+
onPointerup: handleViewportPointerEnd,
|
|
432
|
+
onPointercancel: handleViewportPointerEnd,
|
|
433
|
+
onDblclick: handleViewportDblclick
|
|
434
|
+
}, [(openBlock(), createBlock(resolveDynamicComponent(PreviewerMap[activeFile.value.kind]), {
|
|
277
435
|
file: activeFile.value,
|
|
278
436
|
"max-rows": __props.sheetMaxRows,
|
|
437
|
+
class: normalizeClass(isTransformable.value ? unref(cls).e("previewer") : void 0),
|
|
438
|
+
style: normalizeStyle(previewerStyle.value),
|
|
279
439
|
onError: handleChildError
|
|
280
|
-
}, null, 40, [
|
|
440
|
+
}, null, 40, [
|
|
441
|
+
"file",
|
|
442
|
+
"max-rows",
|
|
443
|
+
"class",
|
|
444
|
+
"style"
|
|
445
|
+
]))], 34)) : (openBlock(), createElementBlock("div", {
|
|
281
446
|
key: 1,
|
|
282
447
|
class: normalizeClass(unref(cls).e("empty"))
|
|
283
448
|
}, [createVNode(unref(_sfc_main$3), { text: "暂无可预览文件" })], 2))]),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-viewer.js","names":[],"sources":["../../../src/components/file-viewer/file-viewer.vue"],"sourcesContent":["<template>\n <Teleport to=\"body\" :disabled=\"!isModal\">\n <transition :name=\"isModal ? 'u-file-viewer-modal' : ''\">\n <div\n v-if=\"!isModal || openModel\"\n :class=\"[cls.b, bem.is('modal', isModal)]\"\n :tabindex=\"isModal ? -1 : undefined\"\n ref=\"rootRef\"\n @mousedown.self=\"handleBackdropMousedown\"\n >\n <div v-if=\"isModal\" :class=\"cls.e('backdrop')\" @mousedown.self=\"handleBackdropMousedown\" />\n <div :class=\"cls.e('inner')\">\n <aside v-if=\"showSidebar\" :class=\"cls.e('sidebar')\" :style=\"{ width: sidebarWidthCss }\">\n <header :class=\"cls.e('sidebar-head')\">\n <span :class=\"cls.e('sidebar-title')\">文件</span>\n <span :class=\"cls.e('sidebar-count')\">{{ normalizedFiles.length }}</span>\n </header>\n <u-scroll tag=\"ul\" :class=\"cls.e('list')\">\n <li\n v-for=\"f in normalizedFiles\"\n :key=\"f.id\"\n :class=\"[cls.e('item'), bem.is('active', f.id === activeId)]\"\n @click=\"activate(f.id)\"\n >\n <span :class=\"[cls.e('badge'), cls.em('badge', f.kind)]\">\n {{ label(f.kind) }}\n </span>\n <span :class=\"cls.e('item-meta')\">\n <span :class=\"cls.e('item-name')\" :title=\"f.name\">{{ f.name }}</span>\n <span :class=\"cls.e('item-size')\">{{ formatBytes(f.size) }}</span>\n </span>\n </li>\n <li v-if=\"!normalizedFiles.length\" :class=\"cls.e('list-empty')\">\n <u-empty text=\"暂无文件\" :size=\"32\" />\n </li>\n </u-scroll>\n </aside>\n\n <section :class=\"cls.e('stage')\">\n <header :class=\"cls.e('stage-head')\">\n <div :class=\"cls.e('stage-title')\">\n <span v-if=\"activeFile\" :class=\"[cls.e('badge'), cls.em('badge', activeFile.kind)]\">\n {{ label(activeFile.kind) }}\n </span>\n <span :class=\"cls.e('stage-name')\">\n {{ activeFile?.name ?? '—' }}\n </span>\n <span v-if=\"activeFile?.size\" :class=\"cls.e('stage-sub')\">\n {{ formatBytes(activeFile.size) }}\n </span>\n </div>\n <div :class=\"cls.e('stage-actions')\">\n <button :class=\"cls.e('action')\" :disabled=\"!hasPrev\" type=\"button\" @click=\"prev\">\n 上一个\n </button>\n <button :class=\"cls.e('action')\" :disabled=\"!hasNext\" type=\"button\" @click=\"next\">\n 下一个\n </button>\n <button\n v-if=\"downloadable && activeFile\"\n :class=\"[cls.e('action'), cls.em('action', 'primary')]\"\n type=\"button\"\n @click=\"download\"\n >\n 下载\n </button>\n <button\n v-if=\"isModal\"\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"关闭预览\"\n title=\"关闭\"\n @click=\"handleClose\"\n >\n <u-icon :size=\"16\">\n <Close />\n </u-icon>\n </button>\n </div>\n </header>\n <div :class=\"cls.e('body')\">\n <transition name=\"u-file-viewer-fade\" mode=\"out-in\">\n <component\n :is=\"PreviewerMap[activeFile.kind]\"\n v-if=\"activeFile\"\n :key=\"activeFile.id\"\n :file=\"activeFile\"\n :max-rows=\"sheetMaxRows\"\n @error=\"handleChildError\"\n />\n <div v-else :class=\"cls.e('empty')\">\n <u-empty text=\"暂无可预览文件\" />\n </div>\n </transition>\n </div>\n </section>\n </div>\n </div>\n </transition>\n </Teleport>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Close } from '@veltra/icons/normal'\nimport { bem, withUnit } from '@veltra/utils'\nimport { computed, defineAsyncComponent, nextTick, onBeforeUnmount, shallowRef, watch } from 'vue'\n\nimport type {\n _FileViewerExposed,\n FileViewerEmits,\n FileViewerItem,\n FileViewerKind,\n FileViewerProps\n} from '../../types/file-viewer'\nimport { UEmpty } from '../empty'\nimport { UIcon } from '../icon'\nimport { UScroll } from '../scroll'\nimport { FILE_VIEWER_KIND_LABEL, downloadFile, formatBytes, inferKind } from './helper'\n\ndefineOptions({\n name: 'FileViewer',\n inheritAttrs: false\n})\n\nconst props = withDefaults(defineProps<FileViewerProps>(), {\n modelValue: undefined,\n sidebarWidth: '280px',\n sheetMaxRows: 50_000,\n downloadable: true,\n open: undefined,\n closeOnClickBackdrop: true,\n closeOnEsc: true\n})\n\nconst emit = defineEmits<FileViewerEmits>()\n\nconst cls = bem('file-viewer')\n\nconst activeId = defineModel<string | undefined>('modelValue', { default: undefined })\nconst openModel = defineModel<boolean | undefined>('open', { default: undefined })\n\nconst rootRef = shallowRef<HTMLDivElement>()\n\nconst PreviewerMap: Record<FileViewerKind, ReturnType<typeof defineAsyncComponent>> = {\n image: defineAsyncComponent(() => import('./previewers/image-previewer.vue')),\n video: defineAsyncComponent(() => import('./previewers/video-previewer.vue')),\n pdf: defineAsyncComponent(() => import('./previewers/pdf-previewer.vue')),\n sheet: defineAsyncComponent(() => import('./previewers/sheet-previewer.vue')),\n docx: defineAsyncComponent(() => import('./previewers/docx-previewer.vue')),\n text: defineAsyncComponent(() => import('./previewers/text-previewer.vue'))\n}\n\ninterface NormalizedFile extends FileViewerItem {\n id: string\n kind: FileViewerKind\n}\n\nconst normalizedFiles = computed<NormalizedFile[]>(() =>\n props.files.map((f, i) => ({\n ...f,\n id: f.id ?? `file-${i}`,\n kind: inferKind(f.name, f.kind)\n }))\n)\n\nconst activeFile = computed<NormalizedFile | undefined>(() =>\n normalizedFiles.value.find((f) => f.id === activeId.value)\n)\n\nconst activeIndex = computed(() => normalizedFiles.value.findIndex((f) => f.id === activeId.value))\n\nconst hasPrev = computed(() => activeIndex.value > 0)\nconst hasNext = computed(\n () => activeIndex.value >= 0 && activeIndex.value < normalizedFiles.value.length - 1\n)\n\nconst showSidebar = computed(() => props.sidebarWidth !== false && props.sidebarWidth !== 0)\n\nconst sidebarWidthCss = computed(() => {\n const w = props.sidebarWidth\n if (w === false || w === 0) return undefined\n return withUnit(w ?? '280px', 'px')\n})\n\n/** 是否启用模态模式:只要父组件显式传入 open(含 v-model:open),即进入模态 */\nconst isModal = computed(() => openModel.value !== undefined)\n\nfunction label(kind: FileViewerKind): string {\n return FILE_VIEWER_KIND_LABEL[kind]\n}\n\nfunction activate(id: string) {\n if (activeId.value === id) return\n activeId.value = id\n const f = normalizedFiles.value.find((x) => x.id === id)\n if (f) emit('change', f)\n}\n\nfunction prev() {\n const i = activeIndex.value\n if (i <= 0) return\n const target = normalizedFiles.value[i - 1]\n if (target) activate(target.id)\n}\n\nfunction next() {\n const i = activeIndex.value\n if (i < 0 || i >= normalizedFiles.value.length - 1) return\n const target = normalizedFiles.value[i + 1]\n if (target) activate(target.id)\n}\n\nasync function download() {\n if (!activeFile.value) return\n try {\n await downloadFile(activeFile.value)\n } catch (err) {\n emit('error', { file: activeFile.value, error: err })\n }\n}\n\nfunction handleChildError(err: unknown) {\n if (!activeFile.value) return\n emit('error', { file: activeFile.value, error: err })\n}\n\nfunction handleClose() {\n if (!isModal.value) return\n openModel.value = false\n}\n\nfunction handleWindowKeydown(e: KeyboardEvent) {\n if (e.key !== 'Escape') return\n if (!isModal.value || !openModel.value) return\n if (props.closeOnEsc === false) return\n e.stopPropagation()\n handleClose()\n}\n\nfunction handleBackdropMousedown() {\n if (!isModal.value) return\n if (props.closeOnClickBackdrop === false) return\n handleClose()\n}\n\nwatch(\n normalizedFiles,\n (files) => {\n if (!files.length) {\n activeId.value = undefined\n return\n }\n if (!activeId.value || !files.some((f) => f.id === activeId.value)) {\n activeId.value = files[0]!.id\n }\n },\n { immediate: true }\n)\n\n// 模态打开时:锁定 body 滚动 + 让容器获得焦点以便接收 ESC\nlet previousBodyOverflow = ''\nlet isBodyLocked = false\n\nfunction lockBody() {\n if (isBodyLocked || typeof document === 'undefined') return\n previousBodyOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n isBodyLocked = true\n}\n\nfunction unlockBody() {\n if (!isBodyLocked || typeof document === 'undefined') return\n document.body.style.overflow = previousBodyOverflow\n isBodyLocked = false\n}\n\nwatch(\n [isModal, openModel],\n ([modal, open]) => {\n if (modal && open) {\n lockBody()\n nextTick(() => {\n rootRef.value?.focus()\n })\n if (typeof window !== 'undefined') {\n window.addEventListener('keydown', handleWindowKeydown, true)\n }\n } else {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n }\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n})\n\ndefineExpose<_FileViewerExposed>({\n activeId,\n activate,\n next,\n prev\n})\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"file-viewer.js","names":[],"sources":["../../../src/components/file-viewer/file-viewer.vue"],"sourcesContent":["<template>\n <Teleport to=\"body\" :disabled=\"!isModal\">\n <transition :name=\"isModal ? 'u-file-viewer-modal' : ''\">\n <div\n v-if=\"!isModal || openModel\"\n :class=\"[cls.b, bem.is('modal', isModal)]\"\n :tabindex=\"isModal ? -1 : undefined\"\n ref=\"rootRef\"\n @mousedown.self=\"handleBackdropMousedown\"\n >\n <div v-if=\"isModal\" :class=\"cls.e('backdrop')\" @mousedown.self=\"handleBackdropMousedown\" />\n <div :class=\"cls.e('inner')\">\n <aside v-if=\"showSidebar\" :class=\"cls.e('sidebar')\" :style=\"{ width: sidebarWidthCss }\">\n <header :class=\"cls.e('sidebar-head')\">\n <span :class=\"cls.e('sidebar-title')\">文件</span>\n <span :class=\"cls.e('sidebar-count')\">{{ normalizedFiles.length }}</span>\n </header>\n <u-scroll tag=\"ul\" :class=\"cls.e('list')\">\n <li\n v-for=\"f in normalizedFiles\"\n :key=\"f.id\"\n :class=\"[cls.e('item'), bem.is('active', f.id === activeId)]\"\n :title=\"f.name\"\n @click=\"activate(f.id)\"\n >\n <span :class=\"cls.e('item-meta')\">\n <span :class=\"cls.e('item-name')\" :title=\"f.name\">{{ f.name }}</span>\n <span :class=\"cls.e('item-size')\">{{ formatBytes(f.size) }}</span>\n </span>\n <span :class=\"cls.e('item-kind')\">{{ label(f.kind) }}</span>\n </li>\n <li v-if=\"!normalizedFiles.length\" :class=\"cls.e('list-empty')\">\n <u-empty text=\"暂无文件\" :size=\"32\" />\n </li>\n </u-scroll>\n </aside>\n\n <section :class=\"cls.e('stage')\">\n <header :class=\"cls.e('stage-head')\">\n <div :class=\"cls.e('stage-title')\">\n <span v-if=\"activeFile\" :class=\"[cls.e('badge'), cls.em('badge', activeFile.kind)]\">\n {{ label(activeFile.kind) }}\n </span>\n <span :class=\"cls.e('stage-copy')\">\n <span :class=\"cls.e('stage-name')\" :title=\"activeFile?.name\">\n {{ activeFile?.name ?? '—' }}\n </span>\n <span v-if=\"activeFile\" :class=\"cls.e('stage-sub')\">\n <span>{{ activeIndexLabel }}</span>\n <span v-if=\"activeFile.size\">{{ formatBytes(activeFile.size) }}</span>\n </span>\n </span>\n </div>\n <div :class=\"cls.e('stage-actions')\">\n <span :class=\"cls.e('action-group')\">\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"!hasPrev\"\n type=\"button\"\n aria-label=\"上一个\"\n title=\"上一个\"\n @click=\"prev\"\n >\n <u-icon :size=\"15\">\n <ArrowLeft />\n </u-icon>\n </button>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"!hasNext\"\n type=\"button\"\n aria-label=\"下一个\"\n title=\"下一个\"\n @click=\"next\"\n >\n <u-icon :size=\"15\">\n <ArrowRight />\n </u-icon>\n </button>\n </span>\n <span v-if=\"isTransformable\" :class=\"cls.e('action-group')\">\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"zoomOutDisabled\"\n type=\"button\"\n aria-label=\"缩小\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n <u-icon :size=\"15\">\n <ZoomOut />\n </u-icon>\n </button>\n <span :class=\"cls.e('zoom-value')\">{{ zoomPercent }}</span>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"zoomInDisabled\"\n type=\"button\"\n aria-label=\"放大\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n <u-icon :size=\"15\">\n <ZoomIn />\n </u-icon>\n </button>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"isTransformReset\"\n type=\"button\"\n aria-label=\"重置视图\"\n title=\"重置视图\"\n @click=\"resetTransform\"\n >\n <u-icon :size=\"15\">\n <Refresh />\n </u-icon>\n </button>\n </span>\n <button\n v-if=\"downloadable && activeFile\"\n :class=\"[cls.e('action'), cls.em('action', 'primary'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"下载\"\n title=\"下载\"\n @click=\"download\"\n >\n <u-icon :size=\"15\">\n <Download />\n </u-icon>\n </button>\n <button\n v-if=\"isModal\"\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"关闭预览\"\n title=\"关闭\"\n @click=\"handleClose\"\n >\n <u-icon :size=\"16\">\n <Close />\n </u-icon>\n </button>\n </div>\n </header>\n <div :class=\"cls.e('body')\">\n <transition name=\"u-file-viewer-fade\" mode=\"out-in\">\n <div\n v-if=\"activeFile\"\n :key=\"activeFile.id\"\n :class=\"[\n cls.e('viewport'),\n bem.is('transformable', isTransformable),\n bem.is('pannable', canPan),\n bem.is('dragging', isDragging)\n ]\"\n @pointerdown=\"handleViewportPointerDown\"\n @pointermove=\"handleViewportPointerMove\"\n @pointerup=\"handleViewportPointerEnd\"\n @pointercancel=\"handleViewportPointerEnd\"\n @dblclick=\"handleViewportDblclick\"\n >\n <component\n :is=\"PreviewerMap[activeFile.kind]\"\n :file=\"activeFile\"\n :max-rows=\"sheetMaxRows\"\n :class=\"isTransformable ? cls.e('previewer') : undefined\"\n :style=\"previewerStyle\"\n @error=\"handleChildError\"\n />\n </div>\n <div v-else :class=\"cls.e('empty')\">\n <u-empty text=\"暂无可预览文件\" />\n </div>\n </transition>\n </div>\n </section>\n </div>\n </div>\n </transition>\n </Teleport>\n</template>\n\n<script lang=\"ts\" setup>\nimport {\n ArrowLeft,\n ArrowRight,\n Close,\n Download,\n Refresh,\n ZoomIn,\n ZoomOut\n} from '@veltra/icons/normal'\nimport { bem, withUnit } from '@veltra/utils'\nimport {\n computed,\n defineAsyncComponent,\n nextTick,\n onBeforeUnmount,\n ref,\n shallowRef,\n watch\n} from 'vue'\nimport type { CSSProperties } from 'vue'\n\nimport type {\n _FileViewerExposed,\n FileViewerEmits,\n FileViewerItem,\n FileViewerKind,\n FileViewerProps\n} from '../../types/file-viewer'\nimport { UEmpty } from '../empty'\nimport { UIcon } from '../icon'\nimport { UScroll } from '../scroll'\nimport { FILE_VIEWER_KIND_LABEL, downloadFile, formatBytes, inferKind } from './helper'\n\ndefineOptions({\n name: 'FileViewer',\n inheritAttrs: false\n})\n\nconst props = withDefaults(defineProps<FileViewerProps>(), {\n modelValue: undefined,\n sidebarWidth: '280px',\n sheetMaxRows: 50_000,\n downloadable: true,\n open: undefined,\n closeOnClickBackdrop: true,\n closeOnEsc: true\n})\n\nconst emit = defineEmits<FileViewerEmits>()\n\nconst cls = bem('file-viewer')\n\nconst MIN_SCALE = 0.5\nconst MAX_SCALE = 3\nconst SCALE_STEP = 0.25\nconst TRANSFORMABLE_KINDS = new Set<FileViewerKind>(['image', 'pdf', 'docx'])\n\nconst activeId = defineModel<string | undefined>('modelValue', { default: undefined })\nconst openModel = defineModel<boolean | undefined>('open', { default: undefined })\n\nconst rootRef = shallowRef<HTMLDivElement>()\nconst scale = ref(1)\nconst offsetX = ref(0)\nconst offsetY = ref(0)\nconst isDragging = ref(false)\n\nlet dragState:\n | {\n pointerId: number\n startX: number\n startY: number\n originX: number\n originY: number\n }\n | undefined\n\nconst PreviewerMap: Record<FileViewerKind, ReturnType<typeof defineAsyncComponent>> = {\n image: defineAsyncComponent(() => import('./previewers/image-previewer.vue')),\n video: defineAsyncComponent(() => import('./previewers/video-previewer.vue')),\n pdf: defineAsyncComponent(() => import('./previewers/pdf-previewer.vue')),\n sheet: defineAsyncComponent(() => import('./previewers/sheet-previewer.vue')),\n docx: defineAsyncComponent(() => import('./previewers/docx-previewer.vue')),\n text: defineAsyncComponent(() => import('./previewers/text-previewer.vue'))\n}\n\ninterface NormalizedFile extends FileViewerItem {\n id: string\n kind: FileViewerKind\n}\n\nconst normalizedFiles = computed<NormalizedFile[]>(() =>\n props.files.map((f, i) => ({\n ...f,\n id: f.id ?? `file-${i}`,\n kind: inferKind(f.name, f.kind)\n }))\n)\n\nconst activeFile = computed<NormalizedFile | undefined>(() =>\n normalizedFiles.value.find((f) => f.id === activeId.value)\n)\n\nconst activeIndex = computed(() => normalizedFiles.value.findIndex((f) => f.id === activeId.value))\n\nconst hasPrev = computed(() => activeIndex.value > 0)\nconst hasNext = computed(\n () => activeIndex.value >= 0 && activeIndex.value < normalizedFiles.value.length - 1\n)\n\nconst showSidebar = computed(() => props.sidebarWidth !== false && props.sidebarWidth !== 0)\n\nconst sidebarWidthCss = computed(() => {\n const w = props.sidebarWidth\n if (w === false || w === 0) return undefined\n return withUnit(w ?? '280px', 'px')\n})\n\n/** 是否启用模态模式:只要父组件显式传入 open(含 v-model:open),即进入模态 */\nconst isModal = computed(() => openModel.value !== undefined)\n\nconst activeIndexLabel = computed(() =>\n activeIndex.value >= 0 ? `${activeIndex.value + 1} / ${normalizedFiles.value.length}` : ''\n)\n\nconst isTransformable = computed(\n () => !!activeFile.value && TRANSFORMABLE_KINDS.has(activeFile.value.kind)\n)\n\nconst canPan = computed(() => isTransformable.value && scale.value > 1)\n\nconst zoomPercent = computed(() => `${Math.round(scale.value * 100)}%`)\n\nconst zoomInDisabled = computed(() => !isTransformable.value || scale.value >= MAX_SCALE)\n\nconst zoomOutDisabled = computed(() => !isTransformable.value || scale.value <= MIN_SCALE)\n\nconst isTransformReset = computed(\n () => scale.value === 1 && offsetX.value === 0 && offsetY.value === 0\n)\n\nconst previewerStyle = computed<CSSProperties | undefined>(() => {\n if (!isTransformable.value) return undefined\n return {\n transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value})`\n }\n})\n\nfunction label(kind: FileViewerKind): string {\n return FILE_VIEWER_KIND_LABEL[kind]\n}\n\nfunction activate(id: string) {\n if (activeId.value === id) return\n activeId.value = id\n const f = normalizedFiles.value.find((x) => x.id === id)\n if (f) emit('change', f)\n}\n\nfunction prev() {\n const i = activeIndex.value\n if (i <= 0) return\n const target = normalizedFiles.value[i - 1]\n if (target) activate(target.id)\n}\n\nfunction next() {\n const i = activeIndex.value\n if (i < 0 || i >= normalizedFiles.value.length - 1) return\n const target = normalizedFiles.value[i + 1]\n if (target) activate(target.id)\n}\n\nfunction normalizeScale(value: number): number {\n const clamped = Math.min(MAX_SCALE, Math.max(MIN_SCALE, value))\n return Math.round(clamped * 100) / 100\n}\n\nfunction setScale(value: number) {\n scale.value = normalizeScale(value)\n if (scale.value <= 1) {\n offsetX.value = 0\n offsetY.value = 0\n }\n}\n\nfunction zoomIn() {\n if (!isTransformable.value) return\n setScale(scale.value + SCALE_STEP)\n}\n\nfunction zoomOut() {\n if (!isTransformable.value) return\n setScale(scale.value - SCALE_STEP)\n}\n\nfunction resetTransform() {\n scale.value = 1\n offsetX.value = 0\n offsetY.value = 0\n dragState = undefined\n isDragging.value = false\n}\n\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false\n return !!target.closest('button, a, input, textarea, select, video, [contenteditable=\"true\"]')\n}\n\nfunction handleViewportPointerDown(e: PointerEvent) {\n if (!canPan.value || e.button !== 0 || isInteractiveTarget(e.target)) return\n\n dragState = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n originX: offsetX.value,\n originY: offsetY.value\n }\n isDragging.value = true\n const el = e.currentTarget as HTMLElement\n el.setPointerCapture(e.pointerId)\n e.preventDefault()\n}\n\nfunction handleViewportPointerMove(e: PointerEvent) {\n if (!dragState || dragState.pointerId !== e.pointerId) return\n offsetX.value = dragState.originX + e.clientX - dragState.startX\n offsetY.value = dragState.originY + e.clientY - dragState.startY\n}\n\nfunction handleViewportPointerEnd(e: PointerEvent) {\n if (!dragState || dragState.pointerId !== e.pointerId) return\n const el = e.currentTarget as HTMLElement\n if (el.hasPointerCapture(e.pointerId)) {\n el.releasePointerCapture(e.pointerId)\n }\n dragState = undefined\n isDragging.value = false\n}\n\nfunction handleViewportDblclick() {\n if (!isTransformable.value) return\n if (scale.value === 1) {\n setScale(2)\n } else {\n resetTransform()\n }\n}\n\nasync function download() {\n if (!activeFile.value) return\n try {\n await downloadFile(activeFile.value)\n } catch (err) {\n emit('error', { file: activeFile.value, error: err })\n }\n}\n\nfunction handleChildError(err: unknown) {\n if (!activeFile.value) return\n emit('error', { file: activeFile.value, error: err })\n}\n\nfunction handleClose() {\n if (!isModal.value) return\n openModel.value = false\n}\n\nfunction handleWindowKeydown(e: KeyboardEvent) {\n if (e.key !== 'Escape') return\n if (!isModal.value || !openModel.value) return\n if (props.closeOnEsc === false) return\n e.stopPropagation()\n handleClose()\n}\n\nfunction handleBackdropMousedown() {\n if (!isModal.value) return\n if (props.closeOnClickBackdrop === false) return\n handleClose()\n}\n\nwatch(\n normalizedFiles,\n (files) => {\n if (!files.length) {\n activeId.value = undefined\n return\n }\n if (!activeId.value || !files.some((f) => f.id === activeId.value)) {\n activeId.value = files[0]!.id\n }\n },\n { immediate: true }\n)\n\nwatch(\n () => activeFile.value?.id,\n () => resetTransform()\n)\n\n// 模态打开时:锁定 body 滚动 + 让容器获得焦点以便接收 ESC\nlet previousBodyOverflow = ''\nlet isBodyLocked = false\n\nfunction lockBody() {\n if (isBodyLocked || typeof document === 'undefined') return\n previousBodyOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n isBodyLocked = true\n}\n\nfunction unlockBody() {\n if (!isBodyLocked || typeof document === 'undefined') return\n document.body.style.overflow = previousBodyOverflow\n isBodyLocked = false\n}\n\nwatch(\n [isModal, openModel],\n ([modal, open]) => {\n if (modal && open) {\n lockBody()\n nextTick(() => {\n rootRef.value?.focus()\n })\n if (typeof window !== 'undefined') {\n window.addEventListener('keydown', handleWindowKeydown, true)\n }\n } else {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n }\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n})\n\ndefineExpose<_FileViewerExposed>({\n activeId,\n activate,\n next,\n prev\n})\n</script>\n"],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import _sfc_main$1 from "../../scroll/scroll.js";
|
|
2
|
-
import { createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, normalizeClass, onBeforeUnmount, openBlock, ref, unref, useTemplateRef, watch, withCtx } from "vue";
|
|
2
|
+
import { createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, mergeProps, normalizeClass, onBeforeUnmount, openBlock, ref, unref, useAttrs, useTemplateRef, watch, withCtx } from "vue";
|
|
3
3
|
import { bem } from "@veltra/utils";
|
|
4
4
|
//#region src/components/file-viewer/previewers/docx-previewer.vue
|
|
5
5
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
6
6
|
name: "FileViewerDocxPreviewer",
|
|
7
|
+
inheritAttrs: false,
|
|
7
8
|
__name: "docx-previewer",
|
|
8
9
|
props: { file: {} },
|
|
9
10
|
emits: ["error"],
|
|
@@ -11,6 +12,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
11
12
|
const props = __props;
|
|
12
13
|
const emit = __emit;
|
|
13
14
|
const cls = bem("file-viewer");
|
|
15
|
+
const attrs = useAttrs();
|
|
14
16
|
const container = useTemplateRef("container");
|
|
15
17
|
const loading = ref(true);
|
|
16
18
|
let controller;
|
|
@@ -53,10 +55,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
53
55
|
if (container.value) container.value.innerHTML = "";
|
|
54
56
|
});
|
|
55
57
|
return (_ctx, _cache) => {
|
|
56
|
-
return openBlock(), createBlock(unref(_sfc_main$1), {
|
|
58
|
+
return openBlock(), createBlock(unref(_sfc_main$1), mergeProps({
|
|
57
59
|
tag: "div",
|
|
58
|
-
class:
|
|
59
|
-
}, {
|
|
60
|
+
class: unref(cls).e("docx")
|
|
61
|
+
}, unref(attrs)), {
|
|
60
62
|
default: withCtx(() => [createElementVNode("div", {
|
|
61
63
|
ref_key: "container",
|
|
62
64
|
ref: container,
|
|
@@ -66,7 +68,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
66
68
|
class: normalizeClass(unref(cls).e("loading"))
|
|
67
69
|
}, "加载中…", 2)) : createCommentVNode("v-if", true)]),
|
|
68
70
|
_: 1
|
|
69
|
-
},
|
|
71
|
+
}, 16, ["class"]);
|
|
70
72
|
};
|
|
71
73
|
}
|
|
72
74
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docx-previewer.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/docx-previewer.vue"],"sourcesContent":["<template>\n <u-scroll tag=\"div\" :class=\"cls.e('docx')\">\n <div ref=\"container\" :class=\"cls.e('docx-body')\" />\n <div v-if=\"loading\" :class=\"cls.e('loading')\">加载中…</div>\n </u-scroll>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { onBeforeUnmount, ref, useTemplateRef, watch } from 'vue'\n\nimport type { FileViewerItem } from '../../../types/file-viewer'\nimport { UScroll } from '../../scroll'\n\ndefineOptions({ name: 'FileViewerDocxPreviewer' })\n\nconst props = defineProps<{ file: FileViewerItem }>()\n\nconst emit = defineEmits<{ (e: 'error', err: unknown): void }>()\n\nconst cls = bem('file-viewer')\n\nconst container = useTemplateRef<HTMLDivElement>('container')\nconst loading = ref(true)\n\nlet controller: AbortController | undefined\n\nasync function load() {\n controller?.abort()\n controller = new AbortController()\n const signal = controller.signal\n loading.value = true\n\n try {\n const [{ toArrayBuffer }, docx] = await Promise.all([\n import('../helper'),\n import('docx-preview')\n ])\n\n const buf = await toArrayBuffer(props.file.src, signal)\n if (signal.aborted) return\n const el = container.value\n if (!el) return\n el.innerHTML = ''\n\n await docx.renderAsync(buf, el, undefined, {\n className: 'u-file-viewer__docx-doc',\n inWrapper: true,\n ignoreWidth: false,\n ignoreHeight: false,\n ignoreFonts: false,\n breakPages: true,\n experimental: false,\n useBase64URL: false,\n renderChanges: false,\n renderHeaders: true,\n renderFooters: true,\n renderFootnotes: true\n })\n } catch (err) {\n if ((err as { name?: string })?.name === 'AbortError') return\n emit('error', err)\n } finally {\n loading.value = false\n }\n}\n\nwatch(\n () => props.file,\n () => load(),\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n controller?.abort()\n if (container.value) container.value.innerHTML = ''\n})\n</script>\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"docx-previewer.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/docx-previewer.vue"],"sourcesContent":["<template>\n <u-scroll tag=\"div\" :class=\"cls.e('docx')\" v-bind=\"attrs\">\n <div ref=\"container\" :class=\"cls.e('docx-body')\" />\n <div v-if=\"loading\" :class=\"cls.e('loading')\">加载中…</div>\n </u-scroll>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { onBeforeUnmount, ref, useAttrs, useTemplateRef, watch } from 'vue'\n\nimport type { FileViewerItem } from '../../../types/file-viewer'\nimport { UScroll } from '../../scroll'\n\ndefineOptions({ name: 'FileViewerDocxPreviewer', inheritAttrs: false })\n\nconst props = defineProps<{ file: FileViewerItem }>()\n\nconst emit = defineEmits<{ (e: 'error', err: unknown): void }>()\n\nconst cls = bem('file-viewer')\nconst attrs = useAttrs()\n\nconst container = useTemplateRef<HTMLDivElement>('container')\nconst loading = ref(true)\n\nlet controller: AbortController | undefined\n\nasync function load() {\n controller?.abort()\n controller = new AbortController()\n const signal = controller.signal\n loading.value = true\n\n try {\n const [{ toArrayBuffer }, docx] = await Promise.all([\n import('../helper'),\n import('docx-preview')\n ])\n\n const buf = await toArrayBuffer(props.file.src, signal)\n if (signal.aborted) return\n const el = container.value\n if (!el) return\n el.innerHTML = ''\n\n await docx.renderAsync(buf, el, undefined, {\n className: 'u-file-viewer__docx-doc',\n inWrapper: true,\n ignoreWidth: false,\n ignoreHeight: false,\n ignoreFonts: false,\n breakPages: true,\n experimental: false,\n useBase64URL: false,\n renderChanges: false,\n renderHeaders: true,\n renderFooters: true,\n renderFootnotes: true\n })\n } catch (err) {\n if ((err as { name?: string })?.name === 'AbortError') return\n emit('error', err)\n } finally {\n loading.value = false\n }\n}\n\nwatch(\n () => props.file,\n () => load(),\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n controller?.abort()\n if (container.value) container.value.innerHTML = ''\n})\n</script>\n"],"mappings":";;;;;;;;;;;EAgBA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,cAAa;EAC7B,MAAM,QAAQ,UAAS;EAEvB,MAAM,YAAY,eAA+B,YAAW;EAC5D,MAAM,UAAU,IAAI,KAAI;EAExB,IAAI;EAEJ,eAAe,OAAO;AACpB,eAAY,OAAM;AAClB,gBAAa,IAAI,iBAAgB;GACjC,MAAM,SAAS,WAAW;AAC1B,WAAQ,QAAQ;AAEhB,OAAI;IACF,MAAM,CAAC,EAAE,iBAAiB,QAAQ,MAAM,QAAQ,IAAI,CAClD,OAAO,iBACP,OAAO,gBACR,CAAA;IAED,MAAM,MAAM,MAAM,cAAc,MAAM,KAAK,KAAK,OAAM;AACtD,QAAI,OAAO,QAAS;IACpB,MAAM,KAAK,UAAU;AACrB,QAAI,CAAC,GAAI;AACT,OAAG,YAAY;AAEf,UAAM,KAAK,YAAY,KAAK,IAAI,KAAA,GAAW;KACzC,WAAW;KACX,WAAW;KACX,aAAa;KACb,cAAc;KACd,aAAa;KACb,YAAY;KACZ,cAAc;KACd,cAAc;KACd,eAAe;KACf,eAAe;KACf,eAAe;KACf,iBAAiB;KAClB,CAAA;YACM,KAAK;AACZ,QAAK,KAA2B,SAAS,aAAc;AACvD,SAAK,SAAS,IAAG;aACT;AACR,YAAQ,QAAQ;;;AAIpB,cACQ,MAAM,YACN,MAAM,EACZ,EAAE,WAAW,MAAK,CACpB;AAEA,wBAAsB;AACpB,eAAY,OAAM;AAClB,OAAI,UAAU,MAAO,WAAU,MAAM,YAAY;IAClD;;uBA5EC,YAGW,MAAA,YAAA,EAHX,WAGW;IAHD,KAAI;IAAO,OAAO,MAAA,IAAG,CAAC,EAAC,OAAA;MAAkB,MAAA,MAAK,CAAA,EAAA;2BACH,CAAnD,mBAAmD,OAAA;cAA1C;KAAJ,KAAI;KAAa,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,YAAA,CAAA;iBACvB,QAAA,SAAA,WAAA,EAAX,mBAAwD,OAAA;;KAAnC,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,UAAA,CAAA;OAAa,QAAI,EAAA,IAAA,mBAAA,QAAA,KAAA,CAAA,CAAA"}
|