@qxs-bns/components-wc 0.0.18 → 0.0.19

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.
@@ -1 +1 @@
1
- {"version":3,"file":"blocksuite-editor.cjs","sources":["../../../../packages/components-wc/src/editor/blocksuite-editor.ts"],"sourcesContent":["import { Editor } from '@tiptap/core'\nimport Blockquote from '@tiptap/extension-blockquote'\nimport Bold from '@tiptap/extension-bold'\nimport BulletList from '@tiptap/extension-bullet-list'\nimport Code from '@tiptap/extension-code'\nimport Document from '@tiptap/extension-document'\nimport Heading from '@tiptap/extension-heading'\nimport History from '@tiptap/extension-history'\nimport HorizontalRule from '@tiptap/extension-horizontal-rule'\nimport Image from '@tiptap/extension-image'\nimport Italic from '@tiptap/extension-italic'\nimport Link from '@tiptap/extension-link'\nimport ListItem from '@tiptap/extension-list-item'\nimport OrderedList from '@tiptap/extension-ordered-list'\nimport Paragraph from '@tiptap/extension-paragraph'\nimport Strike from '@tiptap/extension-strike'\nimport { Table } from '@tiptap/extension-table'\nimport { TableCell } from '@tiptap/extension-table-cell'\nimport { TableHeader } from '@tiptap/extension-table-header'\nimport { TableRow } from '@tiptap/extension-table-row'\nimport Text from '@tiptap/extension-text'\nimport TextAlign from '@tiptap/extension-text-align'\nimport Underline from '@tiptap/extension-underline'\nimport Placeholder from '@tiptap/extension-placeholder'\nimport { Extension } from '@tiptap/core'\nimport { css, html, LitElement } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { safeCustomElement } from '../base/define'\n\n@safeCustomElement('qxs-blocksuite-editor')\nexport class QxsBlocksuiteEditor extends LitElement {\n static styles = css`\n :host {\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, sans-serif;\n }\n\n .editor-wrapper {\n border: 1px solid #e3e3e3;\n border-radius: 12px;\n background: #fff;\n overflow: visible;\n position: relative;\n min-height: 80px;\n }\n\n .editor-wrapper:focus-within {\n border-color: var(--qxs-color-primary, #3D61E3);\n }\n\n .editor-wrapper.preview {\n border: none;\n border-radius: 0;\n background: transparent;\n }\n\n .editor-wrapper.preview .editor-content {\n padding: 8px 12px;\n min-height: unset;\n }\n\n .editor-content {\n padding: 12px 16px;\n min-height: 80px;\n cursor: text;\n }\n\n .editor-content:empty::before {\n content: '输入 / 唤出快捷命令';\n color: #c0c0c0;\n pointer-events: none;\n display: block;\n padding-top: 28px;\n text-align: center;\n }\n\n .editor-content .ProseMirror:empty {\n min-height: 80px;\n }\n\n .ProseMirror p.is-editor-empty:first-child::before {\n content: attr(data-placeholder);\n color: #c0c0c0;\n pointer-events: none;\n float: left;\n height: 0;\n }\n\n .ProseMirror p.is-empty:only-child::before,\n .ProseMirror p.is-empty:only-child > br:first-child + *::before {\n content: attr(data-placeholder);\n color: #c0c0c0;\n pointer-events: none;\n float: left;\n height: 0;\n }\n\n .editor-wrapper.loading {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n background: #fafafa;\n }\n\n .loading-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: #909399;\n font-size: 14px;\n }\n\n .loading-spinner {\n width: 24px;\n height: 24px;\n border: 2px solid #e3e3e3;\n border-top-color: var(--qxs-color-primary, #3D61E3);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .ProseMirror {\n outline: none;\n line-height: 1.7;\n color: #37352f;\n font-size: 15px;\n }\n\n .ProseMirror > * + * {\n margin-top: 0.5em;\n }\n\n .ProseMirror > *:first-child {\n margin-top: 0 !important;\n }\n\n .ProseMirror p {\n margin: 0;\n }\n\n .ProseMirror h1 {\n font-size: 1.875em;\n font-weight: 700;\n margin: 0 0 0.25em;\n line-height: 1.3;\n }\n\n .ProseMirror > h1:first-child {\n margin-top: 0 !important;\n line-height: 1.15;\n }\n\n .ProseMirror > p:first-child {\n margin-top: 0 !important;\n }\n\n .ProseMirror h2 {\n font-size: 1.5em;\n font-weight: 600;\n margin: 0.5em 0 0.25em;\n line-height: 1.3;\n }\n\n .ProseMirror h3 {\n font-size: 1.25em;\n font-weight: 600;\n margin: 0.5em 0 0.25em;\n line-height: 1.3;\n }\n\n .ProseMirror ul,\n .ProseMirror ol {\n padding-left: 1.5em;\n margin: 0;\n }\n\n .ProseMirror li {\n margin: 0.1em 0;\n }\n\n .ProseMirror li::marker {\n color: #37352f;\n }\n\n .ProseMirror strong {\n font-weight: 700;\n }\n\n .ProseMirror em {\n font-style: italic;\n font-synthesis: none;\n transform: skewX(-12deg);\n display: inline-block;\n }\n\n .ProseMirror u {\n text-decoration: underline;\n }\n\n .ProseMirror s {\n text-decoration: line-through;\n color: #787774;\n }\n\n .ProseMirror code {\n background: rgba(135, 131, 120, 0.14);\n color: #eb5757;\n padding: 2px 4px;\n border-radius: 4px;\n font-family: 'SFMono-Regular', Menlo, Consolas, monospace;\n font-size: 85%;\n }\n\n .ProseMirror pre {\n background: #f6f6f7;\n border-radius: 8px;\n padding: 12px 16px;\n overflow-x: auto;\n }\n\n .ProseMirror pre code {\n background: none;\n padding: 0;\n color: #37352f;\n }\n\n .ProseMirror blockquote {\n border-left: 3px solid #e3e3e3;\n padding-left: 1em;\n margin: 0.75em 0;\n color: #787774;\n }\n\n .ProseMirror hr {\n border: none;\n border-top: 1px solid #e3e3e3;\n margin: 1.5em 0;\n }\n\n .ProseMirror img {\n max-width: 100%;\n height: auto;\n border-radius: 8px;\n }\n\n .ProseMirror a {\n color: var(--qxs-color-primary, #3D61E3);\n text-decoration: underline;\n cursor: pointer;\n }\n\n .ProseMirror img.ProseMirror-selectednode {\n outline: 2px solid var(--qxs-color-primary, #3D61E3);\n }\n\n /* Table styles */\n .ProseMirror table {\n border-collapse: collapse;\n width: 100%;\n margin: 1em 0;\n border: 1px solid #e3e3e3;\n border-radius: 8px;\n overflow: hidden;\n }\n\n .ProseMirror th,\n .ProseMirror td {\n border: 1px solid #e3e3e3;\n padding: 8px 12px;\n text-align: left;\n vertical-align: top;\n }\n\n .ProseMirror th {\n background: #fafafa;\n font-weight: 600;\n }\n\n .ProseMirror .selectedCell {\n background: rgba(30, 150, 252, 0.1);\n }\n\n /* Table Cell Toolbar */\n .table-cell-toolbar {\n position: absolute;\n z-index: 50;\n display: flex;\n gap: 2px;\n padding: 4px;\n background: #fff;\n border: 1px solid #e3e3e3;\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n }\n\n .table-cell-toolbar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n color: #606266;\n transition: all 0.15s;\n }\n\n .table-cell-toolbar-btn:hover {\n background: #ecf5ff;\n color: var(--qxs-color-primary, #3D61E3);\n }\n\n .table-cell-toolbar-btn.danger:hover {\n background: #fef0f0;\n color: #f56c6c;\n }\n\n /* Bubble Menu */\n .bubble-menu {\n position: absolute;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 4px 6px;\n background: #fff;\n border: 1px solid #e3e3e3;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 100;\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.15s, visibility 0.15s, transform 0.15s;\n transform: translateY(4px);\n max-width: calc(100vw - 40px);\n }\n\n .bubble-menu.is-visible {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n }\n\n .bubble-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: #37352f;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.15s;\n position: relative;\n }\n\n .bubble-btn:hover {\n background: rgba(55, 53, 47, 0.08);\n }\n\n .bubble-btn.is-active {\n background: var(--qxs-color-primary, #3D61E3);\n color: #fff;\n }\n\n .bubble-btn svg {\n width: 16px;\n height: 16px;\n stroke: currentColor;\n stroke-width: 2;\n fill: none;\n }\n\n .bubble-divider {\n width: 1px;\n height: 16px;\n background: #e3e3e3;\n margin: 0 3px;\n }\n\n /* Dropdown */\n .bubble-dropdown {\n position: relative;\n }\n\n .bubble-dropdown-btn {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 0 6px;\n height: 28px;\n border: none;\n background: transparent;\n color: #37352f;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n font-family: inherit;\n transition: all 0.15s;\n white-space: nowrap;\n }\n\n .bubble-dropdown-btn:hover {\n background: rgba(55, 53, 47, 0.08);\n }\n\n .bubble-dropdown-btn svg {\n width: 12px;\n height: 12px;\n stroke: currentColor;\n stroke-width: 2;\n fill: none;\n }\n\n .bubble-dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n margin-top: 4px;\n min-width: 120px;\n background: #fff;\n border: 1px solid #e3e3e3;\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n padding: 4px;\n opacity: 0;\n visibility: hidden;\n transform: translateY(-4px);\n transition: all 0.15s;\n z-index: 101;\n }\n\n .bubble-dropdown:hover .bubble-dropdown-menu,\n .bubble-dropdown.is-open .bubble-dropdown-menu {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n }\n\n .bubble-dropdown-item {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 6px 8px;\n border: none;\n background: transparent;\n color: #37352f;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n font-family: inherit;\n text-align: left;\n transition: all 0.15s;\n }\n\n .bubble-dropdown-item:hover {\n background: rgba(55, 53, 47, 0.08);\n }\n\n .bubble-dropdown-item.is-active {\n background: var(--qxs-color-primary, #3D61E3);\n color: #fff;\n }\n\n .bubble-dropdown-item svg {\n width: 16px;\n height: 16px;\n stroke: currentColor;\n stroke-width: 2;\n fill: none;\n }\n\n .image-input {\n display: none;\n }\n\n .table-grid-preview {\n display: grid;\n grid-template-columns: repeat(10, 18px);\n gap: 2px;\n padding: 8px;\n }\n\n .table-grid-preview .table-cell {\n width: 18px;\n height: 18px;\n border: 1px solid #e3e3e3;\n border-radius: 2px;\n background: #fff;\n cursor: pointer;\n transition: all 0.1s;\n }\n\n .table-grid-preview .table-cell:hover {\n background: rgba(30, 150, 252, 0.3);\n border-color: var(--qxs-color-primary, #3D61E3);\n }\n\n .table-grid-preview .table-cell.selected {\n background: rgba(30, 150, 252, 0.15);\n border-color: rgba(30, 150, 252, 0.5);\n }\n\n .table-size-hint {\n text-align: center;\n padding: 4px 8px 6px;\n font-size: 10px;\n color: #8c8c8c;\n }\n\n /* Image Toolbar */\n .image-toolbar {\n position: absolute;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 4px 6px;\n background: #fff;\n border: 1px solid #e3e3e3;\n border-radius: 6px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n z-index: 100;\n transform: translateX(-50%);\n }\n\n .image-toolbar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n color: #595959;\n transition: all 0.15s;\n }\n\n .image-toolbar-btn:hover {\n background: #f5f5f5;\n color: var(--qxs-color-primary, #3D61E3);\n }\n\n .image-toolbar-btn.danger:hover {\n background: #fff1f0;\n color: #ff4d4f;\n }\n\n .image-toolbar-btn svg {\n width: 16px;\n height: 16px;\n stroke: currentColor;\n stroke-width: 2;\n fill: none;\n }\n\n .image-toolbar-divider {\n width: 1px;\n height: 20px;\n background: #e3e3e3;\n margin: 0 4px;\n }\n\n /* Image More Menu */\n .image-more-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n padding: 4px;\n background: #fff;\n border: 1px solid #e3e3e3;\n border-radius: 6px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n z-index: 101;\n min-width: 120px;\n }\n\n .image-more-menu-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border: none;\n background: transparent;\n width: 100%;\n text-align: left;\n font-size: 13px;\n color: #595959;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .image-more-menu-item:hover {\n background: #f5f5f5;\n color: var(--qxs-color-primary, #3D61E3);\n }\n\n .image-more-menu-item svg {\n width: 14px;\n height: 14px;\n stroke: currentColor;\n stroke-width: 2;\n fill: none;\n }\n\n /* Selected Image */\n .ProseMirror img.selected {\n outline: 2px solid var(--qxs-color-primary, #3D61E3);\n outline-offset: 2px;\n }\n `\n\n @property({ type: String, attribute: 'content' })\n content = ''\n\n @property({ type: String, attribute: 'model-value' })\n modelValue = ''\n\n @property({ type: String, attribute: 'use-model' })\n useModelAttr = 'false'\n\n @property({ type: String, attribute: 'readonly' })\n readonlyAttr = 'false'\n\n @property({ type: String, attribute: 'preview' })\n previewAttr = 'false'\n\n @property({ type: String, attribute: 'custom-styles' })\n customStylesAttr = ''\n\n private _injectedStyleEl: HTMLStyleElement | null = null\n\n private _injectCustomStyles() {\n const shadow = this.shadowRoot\n if (!shadow) return\n\n if (this._injectedStyleEl) {\n this._injectedStyleEl.remove()\n this._injectedStyleEl = null\n }\n\n if (!this.customStylesAttr) return\n\n const styleEl = document.createElement('style')\n styleEl.textContent = this.customStylesAttr\n shadow.appendChild(styleEl)\n this._injectedStyleEl = styleEl\n }\n\n get useModel(): boolean {\n return this.useModelAttr === 'true' || this.useModelAttr === '' || this.hasAttribute('use-model')\n }\n\n set useModel(value: boolean) {\n this.useModelAttr = String(value)\n }\n\n get readonly(): boolean {\n return this.readonlyAttr !== 'false'\n }\n\n set readonly(value: boolean) {\n this.readonlyAttr = String(value)\n }\n\n get preview(): boolean {\n return this.previewAttr !== 'false'\n }\n\n set preview(value: boolean) {\n this.previewAttr = String(value)\n }\n\n @property({ type: Object, attribute: 'upload-image' })\n uploadImage: (file: File) => Promise<string> = async (file: File) => {\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = (e) => resolve(e.target?.result as string)\n reader.onerror = reject\n reader.readAsDataURL(file)\n })\n }\n\n @state() private _editor: Editor | null = null\n @state() private _pendingContent: string | null = null\n private _tableRows = 3\n private _tableCols = 3\n @state() private _hoverRow = 0\n @state() private _hoverCol = 0\n @state() private _tableDropdownOpen = false\n @state() private _tableCellToolbar: { x: number, y: number, visible: boolean, cellRow: number, cellCol: number } = { x: 0, y: 0, visible: false, cellRow: 0, cellCol: 0 }\n @state() private _imageToolbar: { x: number, y: number, visible: boolean } = { x: 0, y: 0, visible: false }\n @state() private _imageMoreMenuVisible = false\n private _hasSlashCommand = false\n\n private _initEditor() {\n if (this._editor) return\n\n const el = this.shadowRoot?.querySelector<HTMLElement>('.editor-content')\n if (!el) {\n requestAnimationFrame(() => this._initEditor())\n return\n }\n\n while (el.firstChild) {\n el.removeChild(el.firstChild)\n }\n\n const useModel = this.useModel || this.hasAttribute('use-model')\n const modelValue = this.getAttribute('model-value') ?? this.modelValue\n const contentValue = this.content\n\n const initialContent = useModel\n ? (this._pendingContent ?? modelValue) || '<p></p>'\n : (this._pendingContent ?? contentValue) || '<p></p>'\n\n const extensions: any[] = [\n Document,\n Paragraph,\n Text,\n Bold,\n Italic,\n Underline,\n Strike,\n Code,\n Heading.extend({\n addAttributes() {\n return {\n ...this.parent?.(),\n dataType: {\n default: null,\n parseHTML: element => element.getAttribute('data-type'),\n renderHTML: attributes => {\n if (!attributes.dataType) return {}\n return { 'data-type': attributes.dataType }\n },\n },\n }\n },\n }).configure({ levels: [1, 2, 3] }),\n BulletList,\n OrderedList,\n ListItem,\n Blockquote,\n HorizontalRule,\n History,\n Image.configure({\n inline: false,\n allowBase64: true,\n }),\n Link.configure({\n openOnClick: false,\n HTMLAttributes: {\n rel: 'noopener noreferrer',\n },\n }),\n TextAlign.configure({\n types: ['heading', 'paragraph'],\n }),\n Table.configure({\n resizable: true,\n }),\n TableRow,\n TableCell,\n TableHeader,\n Placeholder.configure({\n placeholder: '输入 / 唤出快捷命令',\n }),\n Extension.create({\n name: 'clearMarksOnEnter',\n addKeyboardShortcuts() {\n return {\n Enter: () => {\n this.editor.chain().focus().unsetAllMarks().clearNodes().run()\n return false\n },\n }\n },\n }),\n ]\n\n this._editor = new Editor({\n element: el,\n extensions,\n editable: !this.readonly,\n content: initialContent,\n })\n\n this._pendingContent = null\n\n this._editor.on('selectionUpdate', () => {\n this._updateBubbleMenuPosition()\n if (this._editor?.isActive('table')) {\n this._showTableCellToolbar()\n } else {\n this._hideTableCellToolbar()\n }\n // Image selection detection\n const editor = this._editor\n if (editor) {\n const { selection } = editor.state\n const { $from } = selection\n const node = $from.node($from.depth)\n if (node.type.name === 'image') {\n const coords = editor.view.coordsAtPos($from.start())\n const wrapperRect = this.shadowRoot?.querySelector('.editor-wrapper')?.getBoundingClientRect()\n if (wrapperRect) {\n const x = coords.left - wrapperRect.left + (coords.right - coords.left) / 2\n const y = coords.top - wrapperRect.top - 40\n this._showImageToolbar({ x, y })\n }\n } else {\n this._hideImageToolbar()\n }\n }\n })\n\n this._editor.on('transaction', () => {\n if (this._editor?.isActive('table')) {\n this._showTableCellToolbar()\n } else {\n this._hideTableCellToolbar()\n }\n this._checkSlashCommand()\n this._setupTableEdgeDetection()\n })\n\n this._editor.on('update', () => {\n this._emitContentChange()\n })\n }\n\n private _tableEdgeDetectionSetup = false\n\n private _emitContentChange() {\n if (!this._editor) return\n const html = this._editor.getHTML()\n\n this.dispatchEvent(new CustomEvent('content-change', {\n detail: html,\n bubbles: true,\n composed: true,\n }))\n }\n\n private _setupTableEdgeDetection() {\n const editorContent = this.shadowRoot?.querySelector('.editor-content')\n const editorWrapper = this.shadowRoot?.querySelector('.editor-wrapper')\n if (!editorContent || this._tableEdgeDetectionSetup) return\n \n this._tableEdgeDetectionSetup = true\n \n const handleEditorClick = () => {\n this._editor?.chain().focus().run()\n }\n\n editorContent.addEventListener('click', handleEditorClick)\n editorWrapper?.addEventListener('click', handleEditorClick)\n }\n\n\n private _checkSlashCommand() {\n if (!this._editor) return\n const { selection } = this._editor.state\n const textBefore = this._editor.state.doc.textBetween(\n Math.max(0, selection.from - 10),\n selection.from,\n ' '\n )\n this._hasSlashCommand = textBefore.endsWith('/')\n }\n\n firstUpdated() {\n this._injectCustomStyles()\n this._initEditor()\n }\n\n updated(changed: Map<string, unknown>) {\n if (changed.has('customStylesAttr')) {\n this._injectCustomStyles()\n }\n\n if (this._editor) {\n if (changed.has('content') || (changed.has('modelValue') && this.useModel)) {\n const newContent = this.useModel ? this.modelValue : this.content\n if (newContent !== this._editor.getHTML()) {\n this._editor.commands.setContent(newContent || '<p></p>')\n }\n }\n if (changed.has('readonly')) {\n this._editor.setEditable(!this.readonly)\n }\n return\n }\n\n // 编辑器未初始化时,只保存待处理内容,不重复初始化\n if (changed.has('content')) {\n this._pendingContent = this.content\n }\n\n if (changed.has('modelValue') && this.useModel) {\n this._pendingContent = this.modelValue\n }\n\n // 只有在 firstUpdated 时才会初始化编辑器\n // 这里不再重复调用 _initEditor()\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this._editor?.destroy()\n this._editor = null\n }\n\n getContent(): string {\n return this._editor?.getHTML() ?? ''\n }\n\n forceUpdate(): void {\n this.requestUpdate()\n if (this._editor) {\n const newContent = this.useModel ? this.modelValue : this.content\n if (newContent !== this._editor.getHTML()) {\n this._editor.commands.setContent(newContent || '<p></p>')\n }\n }\n }\n\n\n private _applyFormat(command: () => void) {\n if (this._hasSlashCommand && this._editor) {\n const { selection } = this._editor.state\n this._editor.chain().focus().deleteRange({ from: selection.from - 1, to: selection.from }).run()\n this._hasSlashCommand = false\n }\n command()\n }\n\n private _toggleBold() {\n this._applyFormat(() => this._editor?.chain().focus().toggleBold().run())\n }\n\n private _toggleItalic() {\n this._applyFormat(() => this._editor?.chain().focus().toggleItalic().run())\n }\n\n private _toggleUnderline() {\n this._applyFormat(() => this._editor?.chain().focus().toggleUnderline().run())\n }\n\n private _toggleStrike() {\n this._applyFormat(() => this._editor?.chain().focus().toggleStrike().run())\n }\n\n private _toggleCode() {\n this._applyFormat(() => this._editor?.chain().focus().toggleCode().run())\n }\n\n private _setHeading(level: number) {\n this._applyFormat(() => this._editor?.chain().focus().toggleHeading({ level: level as 1 | 2 | 3 | 4 | 5 | 6 }).run())\n }\n\n private _setParagraph() {\n this._applyFormat(() => this._editor?.chain().focus().setParagraph().run())\n }\n\n private _toggleBulletList() {\n this._applyFormat(() => this._editor?.chain().focus().toggleBulletList().run())\n }\n\n private _toggleOrderedList() {\n this._applyFormat(() => this._editor?.chain().focus().toggleOrderedList().run())\n }\n\n private _toggleBlockquote() {\n this._applyFormat(() => this._editor?.chain().focus().toggleBlockquote().run())\n }\n\n private _setTextAlign(align: string) {\n this._applyFormat(() => this._editor?.chain().focus().setTextAlign(align as any).run())\n }\n\n private _setLink() {\n // eslint-disable-next-line no-alert\n const url = window.prompt('请输入链接地址:')\n if (url) {\n this._applyFormat(() => this._editor?.chain().focus().setLink({ href: url }).run())\n }\n }\n\n\n private _insertTable(rows?: number, cols?: number) {\n this._editor?.chain().focus().insertTable({ rows: rows ?? this._tableRows, cols: cols ?? this._tableCols, withHeaderRow: true }).run()\n }\n\n private async _handleImageUpload(e: Event) {\n const input = e.target as HTMLInputElement\n const file = input.files?.[0]\n if (file) {\n try {\n const src = await this.uploadImage(file)\n this._editor?.chain().focus().setImage({ src }).run()\n }\n catch (err) {\n console.error('图片上传失败:', err)\n }\n }\n input.value = ''\n }\n\n private _triggerImageUpload() {\n const input = this.shadowRoot?.querySelector<HTMLInputElement>('.image-input')\n input?.click()\n }\n\n private _insertTableByClick(rows: number, cols: number) {\n if (this._hasSlashCommand && this._editor) {\n const { selection } = this._editor.state\n this._editor.chain().focus().deleteRange({ from: selection.from - 1, to: selection.from }).run()\n this._hasSlashCommand = false\n }\n this._tableRows = rows\n this._tableCols = cols\n this._insertTable(rows, cols)\n }\n\n\n private _showTableCellToolbar() {\n if (!this._editor?.isActive('table')) return\n const { state } = this._editor\n const { selection } = state\n const coords = this._editor.view.coordsAtPos(selection.from)\n const editorWrapper = this.shadowRoot?.querySelector<HTMLElement>('.editor-wrapper')\n if (!editorWrapper) return\n const wrapperRect = editorWrapper.getBoundingClientRect()\n\n const cellRow = this._getTableCellRow()\n const cellCol = this._getTableCellCol()\n const isTopRow = cellRow === 0\n const isLeftCol = cellCol === 0\n\n // Only show toolbar on top row or left column\n if (!isTopRow && !isLeftCol) return\n\n requestAnimationFrame(() => {\n this._tableCellToolbar = {\n x: coords.left - wrapperRect.left,\n y: coords.bottom - wrapperRect.top + 8,\n visible: true,\n cellRow,\n cellCol,\n }\n })\n }\n\n private _getTableCellRow(): number {\n if (!this._editor) return 0\n const { selection } = this._editor.state\n const $pos = this._editor.state.doc.resolve(selection.from)\n for (let d = $pos.depth; d > 0; d--) {\n const node = $pos.node(d)\n if (node.type.name === 'tableCell') {\n return $pos.index(d - 1)\n }\n }\n return 0\n }\n\n private _getTableCellCol(): number {\n if (!this._editor) return 0\n const { selection } = this._editor.state\n const $pos = this._editor.state.doc.resolve(selection.from)\n for (let d = $pos.depth; d > 0; d--) {\n const node = $pos.node(d)\n if (node.type.name === 'tableCell') {\n return $pos.index(d)\n }\n }\n return 0\n }\n\n private _hideTableCellToolbar() {\n requestAnimationFrame(() => {\n this._tableCellToolbar = { ...this._tableCellToolbar, visible: false }\n })\n }\n\n private _addTableRowAbove() {\n this._editor?.chain().focus().addRowBefore().run()\n this._hideTableCellToolbar()\n }\n\n private _addTableRowBelow() {\n this._editor?.chain().focus().addRowAfter().run()\n this._hideTableCellToolbar()\n }\n\n private _addTableColumnLeft() {\n this._editor?.chain().focus().addColumnBefore().run()\n this._hideTableCellToolbar()\n }\n\n private _addTableColumnRight() {\n this._editor?.chain().focus().addColumnAfter().run()\n this._hideTableCellToolbar()\n }\n\n private _deleteTableRow() {\n this._editor?.chain().focus().deleteRow().run()\n this._hideTableCellToolbar()\n }\n\n private _deleteTableColumn() {\n this._editor?.chain().focus().deleteColumn().run()\n this._hideTableCellToolbar()\n }\n\n private _deleteTable() {\n this._editor?.chain().focus().deleteTable().run()\n this._hideTableCellToolbar()\n }\n\n // Image Toolbar Methods\n private _showImageToolbar(pos: { x: number, y: number }) {\n requestAnimationFrame(() => {\n this._imageToolbar = { x: pos.x, y: pos.y, visible: true }\n this._imageMoreMenuVisible = false\n })\n }\n\n private _hideImageToolbar() {\n requestAnimationFrame(() => {\n this._imageToolbar = { ...this._imageToolbar, visible: false }\n this._imageMoreMenuVisible = false\n })\n }\n\n private _toggleImageMoreMenu() {\n this._imageMoreMenuVisible = !this._imageMoreMenuVisible\n }\n\n private _deleteImage() {\n this._editor?.chain().focus().deleteNode('image').run()\n this._hideImageToolbar()\n }\n\n private _insertImageAfter() {\n this._triggerImageUpload()\n this._imageMoreMenuVisible = false\n }\n\n private _setImageAlignLeft() {\n const editor = this._editor\n if (editor) {\n const { selection } = editor.state\n const pos = selection.from\n editor.chain().focus().setNodeSelection(pos).run()\n const img = this.shadowRoot?.querySelector('.ProseMirror img.ProseMirror-selectednode') as HTMLElement\n if (img) {\n img.style.display = 'block'\n img.style.margin = '0 auto 0 0'\n }\n }\n this._imageMoreMenuVisible = false\n }\n\n private _setImageAlignCenter() {\n const editor = this._editor\n if (editor) {\n const { selection } = editor.state\n const pos = selection.from\n editor.chain().focus().setNodeSelection(pos).run()\n const img = this.shadowRoot?.querySelector('.ProseMirror img.ProseMirror-selectednode') as HTMLElement\n if (img) {\n img.style.display = 'block'\n img.style.margin = '0 auto'\n }\n }\n this._imageMoreMenuVisible = false\n }\n\n private _setImageAlignRight() {\n const editor = this._editor\n if (editor) {\n const { selection } = editor.state\n const pos = selection.from\n editor.chain().focus().setNodeSelection(pos).run()\n const img = this.shadowRoot?.querySelector('.ProseMirror img.ProseMirror-selectednode') as HTMLElement\n if (img) {\n img.style.display = 'block'\n img.style.margin = '0 0 0 auto'\n }\n }\n this._imageMoreMenuVisible = false\n }\n\n\n private _getTextLabel(): string {\n const editor = this._editor\n if (!editor) { return '正文' }\n if (editor.isActive('heading', { level: 1 })) { return '标题 1' }\n if (editor.isActive('heading', { level: 2 })) { return '标题 2' }\n if (editor.isActive('heading', { level: 3 })) { return '标题 3' }\n return '正文'\n }\n\n private _getAlignLabel(): string {\n const editor = this._editor\n if (!editor) { return '对齐' }\n if (editor.isActive({ textAlign: 'center' })) { return '居中' }\n if (editor.isActive({ textAlign: 'right' })) { return '右对齐' }\n return '左对齐'\n }\n\n private _updateBubbleMenuPosition() {\n requestAnimationFrame(() => {\n const bubbleMenu = this.shadowRoot?.querySelector<HTMLElement>('.bubble-menu')\n const proseMirror = this.shadowRoot?.querySelector<HTMLElement>('.ProseMirror')\n const editorWrapper = this.shadowRoot?.querySelector<HTMLElement>('.editor-wrapper')\n if (!bubbleMenu || !proseMirror || !editorWrapper) { return }\n\n const editor = this._editor\n const isInTable = editor?.isActive('table') ?? false\n const { selection } = editor?.state ?? { selection: null }\n\n // 如果选中了表格节点(而不只是单元格内的文字),隐藏菜单\n if (isInTable && selection && !selection.empty && editor) {\n const { from, to } = selection\n const $from = editor.state.doc.resolve(from)\n const $to = editor.state.doc.resolve(to)\n // 检查选区起点和终点之间是否有表格节点\n let hasTableInSelection = false\n for (let d = $from.depth; d >= 0; d--) {\n if ($from.node(d).type.name === 'table') {\n hasTableInSelection = true\n break\n }\n }\n // 如果选区起点在表格外但终点在表格内,或者选区跨越了表格\n const fromAncestor = $from.node($from.depth)\n const toAncestor = $to.node($to.depth)\n if (fromAncestor.type.name === 'table' || toAncestor.type.name === 'table') {\n hasTableInSelection = true\n }\n if (hasTableInSelection) {\n bubbleMenu.style.opacity = '0'\n bubbleMenu.style.visibility = 'hidden'\n return\n }\n }\n\n // 如果有选中文字,显示菜单\n if (selection && !selection.empty) {\n // continue to show menu\n } else if (!selection || (selection.empty && !this._hasSlashCommand)) {\n bubbleMenu.style.opacity = '0'\n bubbleMenu.style.visibility = 'hidden'\n return\n }\n\n const wrapperRect = editorWrapper.getBoundingClientRect()\n const menuRect = bubbleMenu.getBoundingClientRect()\n\n const { from } = selection!\n const coords = this._editor?.view.coordsAtPos(from)\n if (!coords) { return }\n\n let left = coords.left - wrapperRect.left\n let top = coords.top - wrapperRect.top - 40\n\n if (left + menuRect.width > wrapperRect.width) {\n left = wrapperRect.width - menuRect.width - 8\n }\n if (left < 0) {\n left = 8\n }\n\n if (top < 0) {\n top = coords.bottom - wrapperRect.top + 8\n }\n\n bubbleMenu.style.left = `${left}px`\n bubbleMenu.style.top = `${top}px`\n bubbleMenu.style.opacity = '1'\n bubbleMenu.style.visibility = 'visible'\n })\n }\n\n render() {\n const editor = this._editor\n\n return html`\n <div class=\"editor-wrapper ${!editor ? 'loading' : ''} ${this.preview ? 'preview' : ''}\">\n ${!editor ? html`\n <div class=\"loading-placeholder\">\n <div class=\"loading-spinner\"></div>\n <span>编辑器加载中...</span>\n </div>\n ` : ''}\n <input\n type=\"file\"\n accept=\"image/*\"\n class=\"image-input\"\n @change=${this._handleImageUpload}\n />\n\n <!-- Bubble Menu (悬浮操作栏) -->\n ${!this.preview ? html`\n <div class=\"bubble-menu\">\n <!-- 文本格式 -->\n <button\n class=\"bubble-btn ${editor?.isActive('bold') ? 'is-active' : ''}\"\n @click=${this._toggleBold}\n title=\"加粗\"\n >\n <svg viewBox=\"0 0 24 24\"><path d=\"M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\"/><path d=\"M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\"/></svg>\n </button>\n <button\n class=\"bubble-btn ${editor?.isActive('italic') ? 'is-active' : ''}\"\n @click=${this._toggleItalic}\n title=\"斜体\"\n >\n <svg viewBox=\"0 0 24 24\"><line x1=\"19\" y1=\"4\" x2=\"10\" y2=\"4\"/><line x1=\"14\" y1=\"20\" x2=\"5\" y2=\"20\"/><line x1=\"15\" y1=\"4\" x2=\"9\" y2=\"20\"/></svg>\n </button>\n <button\n class=\"bubble-btn ${editor?.isActive('underline') ? 'is-active' : ''}\"\n @click=${this._toggleUnderline}\n title=\"下划线\"\n >\n <svg viewBox=\"0 0 24 24\"><path d=\"M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3\"/><line x1=\"4\" y1=\"21\" x2=\"20\" y2=\"21\"/></svg>\n </button>\n <button\n class=\"bubble-btn ${editor?.isActive('strike') ? 'is-active' : ''}\"\n @click=${this._toggleStrike}\n title=\"删除线\"\n >\n <svg viewBox=\"0 0 24 24\"><path d=\"M17.3 4.9c-2.3-.6-4.4-1-6.2-.9-2.7 0-5.3.7-5.3 3.6 0 1.5 1.8 3.3 5.3 3.9h.2m8.2 3.2c.3.4.4.8.4 1.3 0 2.9-2.7 3.6-6.2 3.6-2.3 0-4.4-.3-6.2-.9M4 12h16\"/></svg>\n </button>\n\n <div class=\"bubble-divider\"></div>\n\n <!-- 文本类型下拉 -->\n <div class=\"bubble-dropdown\">\n <button class=\"bubble-dropdown-btn\">\n ${this._getTextLabel()}\n <svg viewBox=\"0 0 24 24\"><polyline points=\"6 9 12 15 18 9\"/></svg>\n </button>\n <div class=\"bubble-dropdown-menu\">\n <button\n class=\"bubble-dropdown-item ${!editor?.isActive('heading') ? 'is-active' : ''}\"\n @click=${this._setParagraph}\n >\n 正文\n </button>\n <button\n class=\"bubble-dropdown-item ${editor?.isActive('heading', { level: 1 }) ? 'is-active' : ''}\"\n @click=${() => this._setHeading(1)}\n >\n 标题 1\n </button>\n <button\n class=\"bubble-dropdown-item ${editor?.isActive('heading', { level: 2 }) ? 'is-active' : ''}\"\n @click=${() => this._setHeading(2)}\n >\n 标题 2\n </button>\n <button\n class=\"bubble-dropdown-item ${editor?.isActive('heading', { level: 3 }) ? 'is-active' : ''}\"\n @click=${() => this._setHeading(3)}\n >\n 标题 3\n </button>\n </div>\n </div>\n\n <div class=\"bubble-divider\"></div>\n\n <!-- 对齐下拉 -->\n <div class=\"bubble-dropdown\">\n <button class=\"bubble-dropdown-btn\">\n ${this._getAlignLabel()}\n <svg viewBox=\"0 0 24 24\"><polyline points=\"6 9 12 15 18 9\"/></svg>\n </button>\n <div class=\"bubble-dropdown-menu\">\n <button\n class=\"bubble-dropdown-item ${editor?.isActive({ textAlign: 'left' }) ? 'is-active' : ''}\"\n @click=${() => this._setTextAlign('left')}\n >\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"3\" y1=\"12\" x2=\"15\" y2=\"12\"/><line x1=\"3\" y1=\"18\" x2=\"18\" y2=\"18\"/></svg>\n 左对齐\n </button>\n <button\n class=\"bubble-dropdown-item ${editor?.isActive({ textAlign: 'center' }) ? 'is-active' : ''}\"\n @click=${() => this._setTextAlign('center')}\n >\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"6\" y1=\"12\" x2=\"18\" y2=\"12\"/><line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"/></svg>\n 居中\n </button>\n <button\n class=\"bubble-dropdown-item ${editor?.isActive({ textAlign: 'right' }) ? 'is-active' : ''}\"\n @click=${() => this._setTextAlign('right')}\n >\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"9\" y1=\"12\" x2=\"21\" y2=\"12\"/><line x1=\"6\" y1=\"18\" x2=\"21\" y2=\"18\"/></svg>\n 右对齐\n </button>\n </div>\n </div>\n\n <div class=\"bubble-divider\"></div>\n\n <!-- 行内代码 -->\n <button\n class=\"bubble-btn ${editor?.isActive('code') ? 'is-active' : ''}\"\n @click=${this._toggleCode}\n title=\"行内代码\"\n >\n <svg viewBox=\"0 0 24 24\"><polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/></svg>\n </button>\n\n <!-- 链接 -->\n <button\n class=\"bubble-btn ${editor?.isActive('link') ? 'is-active' : ''}\"\n @click=${this._setLink}\n title=\"链接\"\n >\n <svg viewBox=\"0 0 24 24\"><path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/></svg>\n </button>\n\n <!-- 图片 -->\n <button\n class=\"bubble-btn\"\n @click=${this._triggerImageUpload}\n title=\"图片\"\n >\n <svg viewBox=\"0 0 24 24\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/></svg>\n </button>\n\n <div class=\"bubble-divider\"></div>\n\n <!-- 列表 -->\n <button\n class=\"bubble-btn ${editor?.isActive('bulletList') ? 'is-active' : ''}\"\n @click=${this._toggleBulletList}\n title=\"无序列表\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"9\" y1=\"6\" x2=\"20\" y2=\"6\"/>\n <line x1=\"9\" y1=\"12\" x2=\"20\" y2=\"12\"/>\n <line x1=\"9\" y1=\"18\" x2=\"20\" y2=\"18\"/>\n <circle cx=\"4\" cy=\"6\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\"/>\n <circle cx=\"4\" cy=\"12\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\"/>\n <circle cx=\"4\" cy=\"18\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\"/>\n </svg>\n </button>\n <button\n class=\"bubble-btn ${editor?.isActive('orderedList') ? 'is-active' : ''}\"\n @click=${this._toggleOrderedList}\n title=\"有序列表\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"10\" y1=\"6\" x2=\"21\" y2=\"6\"/>\n <line x1=\"10\" y1=\"12\" x2=\"21\" y2=\"12\"/>\n <line x1=\"10\" y1=\"18\" x2=\"21\" y2=\"18\"/>\n <path d=\"M4 6h1v4\"/>\n <path d=\"M4 10h2\"/>\n <path d=\"M6 18H4c0-1 2-2 2-3s-1-1.5-2-1.5\"/>\n </svg>\n </button>\n\n <!-- 引用 -->\n <button\n class=\"bubble-btn ${editor?.isActive('blockquote') ? 'is-active' : ''}\"\n @click=${this._toggleBlockquote}\n title=\"引用\"\n >\n <svg viewBox=\"0 0 24 24\"><path d=\"M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V21z\"/><path d=\"M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z\"/></svg>\n </button>\n\n <div class=\"bubble-divider\"></div>\n\n <!-- 表格下拉 -->\n <div\n class=\"bubble-dropdown ${this._tableDropdownOpen ? 'is-open' : ''}\"\n @mouseenter=${() => {\n this._tableDropdownOpen = true\n this._hoverRow = 0\n this._hoverCol = 0\n }}\n @mouseleave=${() => this._tableDropdownOpen = false}\n >\n <button class=\"bubble-dropdown-btn\" title=\"表格\">\n <svg viewBox=\"0 0 24 24\" style=\"width:18px;height:18px;stroke:currentColor;stroke-width:2;fill:none;\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/><line x1=\"3\" y1=\"15\" x2=\"21\" y2=\"15\"/><line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"21\"/><line x1=\"15\" y1=\"3\" x2=\"15\" y2=\"21\"/></svg>\n </button>\n <div class=\"bubble-dropdown-menu\">\n <div class=\"table-grid-preview\">\n ${this._renderTableGrid()}\n </div>\n <div class=\"table-size-hint\">\n <span>${this._hoverRow > 0 ? `${this._hoverRow} × ${this._hoverCol}` : `${this._tableRows} × ${this._tableCols}`}</span>\n </div>\n </div>\n </div>\n </div>\n ` : ''}\n\n <div class=\"editor-content\"></div>\n\n <!-- Table Cell Toolbar -->\n ${this._tableCellToolbar.visible && editor?.isActive('table')\n ? html`\n <div\n class=\"table-cell-toolbar\"\n style=\"left: ${this._tableCellToolbar.x}px; top: ${this._tableCellToolbar.y}px;\"\n @mousedown=${(e: Event) => e.preventDefault()}\n >\n ${this._tableCellToolbar.cellRow === 0 ? html`\n <button class=\"table-cell-toolbar-btn\" title=\"上方添加行\" @click=${this._addTableRowAbove}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"4\" y=\"8\" width=\"16\" height=\"8\" rx=\"1\"/><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"7\"/><line x1=\"10\" y1=\"5\" x2=\"14\" y2=\"5\"/></svg>\n </button>\n <button class=\"table-cell-toolbar-btn\" title=\"下方添加行\" @click=${this._addTableRowBelow}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"4\" y=\"8\" width=\"16\" height=\"8\" rx=\"1\"/><line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"17\"/><line x1=\"10\" y1=\"19\" x2=\"14\" y2=\"19\"/></svg>\n </button>\n <button class=\"table-cell-toolbar-btn danger\" title=\"删除行\" @click=${this._deleteTableRow}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"4\" y=\"8\" width=\"16\" height=\"8\" rx=\"1\"/><line x1=\"9\" y1=\"10\" x2=\"9\" y2=\"14\"/><line x1=\"15\" y1=\"10\" x2=\"15\" y2=\"14\"/></svg>\n </button>\n ` : ''}\n ${this._tableCellToolbar.cellCol === 0 ? html`\n ${this._tableCellToolbar.cellRow !== 0 ? html`<div style=\"width:1px;height:20px;background:#e3e3e3;margin:0 4px;\"></div>` : ''}\n <button class=\"table-cell-toolbar-btn\" title=\"左侧添加列\" @click=${this._addTableColumnLeft}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"8\" y=\"4\" width=\"8\" height=\"16\" rx=\"1\"/><line x1=\"3\" y1=\"12\" x2=\"7\" y2=\"12\"/><line x1=\"5\" y1=\"10\" x2=\"5\" y2=\"14\"/></svg>\n </button>\n <button class=\"table-cell-toolbar-btn\" title=\"右侧添加列\" @click=${this._addTableColumnRight}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"8\" y=\"4\" width=\"8\" height=\"16\" rx=\"1\"/><line x1=\"21\" y1=\"12\" x2=\"17\" y2=\"12\"/><line x1=\"19\" y1=\"10\" x2=\"19\" y2=\"14\"/></svg>\n </button>\n <button class=\"table-cell-toolbar-btn danger\" title=\"删除列\" @click=${this._deleteTableColumn}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"8\" y=\"4\" width=\"8\" height=\"16\" rx=\"1\"/><line x1=\"10\" y1=\"9\" x2=\"14\" y2=\"9\"/><line x1=\"10\" y1=\"15\" x2=\"14\" y2=\"15\"/></svg>\n </button>\n ` : ''}\n ${this._tableCellToolbar.cellRow === 0 && this._tableCellToolbar.cellCol === 0 ? html`\n <div style=\"width:1px;height:20px;background:#e3e3e3;margin:0 4px;\"></div>\n <button class=\"table-cell-toolbar-btn danger\" title=\"删除表格\" @click=${this._deleteTable}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>\n </button>\n ` : ''}\n </div>\n `\n : ''}\n\n <!-- Image Toolbar -->\n ${this._imageToolbar.visible\n ? html`\n <div\n class=\"image-toolbar\"\n style=\"left: ${this._imageToolbar.x}px; top: ${this._imageToolbar.y}px;\"\n @mousedown=${(e: Event) => e.preventDefault()}\n >\n <button class=\"image-toolbar-btn danger\" title=\"删除图片\" @click=${this._deleteImage}>\n <svg viewBox=\"0 0 24 24\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>\n </button>\n <button class=\"image-toolbar-btn\" title=\"添加图片\" @click=${this._insertImageAfter}>\n <svg viewBox=\"0 0 24 24\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>\n </button>\n <div class=\"image-toolbar-divider\"></div>\n <div style=\"position: relative;\">\n <button class=\"image-toolbar-btn\" title=\"更多\" @click=${this._toggleImageMoreMenu}>\n <svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"1\"/><circle cx=\"19\" cy=\"12\" r=\"1\"/><circle cx=\"5\" cy=\"12\" r=\"1\"/></svg>\n </button>\n ${this._imageMoreMenuVisible\n ? html`\n <div class=\"image-more-menu\">\n <button class=\"image-more-menu-item\" @click=${this._setImageAlignLeft}>\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"3\" y1=\"12\" x2=\"15\" y2=\"12\"/><line x1=\"3\" y1=\"18\" x2=\"18\" y2=\"18\"/></svg>\n 左对齐\n </button>\n <button class=\"image-more-menu-item\" @click=${this._setImageAlignCenter}>\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"6\" y1=\"12\" x2=\"18\" y2=\"12\"/><line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"/></svg>\n 居中\n </button>\n <button class=\"image-more-menu-item\" @click=${this._setImageAlignRight}>\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"9\" y1=\"12\" x2=\"21\" y2=\"12\"/><line x1=\"6\" y1=\"18\" x2=\"21\" y2=\"18\"/></svg>\n 右对齐\n </button>\n </div>\n `\n : ''}\n </div>\n </div>\n `\n : ''}\n </div>\n `\n }\n\n private _renderTableGrid() {\n const cells = []\n for (let i = 0; i < 100; i++) {\n const row = Math.floor(i / 10) + 1\n const col = (i % 10) + 1\n const isHighlight = this._hoverRow > 0 && row <= this._hoverRow && col <= this._hoverCol\n cells.push(html`\n <div\n class=\"table-cell ${isHighlight ? 'selected' : ''}\"\n @click=${() => {\n this._insertTableByClick(row, col)\n this._tableDropdownOpen = false\n }}\n @mouseenter=${() => {\n this._hoverRow = row\n this._hoverCol = col\n }}\n @mouseleave=${() => {\n this._hoverRow = 0\n this._hoverCol = 0\n }}\n ></div>\n `)\n }\n return cells\n }\n}\n\nexport function register() {}\n"],"names":["QxsBlocksuiteEditor","LitElement","constructor","super","arguments","this","content","modelValue","useModelAttr","readonlyAttr","previewAttr","customStylesAttr","_injectedStyleEl","uploadImage","async","Promise","resolve","reject","reader","FileReader","onload","e","target","result","onerror","readAsDataURL","file","_editor","_pendingContent","_tableRows","_tableCols","_hoverRow","_hoverCol","_tableDropdownOpen","_tableCellToolbar","x","y","visible","cellRow","cellCol","_imageToolbar","_imageMoreMenuVisible","_hasSlashCommand","_tableEdgeDetectionSetup","_injectCustomStyles","shadow","shadowRoot","remove","styleEl","document","createElement","textContent","appendChild","useModel","hasAttribute","value","String","readonly","preview","_initEditor","el","querySelector","requestAnimationFrame","firstChild","removeChild","getAttribute","contentValue","initialContent","extensions","Document","Paragraph","Text","Bold","Italic","Underline","Strike","Code","Heading","extend","addAttributes","parent","dataType","default","parseHTML","element","renderHTML","attributes","configure","levels","BulletList","OrderedList","ListItem","Blockquote","HorizontalRule","History","Image","inline","allowBase64","Link","openOnClick","HTMLAttributes","rel","TextAlign","types","Table","resizable","TableRow","TableCell","TableHeader","Placeholder","placeholder","Extension","create","name","addKeyboardShortcuts","Enter","editor","chain","focus","unsetAllMarks","clearNodes","run","Editor","editable","on","_updateBubbleMenuPosition","isActive","_showTableCellToolbar","_hideTableCellToolbar","selection","state","$from","node","depth","type","coords","view","coordsAtPos","start","wrapperRect","getBoundingClientRect","left","right","top","_showImageToolbar","_hideImageToolbar","_checkSlashCommand","_setupTableEdgeDetection","_emitContentChange","html","getHTML","dispatchEvent","CustomEvent","detail","bubbles","composed","editorContent","editorWrapper","handleEditorClick","addEventListener","textBefore","doc","textBetween","Math","max","from","endsWith","firstUpdated","updated","changed","has","newContent","commands","setContent","setEditable","disconnectedCallback","destroy","getContent","forceUpdate","requestUpdate","_applyFormat","command","deleteRange","to","_toggleBold","toggleBold","_toggleItalic","toggleItalic","_toggleUnderline","toggleUnderline","_toggleStrike","toggleStrike","_toggleCode","toggleCode","_setHeading","level","toggleHeading","_setParagraph","setParagraph","_toggleBulletList","toggleBulletList","_toggleOrderedList","toggleOrderedList","_toggleBlockquote","toggleBlockquote","_setTextAlign","align","setTextAlign","_setLink","url","window","prompt","setLink","href","_insertTable","rows","cols","insertTable","withHeaderRow","_handleImageUpload","input","files","src","setImage","err","_triggerImageUpload","click","_insertTableByClick","_getTableCellRow","_getTableCellCol","bottom","$pos","d","index","_addTableRowAbove","addRowBefore","_addTableRowBelow","addRowAfter","_addTableColumnLeft","addColumnBefore","_addTableColumnRight","addColumnAfter","_deleteTableRow","deleteRow","_deleteTableColumn","deleteColumn","_deleteTable","deleteTable","pos","_toggleImageMoreMenu","_deleteImage","deleteNode","_insertImageAfter","_setImageAlignLeft","setNodeSelection","img","style","display","margin","_setImageAlignCenter","_setImageAlignRight","_getTextLabel","_getAlignLabel","textAlign","bubbleMenu","proseMirror","isInTable","empty","$to","hasTableInSelection","fromAncestor","toAncestor","opacity","visibility","menuRect","width","render","_renderTableGrid","preventDefault","cells","i","row","floor","col","isHighlight","push","styles","css","__decorateClass","property","attribute","prototype","Object","safeCustomElement"],"mappings":"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"}
1
+ {"version":3,"file":"blocksuite-editor.cjs","sources":["../../../../packages/components-wc/src/editor/blocksuite-editor.ts"],"sourcesContent":["import { Editor } from '@tiptap/core'\nimport Blockquote from '@tiptap/extension-blockquote'\nimport Bold from '@tiptap/extension-bold'\nimport BulletList from '@tiptap/extension-bullet-list'\nimport Code from '@tiptap/extension-code'\nimport Document from '@tiptap/extension-document'\nimport Heading from '@tiptap/extension-heading'\nimport History from '@tiptap/extension-history'\nimport HorizontalRule from '@tiptap/extension-horizontal-rule'\nimport Image from '@tiptap/extension-image'\nimport Italic from '@tiptap/extension-italic'\nimport Link from '@tiptap/extension-link'\nimport ListItem from '@tiptap/extension-list-item'\nimport OrderedList from '@tiptap/extension-ordered-list'\nimport Paragraph from '@tiptap/extension-paragraph'\nimport Strike from '@tiptap/extension-strike'\nimport { Table } from '@tiptap/extension-table'\nimport { TableCell } from '@tiptap/extension-table-cell'\nimport { TableHeader } from '@tiptap/extension-table-header'\nimport { TableRow } from '@tiptap/extension-table-row'\nimport Text from '@tiptap/extension-text'\nimport TextAlign from '@tiptap/extension-text-align'\nimport Underline from '@tiptap/extension-underline'\nimport Placeholder from '@tiptap/extension-placeholder'\nimport { Extension } from '@tiptap/core'\nimport { css, html, LitElement } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { safeCustomElement } from '../base/define'\n\n@safeCustomElement('qxs-blocksuite-editor')\nexport class QxsBlocksuiteEditor extends LitElement {\n static styles = css`\n :host {\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, sans-serif;\n }\n\n .editor-wrapper {\n border: 1px solid #e3e3e3;\n border-radius: 12px;\n background: #fff;\n overflow: visible;\n position: relative;\n min-height: 80px;\n }\n\n .editor-wrapper:focus-within {\n border-color: var(--qxs-color-primary, #3D61E3);\n }\n\n .editor-wrapper.preview {\n border: none;\n border-radius: 0;\n background: transparent;\n }\n\n .editor-wrapper.preview .editor-content {\n padding: 8px 12px;\n min-height: unset;\n }\n\n .editor-content {\n padding: 12px 16px;\n min-height: 80px;\n cursor: text;\n }\n\n .editor-content:empty::before {\n content: '输入 / 唤出快捷命令';\n color: #c0c0c0;\n pointer-events: none;\n display: block;\n padding-top: 28px;\n text-align: center;\n }\n\n .editor-content .ProseMirror:empty {\n min-height: 80px;\n }\n\n .ProseMirror p.is-editor-empty:first-child::before {\n content: attr(data-placeholder);\n color: #c0c0c0;\n pointer-events: none;\n float: left;\n height: 0;\n }\n\n .ProseMirror p.is-empty:only-child::before,\n .ProseMirror p.is-empty:only-child > br:first-child + *::before {\n content: attr(data-placeholder);\n color: #c0c0c0;\n pointer-events: none;\n float: left;\n height: 0;\n }\n\n .editor-wrapper.loading {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n background: #fafafa;\n }\n\n .loading-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: #909399;\n font-size: 14px;\n }\n\n .loading-spinner {\n width: 24px;\n height: 24px;\n border: 2px solid #e3e3e3;\n border-top-color: var(--qxs-color-primary, #3D61E3);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .ProseMirror {\n outline: none;\n line-height: 1.7;\n color: #37352f;\n font-size: 15px;\n }\n\n .ProseMirror > * + * {\n margin-top: 0.5em;\n }\n\n .ProseMirror > *:first-child {\n margin-top: 0 !important;\n }\n\n .ProseMirror p {\n margin: 0;\n }\n\n .ProseMirror h1 {\n font-size: 1.875em;\n font-weight: 700;\n margin: 0 0 0.25em;\n line-height: 1.3;\n }\n\n .ProseMirror > h1:first-child {\n margin-top: 0 !important;\n line-height: 1.15;\n }\n\n .ProseMirror > p:first-child {\n margin-top: 0 !important;\n }\n\n .ProseMirror h2 {\n font-size: 1.5em;\n font-weight: 600;\n margin: 0.5em 0 0.25em;\n line-height: 1.3;\n }\n\n .ProseMirror h3 {\n font-size: 1.25em;\n font-weight: 600;\n margin: 0.5em 0 0.25em;\n line-height: 1.3;\n }\n\n .ProseMirror ul,\n .ProseMirror ol {\n padding-left: 1.5em;\n margin: 0;\n }\n\n .ProseMirror li {\n margin: 0.1em 0;\n }\n\n .ProseMirror li::marker {\n color: #37352f;\n }\n\n .ProseMirror strong {\n font-weight: 700;\n }\n\n .ProseMirror em {\n font-style: italic;\n font-synthesis: none;\n transform: skewX(-12deg);\n display: inline-block;\n }\n\n .ProseMirror u {\n text-decoration: underline;\n }\n\n .ProseMirror s {\n text-decoration: line-through;\n color: #787774;\n }\n\n .ProseMirror code {\n background: rgba(135, 131, 120, 0.14);\n color: #eb5757;\n padding: 2px 4px;\n border-radius: 4px;\n font-family: 'SFMono-Regular', Menlo, Consolas, monospace;\n font-size: 85%;\n }\n\n .ProseMirror pre {\n background: #f6f6f7;\n border-radius: 8px;\n padding: 12px 16px;\n overflow-x: auto;\n }\n\n .ProseMirror pre code {\n background: none;\n padding: 0;\n color: #37352f;\n }\n\n .ProseMirror blockquote {\n border-left: 3px solid #e3e3e3;\n padding-left: 1em;\n margin: 0.75em 0;\n color: #787774;\n }\n\n .ProseMirror hr {\n border: none;\n border-top: 1px solid #e3e3e3;\n margin: 1.5em 0;\n }\n\n .ProseMirror img {\n max-width: 100%;\n height: auto;\n border-radius: 8px;\n }\n\n .ProseMirror a {\n color: var(--qxs-color-primary, #3D61E3);\n text-decoration: underline;\n cursor: pointer;\n }\n\n .ProseMirror img.ProseMirror-selectednode {\n outline: 2px solid var(--qxs-color-primary, #3D61E3);\n }\n\n /* Table styles */\n .ProseMirror table {\n border-collapse: collapse;\n width: 100%;\n margin: 1em 0;\n border: 1px solid #e3e3e3;\n border-radius: 8px;\n overflow: hidden;\n }\n\n .ProseMirror th,\n .ProseMirror td {\n border: 1px solid #e3e3e3;\n padding: 8px 12px;\n text-align: left;\n vertical-align: top;\n }\n\n .ProseMirror th {\n background: #fafafa;\n font-weight: 600;\n }\n\n .ProseMirror .selectedCell {\n background: rgba(30, 150, 252, 0.1);\n }\n\n /* Table Cell Toolbar */\n .table-cell-toolbar {\n position: absolute;\n z-index: 50;\n display: flex;\n gap: 2px;\n padding: 4px;\n background: #fff;\n border: 1px solid #e3e3e3;\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n }\n\n .table-cell-toolbar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n color: #606266;\n transition: all 0.15s;\n }\n\n .table-cell-toolbar-btn:hover {\n background: #ecf5ff;\n color: var(--qxs-color-primary, #3D61E3);\n }\n\n .table-cell-toolbar-btn.danger:hover {\n background: #fef0f0;\n color: #f56c6c;\n }\n\n /* Bubble Menu */\n .bubble-menu {\n position: absolute;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 4px 6px;\n background: #fff;\n border: 1px solid #e3e3e3;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 100;\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.15s, visibility 0.15s, transform 0.15s;\n transform: translateY(4px);\n max-width: calc(100vw - 40px);\n }\n\n .bubble-menu.is-visible {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n }\n\n .bubble-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: #37352f;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.15s;\n position: relative;\n }\n\n .bubble-btn:hover {\n background: rgba(55, 53, 47, 0.08);\n }\n\n .bubble-btn.is-active {\n background: var(--qxs-color-primary, #3D61E3);\n color: #fff;\n }\n\n .bubble-btn svg {\n width: 16px;\n height: 16px;\n stroke: currentColor;\n stroke-width: 2;\n fill: none;\n }\n\n .bubble-divider {\n width: 1px;\n height: 16px;\n background: #e3e3e3;\n margin: 0 3px;\n }\n\n /* Dropdown */\n .bubble-dropdown {\n position: relative;\n }\n\n .bubble-dropdown-btn {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 0 6px;\n height: 28px;\n border: none;\n background: transparent;\n color: #37352f;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n font-family: inherit;\n transition: all 0.15s;\n white-space: nowrap;\n }\n\n .bubble-dropdown-btn:hover {\n background: rgba(55, 53, 47, 0.08);\n }\n\n .bubble-dropdown-btn svg {\n width: 12px;\n height: 12px;\n stroke: currentColor;\n stroke-width: 2;\n fill: none;\n }\n\n .bubble-dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n margin-top: 4px;\n min-width: 120px;\n background: #fff;\n border: 1px solid #e3e3e3;\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n padding: 4px;\n opacity: 0;\n visibility: hidden;\n transform: translateY(-4px);\n transition: all 0.15s;\n z-index: 101;\n }\n\n .bubble-dropdown:hover .bubble-dropdown-menu,\n .bubble-dropdown.is-open .bubble-dropdown-menu {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n }\n\n .bubble-dropdown-item {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 6px 8px;\n border: none;\n background: transparent;\n color: #37352f;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n font-family: inherit;\n text-align: left;\n transition: all 0.15s;\n }\n\n .bubble-dropdown-item:hover {\n background: rgba(55, 53, 47, 0.08);\n }\n\n .bubble-dropdown-item.is-active {\n background: var(--qxs-color-primary, #3D61E3);\n color: #fff;\n }\n\n .bubble-dropdown-item svg {\n width: 16px;\n height: 16px;\n stroke: currentColor;\n stroke-width: 2;\n fill: none;\n }\n\n .image-input {\n display: none;\n }\n\n .table-grid-preview {\n display: grid;\n grid-template-columns: repeat(10, 18px);\n gap: 2px;\n padding: 8px;\n }\n\n .table-grid-preview .table-cell {\n width: 18px;\n height: 18px;\n border: 1px solid #e3e3e3;\n border-radius: 2px;\n background: #fff;\n cursor: pointer;\n transition: all 0.1s;\n }\n\n .table-grid-preview .table-cell:hover {\n background: rgba(30, 150, 252, 0.3);\n border-color: var(--qxs-color-primary, #3D61E3);\n }\n\n .table-grid-preview .table-cell.selected {\n background: rgba(30, 150, 252, 0.15);\n border-color: rgba(30, 150, 252, 0.5);\n }\n\n .table-size-hint {\n text-align: center;\n padding: 4px 8px 6px;\n font-size: 10px;\n color: #8c8c8c;\n }\n\n /* Image Toolbar */\n .image-toolbar {\n position: absolute;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 4px 6px;\n background: #fff;\n border: 1px solid #e3e3e3;\n border-radius: 6px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n z-index: 100;\n transform: translateX(-50%);\n }\n\n .image-toolbar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n color: #595959;\n transition: all 0.15s;\n }\n\n .image-toolbar-btn:hover {\n background: #f5f5f5;\n color: var(--qxs-color-primary, #3D61E3);\n }\n\n .image-toolbar-btn.danger:hover {\n background: #fff1f0;\n color: #ff4d4f;\n }\n\n .image-toolbar-btn svg {\n width: 16px;\n height: 16px;\n stroke: currentColor;\n stroke-width: 2;\n fill: none;\n }\n\n .image-toolbar-divider {\n width: 1px;\n height: 20px;\n background: #e3e3e3;\n margin: 0 4px;\n }\n\n /* Image More Menu */\n .image-more-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n padding: 4px;\n background: #fff;\n border: 1px solid #e3e3e3;\n border-radius: 6px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n z-index: 101;\n min-width: 120px;\n }\n\n .image-more-menu-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border: none;\n background: transparent;\n width: 100%;\n text-align: left;\n font-size: 13px;\n color: #595959;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .image-more-menu-item:hover {\n background: #f5f5f5;\n color: var(--qxs-color-primary, #3D61E3);\n }\n\n .image-more-menu-item svg {\n width: 14px;\n height: 14px;\n stroke: currentColor;\n stroke-width: 2;\n fill: none;\n }\n\n /* Selected Image */\n .ProseMirror img.selected {\n outline: 2px solid var(--qxs-color-primary, #3D61E3);\n outline-offset: 2px;\n }\n `\n\n @property({ type: String, attribute: 'content' })\n content = ''\n\n @property({ type: String, attribute: 'model-value' })\n modelValue = ''\n\n @property({ type: String, attribute: 'use-model' })\n useModelAttr = 'false'\n\n @property({ type: String, attribute: 'readonly' })\n readonlyAttr = 'false'\n\n @property({ type: String, attribute: 'preview' })\n previewAttr = 'false'\n\n @property({ type: String, attribute: 'custom-styles' })\n customStylesAttr = ''\n\n private _injectedStyleEl: HTMLStyleElement | null = null\n\n private _injectCustomStyles() {\n const shadow = this.shadowRoot\n if (!shadow) return\n\n if (this._injectedStyleEl) {\n this._injectedStyleEl.remove()\n this._injectedStyleEl = null\n }\n\n if (!this.customStylesAttr) return\n\n const styleEl = document.createElement('style')\n styleEl.textContent = this.customStylesAttr\n shadow.appendChild(styleEl)\n this._injectedStyleEl = styleEl\n }\n\n get useModel(): boolean {\n return this.useModelAttr === 'true' || this.useModelAttr === '' || this.hasAttribute('use-model')\n }\n\n set useModel(value: boolean) {\n this.useModelAttr = String(value)\n }\n\n get readonly(): boolean {\n return this.readonlyAttr !== 'false'\n }\n\n set readonly(value: boolean) {\n this.readonlyAttr = String(value)\n }\n\n get preview(): boolean {\n return this.previewAttr !== 'false'\n }\n\n set preview(value: boolean) {\n this.previewAttr = String(value)\n }\n\n @property({ type: Object, attribute: 'upload-image' })\n uploadImage: (file: File) => Promise<string> = async (file: File) => {\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = (e) => resolve(e.target?.result as string)\n reader.onerror = reject\n reader.readAsDataURL(file)\n })\n }\n\n @state() private _editor: Editor | null = null\n @state() private _pendingContent: string | null = null\n private _tableRows = 3\n private _tableCols = 3\n @state() private _hoverRow = 0\n @state() private _hoverCol = 0\n @state() private _tableDropdownOpen = false\n @state() private _tableCellToolbar: { x: number, y: number, visible: boolean, cellRow: number, cellCol: number } = { x: 0, y: 0, visible: false, cellRow: 0, cellCol: 0 }\n @state() private _imageToolbar: { x: number, y: number, visible: boolean } = { x: 0, y: 0, visible: false }\n @state() private _imageMoreMenuVisible = false\n private _hasSlashCommand = false\n private _isUpdating = false\n\n private _initEditor() {\n if (this._editor) return\n\n const el = this.shadowRoot?.querySelector<HTMLElement>('.editor-content')\n if (!el) {\n requestAnimationFrame(() => this._initEditor())\n return\n }\n\n while (el.firstChild) {\n el.removeChild(el.firstChild)\n }\n\n const useModel = this.useModel || this.hasAttribute('use-model')\n const modelValue = this.getAttribute('model-value') ?? this.modelValue\n const contentValue = this.content\n\n const initialContent = useModel\n ? (this._pendingContent ?? modelValue) || '<p></p>'\n : (this._pendingContent ?? contentValue) || '<p></p>'\n\n const extensions: any[] = [\n Document,\n Paragraph,\n Text,\n Bold,\n Italic,\n Underline,\n Strike,\n Code,\n Heading.extend({\n addAttributes() {\n return {\n ...this.parent?.(),\n dataType: {\n default: null,\n parseHTML: element => element.getAttribute('data-type'),\n renderHTML: attributes => {\n if (!attributes.dataType) return {}\n return { 'data-type': attributes.dataType }\n },\n },\n }\n },\n }).configure({ levels: [1, 2, 3] }),\n BulletList,\n OrderedList,\n ListItem,\n Blockquote,\n HorizontalRule,\n History,\n Image.configure({\n inline: false,\n allowBase64: true,\n }),\n Link.configure({\n openOnClick: false,\n HTMLAttributes: {\n rel: 'noopener noreferrer',\n },\n }),\n TextAlign.configure({\n types: ['heading', 'paragraph'],\n }),\n Table.configure({\n resizable: true,\n }),\n TableRow,\n TableCell,\n TableHeader,\n Placeholder.configure({\n placeholder: '输入 / 唤出快捷命令',\n }),\n Extension.create({\n name: 'clearMarksOnEnter',\n addKeyboardShortcuts() {\n return {\n Enter: () => {\n this.editor.chain().focus().unsetAllMarks().clearNodes().run()\n return false\n },\n }\n },\n }),\n ]\n\n this._editor = new Editor({\n element: el,\n extensions,\n editable: !this.readonly,\n content: initialContent,\n })\n\n this._pendingContent = null\n\n this._editor.on('selectionUpdate', () => {\n this._updateBubbleMenuPosition()\n if (this._editor?.isActive('table')) {\n this._showTableCellToolbar()\n } else {\n this._hideTableCellToolbar()\n }\n // Image selection detection\n const editor = this._editor\n if (editor) {\n const { selection } = editor.state\n const { $from } = selection\n const node = $from.node($from.depth)\n if (node.type.name === 'image') {\n const coords = editor.view.coordsAtPos($from.start())\n const wrapperRect = this.shadowRoot?.querySelector('.editor-wrapper')?.getBoundingClientRect()\n if (wrapperRect) {\n const x = coords.left - wrapperRect.left + (coords.right - coords.left) / 2\n const y = coords.top - wrapperRect.top - 40\n this._showImageToolbar({ x, y })\n }\n } else {\n this._hideImageToolbar()\n }\n }\n })\n\n this._editor.on('transaction', () => {\n if (this._editor?.isActive('table')) {\n this._showTableCellToolbar()\n } else {\n this._hideTableCellToolbar()\n }\n this._checkSlashCommand()\n this._setupTableEdgeDetection()\n })\n\n this._editor.on('update', () => {\n this._emitContentChange()\n })\n }\n\n private _tableEdgeDetectionSetup = false\n\n private _emitContentChange() {\n if (!this._editor) return\n const html = this._editor.getHTML()\n\n this.dispatchEvent(new CustomEvent('content-change', {\n detail: html,\n bubbles: true,\n composed: true,\n }))\n }\n\n private _setupTableEdgeDetection() {\n const editorContent = this.shadowRoot?.querySelector('.editor-content')\n const editorWrapper = this.shadowRoot?.querySelector('.editor-wrapper')\n if (!editorContent || this._tableEdgeDetectionSetup) return\n \n this._tableEdgeDetectionSetup = true\n \n const handleEditorClick = () => {\n this._editor?.chain().focus().run()\n }\n\n editorContent.addEventListener('click', handleEditorClick)\n editorWrapper?.addEventListener('click', handleEditorClick)\n }\n\n\n private _checkSlashCommand() {\n if (!this._editor) return\n const { selection } = this._editor.state\n const textBefore = this._editor.state.doc.textBetween(\n Math.max(0, selection.from - 10),\n selection.from,\n ' '\n )\n this._hasSlashCommand = textBefore.endsWith('/')\n }\n\n firstUpdated() {\n this._injectCustomStyles()\n this._initEditor()\n }\n\n updated(changed: Map<string, unknown>) {\n if (changed.has('customStylesAttr')) {\n this._injectCustomStyles()\n }\n\n if (this._editor) {\n if (changed.has('content') || (changed.has('modelValue') && this.useModel)) {\n const newContent = this.useModel ? this.modelValue : this.content\n if (newContent !== this._editor.getHTML()) {\n this._editor.commands.setContent(newContent || '<p></p>')\n }\n }\n if (changed.has('readonly')) {\n this._editor.setEditable(!this.readonly)\n }\n return\n }\n\n // 编辑器未初始化时,只保存待处理内容,不重复初始化\n if (changed.has('content')) {\n this._pendingContent = this.content\n }\n\n if (changed.has('modelValue') && this.useModel) {\n this._pendingContent = this.modelValue\n }\n\n // 只有在 firstUpdated 时才会初始化编辑器\n // 这里不再重复调用 _initEditor()\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this._editor?.destroy()\n this._editor = null\n }\n\n getContent(): string {\n return this._editor?.getHTML() ?? ''\n }\n\n forceUpdate(): void {\n this.requestUpdate()\n if (this._editor) {\n const newContent = this.useModel ? this.modelValue : this.content\n if (newContent !== this._editor.getHTML()) {\n this._editor.commands.setContent(newContent || '<p></p>')\n }\n }\n }\n\n\n private _applyFormat(command: () => void) {\n if (this._hasSlashCommand && this._editor) {\n const { selection } = this._editor.state\n this._editor.chain().focus().deleteRange({ from: selection.from - 1, to: selection.from }).run()\n this._hasSlashCommand = false\n }\n command()\n }\n\n private _toggleBold() {\n this._applyFormat(() => this._editor?.chain().focus().toggleBold().run())\n }\n\n private _toggleItalic() {\n this._applyFormat(() => this._editor?.chain().focus().toggleItalic().run())\n }\n\n private _toggleUnderline() {\n this._applyFormat(() => this._editor?.chain().focus().toggleUnderline().run())\n }\n\n private _toggleStrike() {\n this._applyFormat(() => this._editor?.chain().focus().toggleStrike().run())\n }\n\n private _toggleCode() {\n this._applyFormat(() => this._editor?.chain().focus().toggleCode().run())\n }\n\n private _setHeading(level: number) {\n this._applyFormat(() => this._editor?.chain().focus().toggleHeading({ level: level as 1 | 2 | 3 | 4 | 5 | 6 }).run())\n }\n\n private _setParagraph() {\n this._applyFormat(() => this._editor?.chain().focus().setParagraph().run())\n }\n\n private _toggleBulletList() {\n this._applyFormat(() => this._editor?.chain().focus().toggleBulletList().run())\n }\n\n private _toggleOrderedList() {\n this._applyFormat(() => this._editor?.chain().focus().toggleOrderedList().run())\n }\n\n private _toggleBlockquote() {\n this._applyFormat(() => this._editor?.chain().focus().toggleBlockquote().run())\n }\n\n private _setTextAlign(align: string) {\n this._applyFormat(() => this._editor?.chain().focus().setTextAlign(align as any).run())\n }\n\n private _setLink() {\n // eslint-disable-next-line no-alert\n const url = window.prompt('请输入链接地址:')\n if (url) {\n this._applyFormat(() => this._editor?.chain().focus().setLink({ href: url }).run())\n }\n }\n\n\n private _insertTable(rows?: number, cols?: number) {\n this._editor?.chain().focus().insertTable({ rows: rows ?? this._tableRows, cols: cols ?? this._tableCols, withHeaderRow: true }).run()\n }\n\n private async _handleImageUpload(e: Event) {\n const input = e.target as HTMLInputElement\n const file = input.files?.[0]\n if (file) {\n try {\n const src = await this.uploadImage(file)\n this._editor?.chain().focus().setImage({ src }).run()\n }\n catch (err) {\n console.error('图片上传失败:', err)\n }\n }\n input.value = ''\n }\n\n private _triggerImageUpload() {\n const input = this.shadowRoot?.querySelector<HTMLInputElement>('.image-input')\n input?.click()\n }\n\n private _insertTableByClick(rows: number, cols: number) {\n if (this._hasSlashCommand && this._editor) {\n const { selection } = this._editor.state\n this._editor.chain().focus().deleteRange({ from: selection.from - 1, to: selection.from }).run()\n this._hasSlashCommand = false\n }\n this._tableRows = rows\n this._tableCols = cols\n this._insertTable(rows, cols)\n }\n\n\n private _showTableCellToolbar() {\n if (!this._editor?.isActive('table')) return\n const { state } = this._editor\n const { selection } = state\n const coords = this._editor.view.coordsAtPos(selection.from)\n const editorWrapper = this.shadowRoot?.querySelector<HTMLElement>('.editor-wrapper')\n if (!editorWrapper) return\n const wrapperRect = editorWrapper.getBoundingClientRect()\n\n const cellRow = this._getTableCellRow()\n const cellCol = this._getTableCellCol()\n const isTopRow = cellRow === 0\n const isLeftCol = cellCol === 0\n\n // Only show toolbar on top row or left column\n if (!isTopRow && !isLeftCol) return\n\n requestAnimationFrame(() => {\n this._tableCellToolbar = {\n x: coords.left - wrapperRect.left,\n y: coords.bottom - wrapperRect.top + 8,\n visible: true,\n cellRow,\n cellCol,\n }\n })\n }\n\n private _getTableCellRow(): number {\n if (!this._editor) return 0\n const { selection } = this._editor.state\n const $pos = this._editor.state.doc.resolve(selection.from)\n for (let d = $pos.depth; d > 0; d--) {\n const node = $pos.node(d)\n if (node.type.name === 'tableCell') {\n return $pos.index(d - 1)\n }\n }\n return 0\n }\n\n private _getTableCellCol(): number {\n if (!this._editor) return 0\n const { selection } = this._editor.state\n const $pos = this._editor.state.doc.resolve(selection.from)\n for (let d = $pos.depth; d > 0; d--) {\n const node = $pos.node(d)\n if (node.type.name === 'tableCell') {\n return $pos.index(d)\n }\n }\n return 0\n }\n\n private _hideTableCellToolbar() {\n requestAnimationFrame(() => {\n this._tableCellToolbar = { ...this._tableCellToolbar, visible: false }\n })\n }\n\n private _addTableRowAbove() {\n this._editor?.chain().focus().addRowBefore().run()\n this._hideTableCellToolbar()\n }\n\n private _addTableRowBelow() {\n this._editor?.chain().focus().addRowAfter().run()\n this._hideTableCellToolbar()\n }\n\n private _addTableColumnLeft() {\n this._editor?.chain().focus().addColumnBefore().run()\n this._hideTableCellToolbar()\n }\n\n private _addTableColumnRight() {\n this._editor?.chain().focus().addColumnAfter().run()\n this._hideTableCellToolbar()\n }\n\n private _deleteTableRow() {\n this._editor?.chain().focus().deleteRow().run()\n this._hideTableCellToolbar()\n }\n\n private _deleteTableColumn() {\n this._editor?.chain().focus().deleteColumn().run()\n this._hideTableCellToolbar()\n }\n\n private _deleteTable() {\n this._editor?.chain().focus().deleteTable().run()\n this._hideTableCellToolbar()\n }\n\n // Image Toolbar Methods\n private _showImageToolbar(pos: { x: number, y: number }) {\n requestAnimationFrame(() => {\n this._imageToolbar = { x: pos.x, y: pos.y, visible: true }\n this._imageMoreMenuVisible = false\n })\n }\n\n private _hideImageToolbar() {\n requestAnimationFrame(() => {\n this._imageToolbar = { ...this._imageToolbar, visible: false }\n this._imageMoreMenuVisible = false\n })\n }\n\n private _toggleImageMoreMenu() {\n this._imageMoreMenuVisible = !this._imageMoreMenuVisible\n }\n\n private _deleteImage() {\n this._editor?.chain().focus().deleteNode('image').run()\n this._hideImageToolbar()\n }\n\n private _insertImageAfter() {\n this._triggerImageUpload()\n this._imageMoreMenuVisible = false\n }\n\n private _setImageAlignLeft() {\n const editor = this._editor\n if (editor) {\n const { selection } = editor.state\n const pos = selection.from\n editor.chain().focus().setNodeSelection(pos).run()\n const img = this.shadowRoot?.querySelector('.ProseMirror img.ProseMirror-selectednode') as HTMLElement\n if (img) {\n img.style.display = 'block'\n img.style.margin = '0 auto 0 0'\n }\n }\n this._imageMoreMenuVisible = false\n }\n\n private _setImageAlignCenter() {\n const editor = this._editor\n if (editor) {\n const { selection } = editor.state\n const pos = selection.from\n editor.chain().focus().setNodeSelection(pos).run()\n const img = this.shadowRoot?.querySelector('.ProseMirror img.ProseMirror-selectednode') as HTMLElement\n if (img) {\n img.style.display = 'block'\n img.style.margin = '0 auto'\n }\n }\n this._imageMoreMenuVisible = false\n }\n\n private _setImageAlignRight() {\n const editor = this._editor\n if (editor) {\n const { selection } = editor.state\n const pos = selection.from\n editor.chain().focus().setNodeSelection(pos).run()\n const img = this.shadowRoot?.querySelector('.ProseMirror img.ProseMirror-selectednode') as HTMLElement\n if (img) {\n img.style.display = 'block'\n img.style.margin = '0 0 0 auto'\n }\n }\n this._imageMoreMenuVisible = false\n }\n\n\n private _getTextLabel(): string {\n const editor = this._editor\n if (!editor) { return '正文' }\n if (editor.isActive('heading', { level: 1 })) { return '标题 1' }\n if (editor.isActive('heading', { level: 2 })) { return '标题 2' }\n if (editor.isActive('heading', { level: 3 })) { return '标题 3' }\n return '正文'\n }\n\n private _getAlignLabel(): string {\n const editor = this._editor\n if (!editor) { return '对齐' }\n if (editor.isActive({ textAlign: 'center' })) { return '居中' }\n if (editor.isActive({ textAlign: 'right' })) { return '右对齐' }\n return '左对齐'\n }\n\n private _updateBubbleMenuPosition() {\n requestAnimationFrame(() => {\n const bubbleMenu = this.shadowRoot?.querySelector<HTMLElement>('.bubble-menu')\n const proseMirror = this.shadowRoot?.querySelector<HTMLElement>('.ProseMirror')\n const editorWrapper = this.shadowRoot?.querySelector<HTMLElement>('.editor-wrapper')\n if (!bubbleMenu || !proseMirror || !editorWrapper) { return }\n\n const editor = this._editor\n const isInTable = editor?.isActive('table') ?? false\n const { selection } = editor?.state ?? { selection: null }\n\n // 如果选中了表格节点(而不只是单元格内的文字),隐藏菜单\n if (isInTable && selection && !selection.empty && editor) {\n const { from, to } = selection\n const $from = editor.state.doc.resolve(from)\n const $to = editor.state.doc.resolve(to)\n // 检查选区起点和终点之间是否有表格节点\n let hasTableInSelection = false\n for (let d = $from.depth; d >= 0; d--) {\n if ($from.node(d).type.name === 'table') {\n hasTableInSelection = true\n break\n }\n }\n // 如果选区起点在表格外但终点在表格内,或者选区跨越了表格\n const fromAncestor = $from.node($from.depth)\n const toAncestor = $to.node($to.depth)\n if (fromAncestor.type.name === 'table' || toAncestor.type.name === 'table') {\n hasTableInSelection = true\n }\n if (hasTableInSelection) {\n bubbleMenu.style.opacity = '0'\n bubbleMenu.style.visibility = 'hidden'\n return\n }\n }\n\n // 如果有选中文字,显示菜单\n if (selection && !selection.empty) {\n // continue to show menu\n } else if (!selection || (selection.empty && !this._hasSlashCommand)) {\n bubbleMenu.style.opacity = '0'\n bubbleMenu.style.visibility = 'hidden'\n return\n }\n\n const wrapperRect = editorWrapper.getBoundingClientRect()\n const menuRect = bubbleMenu.getBoundingClientRect()\n\n const { from } = selection!\n const coords = this._editor?.view.coordsAtPos(from)\n if (!coords) { return }\n\n let left = coords.left - wrapperRect.left\n let top = coords.top - wrapperRect.top - 40\n\n if (left + menuRect.width > wrapperRect.width) {\n left = wrapperRect.width - menuRect.width - 8\n }\n if (left < 0) {\n left = 8\n }\n\n if (top < 0) {\n top = coords.bottom - wrapperRect.top + 8\n }\n\n bubbleMenu.style.left = `${left}px`\n bubbleMenu.style.top = `${top}px`\n bubbleMenu.style.opacity = '1'\n bubbleMenu.style.visibility = 'visible'\n })\n }\n\n render() {\n const editor = this._editor\n\n return html`\n <div class=\"editor-wrapper ${!editor ? 'loading' : ''} ${this.preview ? 'preview' : ''}\">\n ${!editor ? html`\n <div class=\"loading-placeholder\">\n <div class=\"loading-spinner\"></div>\n <span>编辑器加载中...</span>\n </div>\n ` : ''}\n <input\n type=\"file\"\n accept=\"image/*\"\n class=\"image-input\"\n @change=${this._handleImageUpload}\n />\n\n <!-- Bubble Menu (悬浮操作栏) -->\n ${!this.preview ? html`\n <div class=\"bubble-menu\">\n <!-- 文本格式 -->\n <button\n class=\"bubble-btn ${editor?.isActive('bold') ? 'is-active' : ''}\"\n @click=${this._toggleBold}\n title=\"加粗\"\n >\n <svg viewBox=\"0 0 24 24\"><path d=\"M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\"/><path d=\"M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\"/></svg>\n </button>\n <button\n class=\"bubble-btn ${editor?.isActive('italic') ? 'is-active' : ''}\"\n @click=${this._toggleItalic}\n title=\"斜体\"\n >\n <svg viewBox=\"0 0 24 24\"><line x1=\"19\" y1=\"4\" x2=\"10\" y2=\"4\"/><line x1=\"14\" y1=\"20\" x2=\"5\" y2=\"20\"/><line x1=\"15\" y1=\"4\" x2=\"9\" y2=\"20\"/></svg>\n </button>\n <button\n class=\"bubble-btn ${editor?.isActive('underline') ? 'is-active' : ''}\"\n @click=${this._toggleUnderline}\n title=\"下划线\"\n >\n <svg viewBox=\"0 0 24 24\"><path d=\"M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3\"/><line x1=\"4\" y1=\"21\" x2=\"20\" y2=\"21\"/></svg>\n </button>\n <button\n class=\"bubble-btn ${editor?.isActive('strike') ? 'is-active' : ''}\"\n @click=${this._toggleStrike}\n title=\"删除线\"\n >\n <svg viewBox=\"0 0 24 24\"><path d=\"M17.3 4.9c-2.3-.6-4.4-1-6.2-.9-2.7 0-5.3.7-5.3 3.6 0 1.5 1.8 3.3 5.3 3.9h.2m8.2 3.2c.3.4.4.8.4 1.3 0 2.9-2.7 3.6-6.2 3.6-2.3 0-4.4-.3-6.2-.9M4 12h16\"/></svg>\n </button>\n\n <div class=\"bubble-divider\"></div>\n\n <!-- 文本类型下拉 -->\n <div class=\"bubble-dropdown\">\n <button class=\"bubble-dropdown-btn\">\n ${this._getTextLabel()}\n <svg viewBox=\"0 0 24 24\"><polyline points=\"6 9 12 15 18 9\"/></svg>\n </button>\n <div class=\"bubble-dropdown-menu\">\n <button\n class=\"bubble-dropdown-item ${!editor?.isActive('heading') ? 'is-active' : ''}\"\n @click=${this._setParagraph}\n >\n 正文\n </button>\n <button\n class=\"bubble-dropdown-item ${editor?.isActive('heading', { level: 1 }) ? 'is-active' : ''}\"\n @click=${() => this._setHeading(1)}\n >\n 标题 1\n </button>\n <button\n class=\"bubble-dropdown-item ${editor?.isActive('heading', { level: 2 }) ? 'is-active' : ''}\"\n @click=${() => this._setHeading(2)}\n >\n 标题 2\n </button>\n <button\n class=\"bubble-dropdown-item ${editor?.isActive('heading', { level: 3 }) ? 'is-active' : ''}\"\n @click=${() => this._setHeading(3)}\n >\n 标题 3\n </button>\n </div>\n </div>\n\n <div class=\"bubble-divider\"></div>\n\n <!-- 对齐下拉 -->\n <div class=\"bubble-dropdown\">\n <button class=\"bubble-dropdown-btn\">\n ${this._getAlignLabel()}\n <svg viewBox=\"0 0 24 24\"><polyline points=\"6 9 12 15 18 9\"/></svg>\n </button>\n <div class=\"bubble-dropdown-menu\">\n <button\n class=\"bubble-dropdown-item ${editor?.isActive({ textAlign: 'left' }) ? 'is-active' : ''}\"\n @click=${() => this._setTextAlign('left')}\n >\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"3\" y1=\"12\" x2=\"15\" y2=\"12\"/><line x1=\"3\" y1=\"18\" x2=\"18\" y2=\"18\"/></svg>\n 左对齐\n </button>\n <button\n class=\"bubble-dropdown-item ${editor?.isActive({ textAlign: 'center' }) ? 'is-active' : ''}\"\n @click=${() => this._setTextAlign('center')}\n >\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"6\" y1=\"12\" x2=\"18\" y2=\"12\"/><line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"/></svg>\n 居中\n </button>\n <button\n class=\"bubble-dropdown-item ${editor?.isActive({ textAlign: 'right' }) ? 'is-active' : ''}\"\n @click=${() => this._setTextAlign('right')}\n >\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"9\" y1=\"12\" x2=\"21\" y2=\"12\"/><line x1=\"6\" y1=\"18\" x2=\"21\" y2=\"18\"/></svg>\n 右对齐\n </button>\n </div>\n </div>\n\n <div class=\"bubble-divider\"></div>\n\n <!-- 行内代码 -->\n <button\n class=\"bubble-btn ${editor?.isActive('code') ? 'is-active' : ''}\"\n @click=${this._toggleCode}\n title=\"行内代码\"\n >\n <svg viewBox=\"0 0 24 24\"><polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/></svg>\n </button>\n\n <!-- 链接 -->\n <button\n class=\"bubble-btn ${editor?.isActive('link') ? 'is-active' : ''}\"\n @click=${this._setLink}\n title=\"链接\"\n >\n <svg viewBox=\"0 0 24 24\"><path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/></svg>\n </button>\n\n <!-- 图片 -->\n <button\n class=\"bubble-btn\"\n @click=${this._triggerImageUpload}\n title=\"图片\"\n >\n <svg viewBox=\"0 0 24 24\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/></svg>\n </button>\n\n <div class=\"bubble-divider\"></div>\n\n <!-- 列表 -->\n <button\n class=\"bubble-btn ${editor?.isActive('bulletList') ? 'is-active' : ''}\"\n @click=${this._toggleBulletList}\n title=\"无序列表\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"9\" y1=\"6\" x2=\"20\" y2=\"6\"/>\n <line x1=\"9\" y1=\"12\" x2=\"20\" y2=\"12\"/>\n <line x1=\"9\" y1=\"18\" x2=\"20\" y2=\"18\"/>\n <circle cx=\"4\" cy=\"6\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\"/>\n <circle cx=\"4\" cy=\"12\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\"/>\n <circle cx=\"4\" cy=\"18\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\"/>\n </svg>\n </button>\n <button\n class=\"bubble-btn ${editor?.isActive('orderedList') ? 'is-active' : ''}\"\n @click=${this._toggleOrderedList}\n title=\"有序列表\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"10\" y1=\"6\" x2=\"21\" y2=\"6\"/>\n <line x1=\"10\" y1=\"12\" x2=\"21\" y2=\"12\"/>\n <line x1=\"10\" y1=\"18\" x2=\"21\" y2=\"18\"/>\n <path d=\"M4 6h1v4\"/>\n <path d=\"M4 10h2\"/>\n <path d=\"M6 18H4c0-1 2-2 2-3s-1-1.5-2-1.5\"/>\n </svg>\n </button>\n\n <!-- 引用 -->\n <button\n class=\"bubble-btn ${editor?.isActive('blockquote') ? 'is-active' : ''}\"\n @click=${this._toggleBlockquote}\n title=\"引用\"\n >\n <svg viewBox=\"0 0 24 24\"><path d=\"M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V21z\"/><path d=\"M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z\"/></svg>\n </button>\n\n <div class=\"bubble-divider\"></div>\n\n <!-- 表格下拉 -->\n <div\n class=\"bubble-dropdown ${this._tableDropdownOpen ? 'is-open' : ''}\"\n @mouseenter=${() => {\n this._tableDropdownOpen = true\n this._hoverRow = 0\n this._hoverCol = 0\n }}\n @mouseleave=${() => this._tableDropdownOpen = false}\n >\n <button class=\"bubble-dropdown-btn\" title=\"表格\">\n <svg viewBox=\"0 0 24 24\" style=\"width:18px;height:18px;stroke:currentColor;stroke-width:2;fill:none;\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/><line x1=\"3\" y1=\"15\" x2=\"21\" y2=\"15\"/><line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"21\"/><line x1=\"15\" y1=\"3\" x2=\"15\" y2=\"21\"/></svg>\n </button>\n <div class=\"bubble-dropdown-menu\">\n <div class=\"table-grid-preview\">\n ${this._renderTableGrid()}\n </div>\n <div class=\"table-size-hint\">\n <span>${this._hoverRow > 0 ? `${this._hoverRow} × ${this._hoverCol}` : `${this._tableRows} × ${this._tableCols}`}</span>\n </div>\n </div>\n </div>\n </div>\n ` : ''}\n\n <div class=\"editor-content\"></div>\n\n <!-- Table Cell Toolbar -->\n ${this._tableCellToolbar.visible && editor?.isActive('table')\n ? html`\n <div\n class=\"table-cell-toolbar\"\n style=\"left: ${this._tableCellToolbar.x}px; top: ${this._tableCellToolbar.y}px;\"\n @mousedown=${(e: Event) => e.preventDefault()}\n >\n ${this._tableCellToolbar.cellRow === 0 ? html`\n <button class=\"table-cell-toolbar-btn\" title=\"上方添加行\" @click=${this._addTableRowAbove}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"4\" y=\"8\" width=\"16\" height=\"8\" rx=\"1\"/><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"7\"/><line x1=\"10\" y1=\"5\" x2=\"14\" y2=\"5\"/></svg>\n </button>\n <button class=\"table-cell-toolbar-btn\" title=\"下方添加行\" @click=${this._addTableRowBelow}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"4\" y=\"8\" width=\"16\" height=\"8\" rx=\"1\"/><line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"17\"/><line x1=\"10\" y1=\"19\" x2=\"14\" y2=\"19\"/></svg>\n </button>\n <button class=\"table-cell-toolbar-btn danger\" title=\"删除行\" @click=${this._deleteTableRow}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"4\" y=\"8\" width=\"16\" height=\"8\" rx=\"1\"/><line x1=\"9\" y1=\"10\" x2=\"9\" y2=\"14\"/><line x1=\"15\" y1=\"10\" x2=\"15\" y2=\"14\"/></svg>\n </button>\n ` : ''}\n ${this._tableCellToolbar.cellCol === 0 ? html`\n ${this._tableCellToolbar.cellRow !== 0 ? html`<div style=\"width:1px;height:20px;background:#e3e3e3;margin:0 4px;\"></div>` : ''}\n <button class=\"table-cell-toolbar-btn\" title=\"左侧添加列\" @click=${this._addTableColumnLeft}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"8\" y=\"4\" width=\"8\" height=\"16\" rx=\"1\"/><line x1=\"3\" y1=\"12\" x2=\"7\" y2=\"12\"/><line x1=\"5\" y1=\"10\" x2=\"5\" y2=\"14\"/></svg>\n </button>\n <button class=\"table-cell-toolbar-btn\" title=\"右侧添加列\" @click=${this._addTableColumnRight}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"8\" y=\"4\" width=\"8\" height=\"16\" rx=\"1\"/><line x1=\"21\" y1=\"12\" x2=\"17\" y2=\"12\"/><line x1=\"19\" y1=\"10\" x2=\"19\" y2=\"14\"/></svg>\n </button>\n <button class=\"table-cell-toolbar-btn danger\" title=\"删除列\" @click=${this._deleteTableColumn}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><rect x=\"8\" y=\"4\" width=\"8\" height=\"16\" rx=\"1\"/><line x1=\"10\" y1=\"9\" x2=\"14\" y2=\"9\"/><line x1=\"10\" y1=\"15\" x2=\"14\" y2=\"15\"/></svg>\n </button>\n ` : ''}\n ${this._tableCellToolbar.cellRow === 0 && this._tableCellToolbar.cellCol === 0 ? html`\n <div style=\"width:1px;height:20px;background:#e3e3e3;margin:0 4px;\"></div>\n <button class=\"table-cell-toolbar-btn danger\" title=\"删除表格\" @click=${this._deleteTable}>\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>\n </button>\n ` : ''}\n </div>\n `\n : ''}\n\n <!-- Image Toolbar -->\n ${this._imageToolbar.visible\n ? html`\n <div\n class=\"image-toolbar\"\n style=\"left: ${this._imageToolbar.x}px; top: ${this._imageToolbar.y}px;\"\n @mousedown=${(e: Event) => e.preventDefault()}\n >\n <button class=\"image-toolbar-btn danger\" title=\"删除图片\" @click=${this._deleteImage}>\n <svg viewBox=\"0 0 24 24\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>\n </button>\n <button class=\"image-toolbar-btn\" title=\"添加图片\" @click=${this._insertImageAfter}>\n <svg viewBox=\"0 0 24 24\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>\n </button>\n <div class=\"image-toolbar-divider\"></div>\n <div style=\"position: relative;\">\n <button class=\"image-toolbar-btn\" title=\"更多\" @click=${this._toggleImageMoreMenu}>\n <svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"1\"/><circle cx=\"19\" cy=\"12\" r=\"1\"/><circle cx=\"5\" cy=\"12\" r=\"1\"/></svg>\n </button>\n ${this._imageMoreMenuVisible\n ? html`\n <div class=\"image-more-menu\">\n <button class=\"image-more-menu-item\" @click=${this._setImageAlignLeft}>\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"3\" y1=\"12\" x2=\"15\" y2=\"12\"/><line x1=\"3\" y1=\"18\" x2=\"18\" y2=\"18\"/></svg>\n 左对齐\n </button>\n <button class=\"image-more-menu-item\" @click=${this._setImageAlignCenter}>\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"6\" y1=\"12\" x2=\"18\" y2=\"12\"/><line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"/></svg>\n 居中\n </button>\n <button class=\"image-more-menu-item\" @click=${this._setImageAlignRight}>\n <svg viewBox=\"0 0 24 24\"><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"9\" y1=\"12\" x2=\"21\" y2=\"12\"/><line x1=\"6\" y1=\"18\" x2=\"21\" y2=\"18\"/></svg>\n 右对齐\n </button>\n </div>\n `\n : ''}\n </div>\n </div>\n `\n : ''}\n </div>\n `\n }\n\n private _renderTableGrid() {\n const cells = []\n for (let i = 0; i < 100; i++) {\n const row = Math.floor(i / 10) + 1\n const col = (i % 10) + 1\n const isHighlight = this._hoverRow > 0 && row <= this._hoverRow && col <= this._hoverCol\n cells.push(html`\n <div\n class=\"table-cell ${isHighlight ? 'selected' : ''}\"\n @click=${() => {\n this._insertTableByClick(row, col)\n this._tableDropdownOpen = false\n }}\n @mouseenter=${() => {\n this._hoverRow = row\n this._hoverCol = col\n }}\n @mouseleave=${() => {\n this._hoverRow = 0\n this._hoverCol = 0\n }}\n ></div>\n `)\n }\n return cells\n }\n}\n\nexport function register() {}\n"],"names":["QxsBlocksuiteEditor","LitElement","constructor","super","arguments","this","content","modelValue","useModelAttr","readonlyAttr","previewAttr","customStylesAttr","_injectedStyleEl","uploadImage","async","Promise","resolve","reject","reader","FileReader","onload","e","target","result","onerror","readAsDataURL","file","_editor","_pendingContent","_tableRows","_tableCols","_hoverRow","_hoverCol","_tableDropdownOpen","_tableCellToolbar","x","y","visible","cellRow","cellCol","_imageToolbar","_imageMoreMenuVisible","_hasSlashCommand","_isUpdating","_tableEdgeDetectionSetup","_injectCustomStyles","shadow","shadowRoot","remove","styleEl","document","createElement","textContent","appendChild","useModel","hasAttribute","value","String","readonly","preview","_initEditor","el","querySelector","requestAnimationFrame","firstChild","removeChild","getAttribute","contentValue","initialContent","extensions","Document","Paragraph","Text","Bold","Italic","Underline","Strike","Code","Heading","extend","addAttributes","parent","dataType","default","parseHTML","element","renderHTML","attributes","configure","levels","BulletList","OrderedList","ListItem","Blockquote","HorizontalRule","History","Image","inline","allowBase64","Link","openOnClick","HTMLAttributes","rel","TextAlign","types","Table","resizable","TableRow","TableCell","TableHeader","Placeholder","placeholder","Extension","create","name","addKeyboardShortcuts","Enter","editor","chain","focus","unsetAllMarks","clearNodes","run","Editor","editable","on","_updateBubbleMenuPosition","isActive","_showTableCellToolbar","_hideTableCellToolbar","selection","state","$from","node","depth","type","coords","view","coordsAtPos","start","wrapperRect","getBoundingClientRect","left","right","top","_showImageToolbar","_hideImageToolbar","_checkSlashCommand","_setupTableEdgeDetection","_emitContentChange","html","getHTML","dispatchEvent","CustomEvent","detail","bubbles","composed","editorContent","editorWrapper","handleEditorClick","addEventListener","textBefore","doc","textBetween","Math","max","from","endsWith","firstUpdated","updated","changed","has","newContent","commands","setContent","setEditable","disconnectedCallback","destroy","getContent","forceUpdate","requestUpdate","_applyFormat","command","deleteRange","to","_toggleBold","toggleBold","_toggleItalic","toggleItalic","_toggleUnderline","toggleUnderline","_toggleStrike","toggleStrike","_toggleCode","toggleCode","_setHeading","level","toggleHeading","_setParagraph","setParagraph","_toggleBulletList","toggleBulletList","_toggleOrderedList","toggleOrderedList","_toggleBlockquote","toggleBlockquote","_setTextAlign","align","setTextAlign","_setLink","url","window","prompt","setLink","href","_insertTable","rows","cols","insertTable","withHeaderRow","_handleImageUpload","input","files","src","setImage","err","_triggerImageUpload","click","_insertTableByClick","_getTableCellRow","_getTableCellCol","bottom","$pos","d","index","_addTableRowAbove","addRowBefore","_addTableRowBelow","addRowAfter","_addTableColumnLeft","addColumnBefore","_addTableColumnRight","addColumnAfter","_deleteTableRow","deleteRow","_deleteTableColumn","deleteColumn","_deleteTable","deleteTable","pos","_toggleImageMoreMenu","_deleteImage","deleteNode","_insertImageAfter","_setImageAlignLeft","setNodeSelection","img","style","display","margin","_setImageAlignCenter","_setImageAlignRight","_getTextLabel","_getAlignLabel","textAlign","bubbleMenu","proseMirror","isInTable","empty","$to","hasTableInSelection","fromAncestor","toAncestor","opacity","visibility","menuRect","width","render","_renderTableGrid","preventDefault","cells","i","row","floor","col","isHighlight","push","styles","css","__decorateClass","property","attribute","prototype","Object","safeCustomElement"],"mappings":"o6CA8BaA,QAAAA,oBAAN,cAAkCC,EAAAA,WAAlCC,WAAAA,GAAAC,SAAAC,WAslBLC,KAAAC,QAAU,GAGVD,KAAAE,WAAa,GAGbF,KAAAG,aAAe,QAGfH,KAAAI,aAAe,QAGfJ,KAAAK,YAAc,QAGdL,KAAAM,iBAAmB,GAEnBN,KAAQO,iBAA4C,KA4CpDP,KAAAQ,YAA+CC,SACtC,IAAIC,QAAQ,CAACC,EAASC,KAC3B,MAAMC,EAAS,IAAIC,WACnBD,EAAOE,OAAUC,GAAML,EAAQK,EAAEC,QAAQC,QACzCL,EAAOM,QAAUP,EACjBC,EAAOO,cAAcC,KAIhBrB,KAAQsB,QAAyB,KACjCtB,KAAQuB,gBAAiC,KAClDvB,KAAQwB,WAAa,EACrBxB,KAAQyB,WAAa,EACZzB,KAAQ0B,UAAY,EACpB1B,KAAQ2B,UAAY,EACpB3B,KAAQ4B,oBAAqB,EAC7B5B,KAAQ6B,kBAAkG,CAAEC,EAAG,EAAGC,EAAG,EAAGC,SAAS,EAAOC,QAAS,EAAGC,QAAS,GAC7JlC,KAAQmC,cAA4D,CAAEL,EAAG,EAAGC,EAAG,EAAGC,SAAS,GAC3FhC,KAAQoC,uBAAwB,EACzCpC,KAAQqC,kBAAmB,EAC3BrC,KAAQsC,aAAc,EA2ItBtC,KAAQuC,0BAA2B,CAAA,CAzM3BC,mBAAAA,GACN,MAAMC,EAASzC,KAAK0C,WACpB,IAAKD,EAAQ,OAOb,GALIzC,KAAKO,mBACPP,KAAKO,iBAAiBoC,SACtB3C,KAAKO,iBAAmB,OAGrBP,KAAKM,iBAAkB,OAE5B,MAAMsC,EAAUC,SAASC,cAAc,SACvCF,EAAQG,YAAc/C,KAAKM,iBAC3BmC,EAAOO,YAAYJ,GACnB5C,KAAKO,iBAAmBqC,CAC1B,CAEA,YAAIK,GACF,MAA6B,SAAtBjD,KAAKG,cAAiD,KAAtBH,KAAKG,cAAuBH,KAAKkD,aAAa,YACvF,CAEA,YAAID,CAASE,GACXnD,KAAKG,aAAeiD,OAAOD,EAC7B,CAEA,YAAIE,GACF,MAA6B,UAAtBrD,KAAKI,YACd,CAEA,YAAIiD,CAASF,GACXnD,KAAKI,aAAegD,OAAOD,EAC7B,CAEA,WAAIG,GACF,MAA4B,UAArBtD,KAAKK,WACd,CAEA,WAAIiD,CAAQH,GACVnD,KAAKK,YAAc+C,OAAOD,EAC5B,CAyBQI,WAAAA,GACN,GAAIvD,KAAKsB,QAAS,OAElB,MAAMkC,EAAKxD,KAAK0C,YAAYe,cAA2B,mBACvD,IAAKD,EAEH,YADAE,sBAAsB,IAAM1D,KAAKuD,eAInC,KAAOC,EAAGG,YACRH,EAAGI,YAAYJ,EAAGG,YAGpB,MAAMV,EAAWjD,KAAKiD,UAAYjD,KAAKkD,aAAa,aAC9ChD,EAAaF,KAAK6D,aAAa,gBAAkB7D,KAAKE,WACtD4D,EAAe9D,KAAKC,QAEpB8D,EAAiBd,GAClBjD,KAAKuB,iBAAmBrB,IAAe,WACvCF,KAAKuB,iBAAmBuC,IAAiB,UAExCE,EAAoB,CACxBC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAAQC,OAAO,CACbC,aAAAA,GACE,MAAO,IACF3E,KAAK4E,WACRC,SAAU,CACRC,QAAS,KACTC,UAAWC,GAAWA,EAAQnB,aAAa,aAC3CoB,WAAYC,GACLA,EAAWL,SACT,CAAE,YAAaK,EAAWL,UADA,CAAA,GAKzC,IACCM,UAAU,CAAEC,OAAQ,CAAC,EAAG,EAAG,KAC9BC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAAMR,UAAU,CACdS,QAAQ,EACRC,aAAa,IAEfC,EAAKX,UAAU,CACbY,aAAa,EACbC,eAAgB,CACdC,IAAK,yBAGTC,EAAUf,UAAU,CAClBgB,MAAO,CAAC,UAAW,eAErBC,EAAAA,MAAMjB,UAAU,CACdkB,WAAW,IAEbC,EAAAA,SACAC,EAAAA,UACAC,EAAAA,YACAC,EAAYtB,UAAU,CACpBuB,YAAa,gBAEfC,EAAAA,UAAUC,OAAO,CACfC,KAAM,oBACNC,oBAAAA,GACE,MAAO,CACLC,MAAOA,KACL/G,KAAKgH,OAAOC,QAAQC,QAAQC,gBAAgBC,aAAaC,OAClD,GAGb,KAIJrH,KAAKsB,QAAU,IAAIgG,SAAO,CACxBtC,QAASxB,EACTQ,aACAuD,UAAWvH,KAAKqD,SAChBpD,QAAS8D,IAGX/D,KAAKuB,gBAAkB,KAEvBvB,KAAKsB,QAAQkG,GAAG,kBAAmB,KACjCxH,KAAKyH,4BACDzH,KAAKsB,SAASoG,SAAS,SACzB1H,KAAK2H,wBAEL3H,KAAK4H,wBAGP,MAAMZ,EAAShH,KAAKsB,QACpB,GAAI0F,EAAQ,CACV,MAAMa,UAAEA,GAAcb,EAAOc,OACvBC,MAAEA,GAAUF,EAElB,GAAuB,UADVE,EAAMC,KAAKD,EAAME,OACrBC,KAAKrB,KAAkB,CAC9B,MAAMsB,EAASnB,EAAOoB,KAAKC,YAAYN,EAAMO,SACvCC,EAAcvI,KAAK0C,YAAYe,cAAc,oBAAoB+E,wBACvE,GAAID,EAAa,CACf,MAAMzG,EAAIqG,EAAOM,KAAOF,EAAYE,MAAQN,EAAOO,MAAQP,EAAOM,MAAQ,EACpE1G,EAAIoG,EAAOQ,IAAMJ,EAAYI,IAAM,GACzC3I,KAAK4I,kBAAkB,CAAE9G,IAAGC,KAC9B,CACF,MACE/B,KAAK6I,mBAET,IAGF7I,KAAKsB,QAAQkG,GAAG,cAAe,KACzBxH,KAAKsB,SAASoG,SAAS,SACzB1H,KAAK2H,wBAEL3H,KAAK4H,wBAEP5H,KAAK8I,qBACL9I,KAAK+I,6BAGP/I,KAAKsB,QAAQkG,GAAG,SAAU,KACxBxH,KAAKgJ,sBAET,CAIQA,kBAAAA,GACN,IAAKhJ,KAAKsB,QAAS,OACnB,MAAM2H,EAAOjJ,KAAKsB,QAAQ4H,UAE1BlJ,KAAKmJ,cAAc,IAAIC,YAAY,iBAAkB,CACnDC,OAAQJ,EACRK,SAAS,EACTC,UAAU,IAEd,CAEQR,wBAAAA,GACN,MAAMS,EAAgBxJ,KAAK0C,YAAYe,cAAc,mBAC/CgG,EAAgBzJ,KAAK0C,YAAYe,cAAc,mBACrD,IAAK+F,GAAiBxJ,KAAKuC,yBAA0B,OAErDvC,KAAKuC,0BAA2B,EAEhC,MAAMmH,EAAoBA,KACxB1J,KAAKsB,SAAS2F,QAAQC,QAAQG,OAGhCmC,EAAcG,iBAAiB,QAASD,GACxCD,GAAeE,iBAAiB,QAASD,EAC3C,CAGQZ,kBAAAA,GACN,IAAK9I,KAAKsB,QAAS,OACnB,MAAMuG,UAAEA,GAAc7H,KAAKsB,QAAQwG,MAC7B8B,EAAa5J,KAAKsB,QAAQwG,MAAM+B,IAAIC,YACxCC,KAAKC,IAAI,EAAGnC,EAAUoC,KAAO,IAC7BpC,EAAUoC,KACV,KAEFjK,KAAKqC,iBAAmBuH,EAAWM,SAAS,IAC9C,CAEAC,YAAAA,GACEnK,KAAKwC,sBACLxC,KAAKuD,aACP,CAEA6G,OAAAA,CAAQC,GAKN,GAJIA,EAAQC,IAAI,qBACdtK,KAAKwC,sBAGHxC,KAAKsB,QAAT,CACE,GAAI+I,EAAQC,IAAI,YAAeD,EAAQC,IAAI,eAAiBtK,KAAKiD,SAAW,CAC1E,MAAMsH,EAAavK,KAAKiD,SAAWjD,KAAKE,WAAaF,KAAKC,QACtDsK,IAAevK,KAAKsB,QAAQ4H,WAC9BlJ,KAAKsB,QAAQkJ,SAASC,WAAWF,GAAc,UAEnD,CACIF,EAAQC,IAAI,aACdtK,KAAKsB,QAAQoJ,aAAa1K,KAAKqD,SAGnC,MAGIgH,EAAQC,IAAI,aACdtK,KAAKuB,gBAAkBvB,KAAKC,SAG1BoK,EAAQC,IAAI,eAAiBtK,KAAKiD,WACpCjD,KAAKuB,gBAAkBvB,KAAKE,WAKhC,CAEAyK,oBAAAA,GACE7K,MAAM6K,uBACN3K,KAAKsB,SAASsJ,UACd5K,KAAKsB,QAAU,IACjB,CAEAuJ,UAAAA,GACE,OAAO7K,KAAKsB,SAAS4H,WAAa,EACpC,CAEA4B,WAAAA,GAEE,GADA9K,KAAK+K,gBACD/K,KAAKsB,QAAS,CAChB,MAAMiJ,EAAavK,KAAKiD,SAAWjD,KAAKE,WAAaF,KAAKC,QACtDsK,IAAevK,KAAKsB,QAAQ4H,WAC9BlJ,KAAKsB,QAAQkJ,SAASC,WAAWF,GAAc,UAEnD,CACF,CAGQS,YAAAA,CAAaC,GACnB,GAAIjL,KAAKqC,kBAAoBrC,KAAKsB,QAAS,CACzC,MAAMuG,UAAEA,GAAc7H,KAAKsB,QAAQwG,MACnC9H,KAAKsB,QAAQ2F,QAAQC,QAAQgE,YAAY,CAAEjB,KAAMpC,EAAUoC,KAAO,EAAGkB,GAAItD,EAAUoC,OAAQ5C,MAC3FrH,KAAKqC,kBAAmB,CAC1B,CACA4I,GACF,CAEQG,WAAAA,GACNpL,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQmE,aAAahE,MACrE,CAEQiE,aAAAA,GACNtL,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQqE,eAAelE,MACvE,CAEQmE,gBAAAA,GACNxL,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQuE,kBAAkBpE,MAC1E,CAEQqE,aAAAA,GACN1L,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQyE,eAAetE,MACvE,CAEQuE,WAAAA,GACN5L,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQ2E,aAAaxE,MACrE,CAEQyE,WAAAA,CAAYC,GAClB/L,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQ8E,cAAc,CAAED,UAAyC1E,MACjH,CAEQ4E,aAAAA,GACNjM,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQgF,eAAe7E,MACvE,CAEQ8E,iBAAAA,GACNnM,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQkF,mBAAmB/E,MAC3E,CAEQgF,kBAAAA,GACNrM,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQoF,oBAAoBjF,MAC5E,CAEQkF,iBAAAA,GACNvM,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQsF,mBAAmBnF,MAC3E,CAEQoF,aAAAA,CAAcC,GACpB1M,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQyF,aAAaD,GAAcrF,MACnF,CAEQuF,QAAAA,GAEN,MAAMC,EAAMC,OAAOC,OAAO,YACtBF,GACF7M,KAAKgL,aAAa,IAAMhL,KAAKsB,SAAS2F,QAAQC,QAAQ8F,QAAQ,CAAEC,KAAMJ,IAAOxF,MAEjF,CAGQ6F,YAAAA,CAAaC,EAAeC,GAClCpN,KAAKsB,SAAS2F,QAAQC,QAAQmG,YAAY,CAAEF,KAAMA,GAAQnN,KAAKwB,WAAY4L,KAAMA,GAAQpN,KAAKyB,WAAY6L,eAAe,IAAQjG,KACnI,CAEA,wBAAckG,CAAmBvM,GAC/B,MAAMwM,EAAQxM,EAAEC,OACVI,EAAOmM,EAAMC,QAAQ,GAC3B,GAAIpM,EACF,IACE,MAAMqM,QAAY1N,KAAKQ,YAAYa,GACnCrB,KAAKsB,SAAS2F,QAAQC,QAAQyG,SAAS,CAAED,QAAOrG,KAClD,OACOuG,GAEP,CAEFJ,EAAMrK,MAAQ,EAChB,CAEQ0K,mBAAAA,GACN,MAAML,EAAQxN,KAAK0C,YAAYe,cAAgC,gBAC/D+J,GAAOM,OACT,CAEQC,mBAAAA,CAAoBZ,EAAcC,GACxC,GAAIpN,KAAKqC,kBAAoBrC,KAAKsB,QAAS,CACzC,MAAMuG,UAAEA,GAAc7H,KAAKsB,QAAQwG,MACnC9H,KAAKsB,QAAQ2F,QAAQC,QAAQgE,YAAY,CAAEjB,KAAMpC,EAAUoC,KAAO,EAAGkB,GAAItD,EAAUoC,OAAQ5C,MAC3FrH,KAAKqC,kBAAmB,CAC1B,CACArC,KAAKwB,WAAa2L,EAClBnN,KAAKyB,WAAa2L,EAClBpN,KAAKkN,aAAaC,EAAMC,EAC1B,CAGQzF,qBAAAA,GACN,IAAK3H,KAAKsB,SAASoG,SAAS,SAAU,OACtC,MAAQI,MAAAA,GAAU9H,KAAKsB,SACjBuG,UAAEA,GAAcC,EAChBK,EAASnI,KAAKsB,QAAQ8G,KAAKC,YAAYR,EAAUoC,MACjDR,EAAgBzJ,KAAK0C,YAAYe,cAA2B,mBAClE,IAAKgG,EAAe,OACpB,MAAMlB,EAAckB,EAAcjB,wBAE5BvG,EAAUjC,KAAKgO,mBACf9L,EAAUlC,KAAKiO,oBACQ,IAAZhM,GACa,IAAZC,IAKlBwB,sBAAsB,KACpB1D,KAAK6B,kBAAoB,CACvBC,EAAGqG,EAAOM,KAAOF,EAAYE,KAC7B1G,EAAGoG,EAAO+F,OAAS3F,EAAYI,IAAM,EACrC3G,SAAS,EACTC,UACAC,YAGN,CAEQ8L,gBAAAA,GACN,IAAKhO,KAAKsB,QAAS,OAAO,EAC1B,MAAMuG,UAAEA,GAAc7H,KAAKsB,QAAQwG,MAC7BqG,EAAOnO,KAAKsB,QAAQwG,MAAM+B,IAAIlJ,QAAQkH,EAAUoC,MACtD,IAAA,IAASmE,EAAID,EAAKlG,MAAOmG,EAAI,EAAGA,IAAK,CAEnC,GAAuB,cADVD,EAAKnG,KAAKoG,GACdlG,KAAKrB,KACZ,OAAOsH,EAAKE,MAAMD,EAAI,EAE1B,CACA,OAAO,CACT,CAEQH,gBAAAA,GACN,IAAKjO,KAAKsB,QAAS,OAAO,EAC1B,MAAMuG,UAAEA,GAAc7H,KAAKsB,QAAQwG,MAC7BqG,EAAOnO,KAAKsB,QAAQwG,MAAM+B,IAAIlJ,QAAQkH,EAAUoC,MACtD,IAAA,IAASmE,EAAID,EAAKlG,MAAOmG,EAAI,EAAGA,IAAK,CAEnC,GAAuB,cADVD,EAAKnG,KAAKoG,GACdlG,KAAKrB,KACZ,OAAOsH,EAAKE,MAAMD,EAEtB,CACA,OAAO,CACT,CAEQxG,qBAAAA,GACNlE,sBAAsB,KACpB1D,KAAK6B,kBAAoB,IAAK7B,KAAK6B,kBAAmBG,SAAS,IAEnE,CAEQsM,iBAAAA,GACNtO,KAAKsB,SAAS2F,QAAQC,QAAQqH,eAAelH,MAC7CrH,KAAK4H,uBACP,CAEQ4G,iBAAAA,GACNxO,KAAKsB,SAAS2F,QAAQC,QAAQuH,cAAcpH,MAC5CrH,KAAK4H,uBACP,CAEQ8G,mBAAAA,GACN1O,KAAKsB,SAAS2F,QAAQC,QAAQyH,kBAAkBtH,MAChDrH,KAAK4H,uBACP,CAEQgH,oBAAAA,GACN5O,KAAKsB,SAAS2F,QAAQC,QAAQ2H,iBAAiBxH,MAC/CrH,KAAK4H,uBACP,CAEQkH,eAAAA,GACN9O,KAAKsB,SAAS2F,QAAQC,QAAQ6H,YAAY1H,MAC1CrH,KAAK4H,uBACP,CAEQoH,kBAAAA,GACNhP,KAAKsB,SAAS2F,QAAQC,QAAQ+H,eAAe5H,MAC7CrH,KAAK4H,uBACP,CAEQsH,YAAAA,GACNlP,KAAKsB,SAAS2F,QAAQC,QAAQiI,cAAc9H,MAC5CrH,KAAK4H,uBACP,CAGQgB,iBAAAA,CAAkBwG,GACxB1L,sBAAsB,KACpB1D,KAAKmC,cAAgB,CAAEL,EAAGsN,EAAItN,EAAGC,EAAGqN,EAAIrN,EAAGC,SAAS,GACpDhC,KAAKoC,uBAAwB,GAEjC,CAEQyG,iBAAAA,GACNnF,sBAAsB,KACpB1D,KAAKmC,cAAgB,IAAKnC,KAAKmC,cAAeH,SAAS,GACvDhC,KAAKoC,uBAAwB,GAEjC,CAEQiN,oBAAAA,GACNrP,KAAKoC,uBAAyBpC,KAAKoC,qBACrC,CAEQkN,YAAAA,GACNtP,KAAKsB,SAAS2F,QAAQC,QAAQqI,WAAW,SAASlI,MAClDrH,KAAK6I,mBACP,CAEQ2G,iBAAAA,GACNxP,KAAK6N,sBACL7N,KAAKoC,uBAAwB,CAC/B,CAEQqN,kBAAAA,GACN,MAAMzI,EAAShH,KAAKsB,QACpB,GAAI0F,EAAQ,CACV,MAAMa,UAAEA,GAAcb,EAAOc,MACvBsH,EAAMvH,EAAUoC,KACtBjD,EAAOC,QAAQC,QAAQwI,iBAAiBN,GAAK/H,MAC7C,MAAMsI,EAAM3P,KAAK0C,YAAYe,cAAc,6CACvCkM,IACFA,EAAIC,MAAMC,QAAU,QACpBF,EAAIC,MAAME,OAAS,aAEvB,CACA9P,KAAKoC,uBAAwB,CAC/B,CAEQ2N,oBAAAA,GACN,MAAM/I,EAAShH,KAAKsB,QACpB,GAAI0F,EAAQ,CACV,MAAMa,UAAEA,GAAcb,EAAOc,MACvBsH,EAAMvH,EAAUoC,KACtBjD,EAAOC,QAAQC,QAAQwI,iBAAiBN,GAAK/H,MAC7C,MAAMsI,EAAM3P,KAAK0C,YAAYe,cAAc,6CACvCkM,IACFA,EAAIC,MAAMC,QAAU,QACpBF,EAAIC,MAAME,OAAS,SAEvB,CACA9P,KAAKoC,uBAAwB,CAC/B,CAEQ4N,mBAAAA,GACN,MAAMhJ,EAAShH,KAAKsB,QACpB,GAAI0F,EAAQ,CACV,MAAMa,UAAEA,GAAcb,EAAOc,MACvBsH,EAAMvH,EAAUoC,KACtBjD,EAAOC,QAAQC,QAAQwI,iBAAiBN,GAAK/H,MAC7C,MAAMsI,EAAM3P,KAAK0C,YAAYe,cAAc,6CACvCkM,IACFA,EAAIC,MAAMC,QAAU,QACpBF,EAAIC,MAAME,OAAS,aAEvB,CACA9P,KAAKoC,uBAAwB,CAC/B,CAGQ6N,aAAAA,GACN,MAAMjJ,EAAShH,KAAKsB,QACpB,OAAK0F,EACDA,EAAOU,SAAS,UAAW,CAAEqE,MAAO,IAAe,OACnD/E,EAAOU,SAAS,UAAW,CAAEqE,MAAO,IAAe,OACnD/E,EAAOU,SAAS,UAAW,CAAEqE,MAAO,IAAe,OAChD,KAJe,IAKxB,CAEQmE,cAAAA,GACN,MAAMlJ,EAAShH,KAAKsB,QACpB,OAAK0F,EACDA,EAAOU,SAAS,CAAEyI,UAAW,WAAsB,KACnDnJ,EAAOU,SAAS,CAAEyI,UAAW,UAAqB,MAC/C,MAHe,IAIxB,CAEQ1I,yBAAAA,GACN/D,sBAAsB,KACpB,MAAM0M,EAAapQ,KAAK0C,YAAYe,cAA2B,gBACzD4M,EAAcrQ,KAAK0C,YAAYe,cAA2B,gBAC1DgG,EAAgBzJ,KAAK0C,YAAYe,cAA2B,mBAClE,IAAK2M,IAAeC,IAAgB5G,EAAiB,OAErD,MAAMzC,EAAShH,KAAKsB,QACdgP,EAAYtJ,GAAQU,SAAS,WAAY,GACzCG,UAAEA,GAAcb,GAAQc,OAAS,CAAED,UAAW,MAGpD,GAAIyI,GAAazI,IAAcA,EAAU0I,OAASvJ,EAAQ,CACxD,MAAQiD,KAAAA,EAAAA,GAAMkB,GAAOtD,EACfE,EAAQf,EAAOc,MAAM+B,IAAIlJ,QAAQsJ,GACjCuG,EAAMxJ,EAAOc,MAAM+B,IAAIlJ,QAAQwK,GAErC,IAAIsF,GAAsB,EAC1B,IAAA,IAASrC,EAAIrG,EAAME,MAAOmG,GAAK,EAAGA,IAChC,GAAgC,UAA5BrG,EAAMC,KAAKoG,GAAGlG,KAAKrB,KAAkB,CACvC4J,GAAsB,EACtB,KACF,CAGF,MAAMC,EAAe3I,EAAMC,KAAKD,EAAME,OAChC0I,EAAaH,EAAIxI,KAAKwI,EAAIvI,OAIhC,GAH+B,UAA3ByI,EAAaxI,KAAKrB,MAA6C,UAAzB8J,EAAWzI,KAAKrB,OACxD4J,GAAsB,GAEpBA,EAGF,OAFAL,EAAWR,MAAMgB,QAAU,SAC3BR,EAAWR,MAAMiB,WAAa,SAGlC,CAGA,GAAIhJ,IAAcA,EAAU0I,gBAEhB1I,GAAcA,EAAU0I,QAAUvQ,KAAKqC,iBAGjD,OAFA+N,EAAWR,MAAMgB,QAAU,SAC3BR,EAAWR,MAAMiB,WAAa,UAIhC,MAAMtI,EAAckB,EAAcjB,wBAC5BsI,EAAWV,EAAW5H,yBAEtByB,KAAEA,GAASpC,EACXM,EAASnI,KAAKsB,SAAS8G,KAAKC,YAAY4B,GAC9C,IAAK9B,EAAU,OAEf,IAAIM,EAAON,EAAOM,KAAOF,EAAYE,KACjCE,EAAMR,EAAOQ,IAAMJ,EAAYI,IAAM,GAErCF,EAAOqI,EAASC,MAAQxI,EAAYwI,QACtCtI,EAAOF,EAAYwI,MAAQD,EAASC,MAAQ,GAE1CtI,EAAO,IACTA,EAAO,GAGLE,EAAM,IACRA,EAAMR,EAAO+F,OAAS3F,EAAYI,IAAM,GAG1CyH,EAAWR,MAAMnH,KAAO,GAAGA,MAC3B2H,EAAWR,MAAMjH,IAAM,GAAGA,MAC1ByH,EAAWR,MAAMgB,QAAU,IAC3BR,EAAWR,MAAMiB,WAAa,WAElC,CAEAG,MAAAA,GACE,MAAMhK,EAAShH,KAAKsB,QAEpB,OAAO2H,EAAAA,IAAA;mCACyBjC,EAAqB,GAAZ,aAAkBhH,KAAKsD,QAAU,UAAY;UAC/E0D,EAKC,GALQiC,EAAAA,IAAA;;;;;;;;;;oBAUAjJ,KAAKuN;;;;UAIdvN,KAAKsD,QAoMJ,GApMc2F,EAAAA,IAAA;;;;gCAIMjC,GAAQU,SAAS,QAAU,YAAc;qBACpD1H,KAAKoL;;;;;;gCAMMpE,GAAQU,SAAS,UAAY,YAAc;qBACtD1H,KAAKsL;;;;;;gCAMMtE,GAAQU,SAAS,aAAe,YAAc;qBACzD1H,KAAKwL;;;;;;gCAMMxE,GAAQU,SAAS,UAAY,YAAc;qBACtD1H,KAAK0L;;;;;;;;;;;gBAWV1L,KAAKiQ;;;;;8CAK0BjJ,GAAQU,SAAS,WAA2B,GAAd;yBACpD1H,KAAKiM;;;;;8CAKgBjF,GAAQU,SAAS,UAAW,CAAEqE,MAAO,IAAO,YAAc;yBAC/E,IAAM/L,KAAK8L,YAAY;;;;;8CAKF9E,GAAQU,SAAS,UAAW,CAAEqE,MAAO,IAAO,YAAc;yBAC/E,IAAM/L,KAAK8L,YAAY;;;;;8CAKF9E,GAAQU,SAAS,UAAW,CAAEqE,MAAO,IAAO,YAAc;yBAC/E,IAAM/L,KAAK8L,YAAY;;;;;;;;;;;;gBAYhC9L,KAAKkQ;;;;;8CAKyBlJ,GAAQU,SAAS,CAAEyI,UAAW,SAAY,YAAc;yBAC7E,IAAMnQ,KAAKyM,cAAc;;;;;;8CAMJzF,GAAQU,SAAS,CAAEyI,UAAW,WAAc,YAAc;yBAC/E,IAAMnQ,KAAKyM,cAAc;;;;;;8CAMJzF,GAAQU,SAAS,CAAEyI,UAAW,UAAa,YAAc;yBAC9E,IAAMnQ,KAAKyM,cAAc;;;;;;;;;;;;gCAYlBzF,GAAQU,SAAS,QAAU,YAAc;qBACpD1H,KAAK4L;;;;;;;;gCAQM5E,GAAQU,SAAS,QAAU,YAAc;qBACpD1H,KAAK4M;;;;;;;;;qBASL5M,KAAK6N;;;;;;;;;;gCAUM7G,GAAQU,SAAS,cAAgB,YAAc;qBAC1D1H,KAAKmM;;;;;;;;;;;;;gCAaMnF,GAAQU,SAAS,eAAiB,YAAc;qBAC3D1H,KAAKqM;;;;;;;;;;;;;;;gCAeMrF,GAAQU,SAAS,cAAgB,YAAc;qBAC1D1H,KAAKuM;;;;;;;;;;qCAUWvM,KAAK4B,mBAAqB,UAAY;0BACjD,KACZ5B,KAAK4B,oBAAqB,EAC1B5B,KAAK0B,UAAY,EACjB1B,KAAK2B,UAAY;0BAEL,IAAM3B,KAAK4B,oBAAqB;;;;;;;kBAOxC5B,KAAKiR;;;wBAGCjR,KAAK0B,UAAY,EAAI,GAAG1B,KAAK0B,eAAe1B,KAAK2B,YAAc,GAAG3B,KAAKwB,gBAAgBxB,KAAKyB;;;;;;;;;;UAU1GzB,KAAK6B,kBAAkBG,SAAWgF,GAAQU,SAAS,SACjDuB,EAAAA,IAAA;;;2BAGejJ,KAAK6B,kBAAkBC,aAAa9B,KAAK6B,kBAAkBE;yBAC5Df,GAAaA,EAAEkQ;;cAEQ,IAAnClR,KAAK6B,kBAAkBI,QAAgBgH,EAAAA,IAAA;4EACuBjJ,KAAKsO;;;4EAGLtO,KAAKwO;;;iFAGAxO,KAAK8O;;;cAGtE;cACiC,IAAnC9O,KAAK6B,kBAAkBK,QAAgB+G,EAAAA,IAAA;gBACF,IAAnCjJ,KAAK6B,kBAAkBI,QAAgBgH,EAAAA,iFAAmF;4EAC9DjJ,KAAK0O;;;4EAGL1O,KAAK4O;;;iFAGA5O,KAAKgP;;;cAGtE;cACiC,IAAnChP,KAAK6B,kBAAkBI,SAAoD,IAAnCjC,KAAK6B,kBAAkBK,QAAgB+G,EAAAA,IAAA;;kFAEXjJ,KAAKkP;;;cAGvE;;YAGJ;;;UAGFlP,KAAKmC,cAAcH,QACjBiH,EAAAA,IAAA;;;2BAGejJ,KAAKmC,cAAcL,aAAa9B,KAAKmC,cAAcJ;yBACpDf,GAAaA,EAAEkQ;;2EAEkClR,KAAKsP;;;oEAGZtP,KAAKwP;;;;;oEAKLxP,KAAKqP;;;gBAGzDrP,KAAKoC,sBACH6G,EAAAA,IAAA;;gEAE8CjJ,KAAKyP;;;;gEAILzP,KAAK+P;;;;gEAIL/P,KAAKgQ;;;;;kBAMnD;;;YAIN;;KAGV,CAEQiB,gBAAAA,GACN,MAAME,EAAQ,GACd,IAAA,IAASC,EAAI,EAAGA,EAAI,IAAKA,IAAK,CAC5B,MAAMC,EAAMtH,KAAKuH,MAAMF,EAAI,IAAM,EAC3BG,EAAOH,EAAI,GAAM,EACjBI,EAAcxR,KAAK0B,UAAY,GAAK2P,GAAOrR,KAAK0B,WAAa6P,GAAOvR,KAAK2B,UAC/EwP,EAAMM,KAAKxI,EAAAA,IAAA;;8BAEauI,EAAc,WAAa;mBACtC,KACPxR,KAAK+N,oBAAoBsD,EAAKE,GAC9BvR,KAAK4B,oBAAqB;wBAEd,KACZ5B,KAAK0B,UAAY2P,EACjBrR,KAAK2B,UAAY4P;wBAEL,KACZvR,KAAK0B,UAAY,EACjB1B,KAAK2B,UAAY;;QAIzB,CACA,OAAOwP,CACT,GApkDWxR,QAAAA,oBACJ+R,OAASC,EAAAA,GAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAqlBhBC,EAAA,CADCC,EAAAA,SAAS,CAAE3J,KAAM9E,OAAQ0O,UAAW,aArlB1BnS,QAAAA,oBAslBXoS,UAAA,UAAA,GAGAH,EAAA,CADCC,EAAAA,SAAS,CAAE3J,KAAM9E,OAAQ0O,UAAW,iBAxlB1BnS,QAAAA,oBAylBXoS,UAAA,aAAA,GAGAH,EAAA,CADCC,EAAAA,SAAS,CAAE3J,KAAM9E,OAAQ0O,UAAW,eA3lB1BnS,QAAAA,oBA4lBXoS,UAAA,eAAA,GAGAH,EAAA,CADCC,EAAAA,SAAS,CAAE3J,KAAM9E,OAAQ0O,UAAW,cA9lB1BnS,QAAAA,oBA+lBXoS,UAAA,eAAA,GAGAH,EAAA,CADCC,EAAAA,SAAS,CAAE3J,KAAM9E,OAAQ0O,UAAW,aAjmB1BnS,QAAAA,oBAkmBXoS,UAAA,cAAA,GAGAH,EAAA,CADCC,EAAAA,SAAS,CAAE3J,KAAM9E,OAAQ0O,UAAW,mBApmB1BnS,QAAAA,oBAqmBXoS,UAAA,mBAAA,GA8CAH,EAAA,CADCC,EAAAA,SAAS,CAAE3J,KAAM8J,OAAQF,UAAW,kBAlpB1BnS,QAAAA,oBAmpBXoS,UAAA,cAAA,GASiBH,EAAA,CAAhB9J,EAAAA,SA5pBUnI,QAAAA,oBA4pBMoS,UAAA,UAAA,GACAH,EAAA,CAAhB9J,EAAAA,SA7pBUnI,QAAAA,oBA6pBMoS,UAAA,kBAAA,GAGAH,EAAA,CAAhB9J,EAAAA,SAhqBUnI,QAAAA,oBAgqBMoS,UAAA,YAAA,GACAH,EAAA,CAAhB9J,EAAAA,SAjqBUnI,QAAAA,oBAiqBMoS,UAAA,YAAA,GACAH,EAAA,CAAhB9J,EAAAA,SAlqBUnI,QAAAA,oBAkqBMoS,UAAA,qBAAA,GACAH,EAAA,CAAhB9J,EAAAA,SAnqBUnI,QAAAA,oBAmqBMoS,UAAA,oBAAA,GACAH,EAAA,CAAhB9J,EAAAA,SApqBUnI,QAAAA,oBAoqBMoS,UAAA,gBAAA,GACAH,EAAA,CAAhB9J,EAAAA,SArqBUnI,QAAAA,oBAqqBMoS,UAAA,wBAAA,GArqBNpS,QAAAA,oBAANiS,EAAA,CADNK,EAAAA,kBAAkB,0BACNtS,QAAAA,sCAukDN,WAAqB"}
@@ -18,7 +18,7 @@
18
18
  custom-id=${t.customId||""}
19
19
  exam-id=${t.examId??0}
20
20
  @move=${r} @delete=${a} @save=${o} @edit=${n} @add=${d}
21
- @set-key=${e=>{this._list=this._list.map((t,i)=>i===s?{...t,isKey:e.detail.value}:t),this._emitListChange()}}
21
+ @set-key=${e=>{this._list[s].isKey=e.detail.value,this.requestUpdate()}}
22
22
  @set-relation=${e=>this._emit("set-relation",e.detail)}
23
23
  ></qxs-subject-single>`:t.answerType===l.SubjectType.BLANK_FILL?e.html`<qxs-blank-fill
24
24
  .title=${t.title||""}
@@ -1 +1 @@
1
- {"version":3,"file":"list.cjs","sources":["../../../../packages/components-wc/src/subject/list.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\nimport Sortable from 'sortablejs'\nimport { safeCustomElement } from '../base/define'\nimport { uid } from '../base/uid'\nimport { SubjectError } from './single'\nimport { SubjectType } from './types'\n\n// 导入子组件以确保它们被注册为 Custom Elements\nimport './action'\nimport './blank-fill'\nimport './layout'\nimport './text-fill'\nimport './scale'\nimport './page-end'\nimport './type'\n\nconst TYPE_LABEL: Record<string, string> = {\n [SubjectType.SINGLE]: '单选题', [SubjectType.MULTIPLE]: '多选题', [SubjectType.SORT]: '排序题',\n [SubjectType.BLANK_FILL]: '填空题', [SubjectType.TEXT_FILL]: '问答题', [SubjectType.SCALE]: '量表题',\n}\n\n@safeCustomElement('qxs-subject-list')\nexport class QxsSubjectList extends LitElement {\n static styles = css`\n :host { display: block; font-family: system-ui, -apple-system, \"PingFang SC\", \"Microsoft YaHei\", sans-serif; font-size: 13px; }\n *, ::before, ::after { box-sizing: border-box; }\n .sort-mode-toggle { display: flex; justify-content: flex-end; margin-bottom: 12px; }\n .btn { display: inline-flex; align-items: center; gap: 4px; height: 28px; padding: 0 12px; font-size: 12px; border: 1px solid #dcdfe6; border-radius: 3px; background: #fff; color: #606266; cursor: pointer; transition: all 0.2s; }\n .btn:hover { color: #3D61E3; border-color: #3D61E3; background: #ecf5ff; }\n .btn.primary { background: #3D61E3; border-color: #3D61E3; color: #fff; }\n .btn.primary:hover { background: #3D61E3; border-color: #3D61E3; }\n .subject-list { display: flex; flex-direction: column; }\n .subject-content { flex: 1; min-width: 0; }\n .ghost { opacity: 0.5; background: #ecf5ff; }\n .chosen { box-shadow: 0 4px 16px rgba(64,158,255,.3); }\n .sort-list { display: flex; flex-direction: column; gap: 8px; }\n .sort-item { display: flex; align-items: center; padding: 12px 16px; background: #f8f9fa; border: 1px solid #e4e7ed; border-radius: 6px; cursor: grab; transition: all 0.3s ease; }\n .sort-item:hover { background: #ecf5ff; border-color: #c6e2ff; }\n .sort-item:active { cursor: grabbing; }\n .sort-item.sort-ghost { opacity: 0.5; background: #ecf5ff; border: 2px dashed #409eff; }\n .sort-item.sort-chosen { background: #ecf5ff; border-color: #409eff; box-shadow: 0 4px 16px rgba(64,158,255,.3); transform: scale(1.02); }\n .sort-handle { display: flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin-right: 12px; color: #909399; flex-shrink: 0; }\n .sort-index { font-size: 13px; color: #606266; font-weight: 500; margin-right: 8px; min-width: 24px; flex-shrink: 0; }\n .sort-title { flex: 1; font-size: 14px; color: #303133; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .sort-type { font-size: 12px; color: #909399; margin-left: 12px; padding: 2px 8px; background: #f0f0f0; border-radius: 4px; flex-shrink: 0; }\n `\n\n @property({ attribute: 'is-preview' }) isPreview = false\n\n // use-model: enables two-way binding via model-value attribute + list-change event\n @property({ attribute: 'use-model' }) useModelAttr: string | null = null\n @property({ attribute: 'model-value' })\n get modelValue(): string { return JSON.stringify(this._list) }\n\n set modelValue(v: string) {\n if (!v || v === this._modelValueAttr) { return }\n this._modelValueAttr = v\n try {\n const parsed = JSON.parse(v)\n if (Array.isArray(parsed)) {\n this._list = parsed.map((i: any) => ({ ...i, customId: i.customId || uid() }))\n this.requestUpdate()\n }\n }\n catch { /* invalid JSON, ignore */ }\n }\n\n private get _useModel(): boolean {\n return this.useModelAttr === 'true' || this.useModelAttr === '' || this.hasAttribute('use-model')\n }\n\n private _modelValueAttr = ''\n\n @property({ type: Object })\n uploadImage: (file: File) => Promise<string> = async (file: File) => {\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = e => resolve(e.target?.result as string)\n reader.onerror = reject\n reader.readAsDataURL(file)\n })\n }\n\n @property({ type: Array })\n get subjectList() { return this._list }\n\n set subjectList(v: any) {\n if (!v) {\n this._list = []\n return\n }\n if (typeof v === 'string') {\n try {\n v = JSON.parse(v)\n }\n catch {\n this._list = []\n this.requestUpdate()\n return\n }\n }\n if (!Array.isArray(v)) {\n this._list = []\n this.requestUpdate()\n return\n }\n this._list = v.map((i: any) => ({ ...i, customId: i.customId || uid() }))\n this.requestUpdate()\n }\n\n attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null) {\n super.attributeChangedCallback(name, oldVal, newVal)\n if (name === 'subject-list' && newVal && !this._list.length) {\n if (newVal.includes('[object Object]')) {\n return\n }\n try {\n const parsed = JSON.parse(newVal)\n if (Array.isArray(parsed)) {\n this._list = parsed.map((i: any) => ({ ...i, customId: i.customId || uid() }))\n this.requestUpdate()\n }\n }\n catch {\n // Not valid JSON, ignore\n }\n }\n }\n\n @state() private _list: any[] = []\n @state() private _sortMode = false\n private _sortable: Sortable | null = null\n\n private get _isPreviewValue(): boolean {\n const val = (this as any).isPreview\n return typeof val === 'string' ? val !== 'false' : !!val\n }\n\n private _initialDataProcessed = false\n\n connectedCallback() {\n super.connectedCallback()\n if (!this._initialDataProcessed) {\n this._initialDataProcessed = true\n Promise.resolve().then(() => {\n if (this._list.length === 0) {\n this._processAttributeList()\n }\n })\n }\n }\n\n private _processAttributeList() {\n const attr = this.getAttribute('subject-list')\n if (!attr || attr === '[]') { return }\n if (attr.includes('[object Object]')) {\n return\n }\n try {\n const parsed = JSON.parse(attr)\n if (Array.isArray(parsed) && parsed.length > 0) {\n this._list = parsed.map((i: any) => ({ ...i, customId: i.customId || uid() }))\n this.requestUpdate()\n }\n }\n catch {\n // Not valid JSON, ignore\n }\n }\n\n firstUpdated() {\n this.updateComplete.then(() => this._initSortable())\n }\n\n updated(changed: Map<string, unknown>) {\n if (changed.has('_sortMode')) {\n this._sortable?.destroy()\n this._sortable = null\n this.updateComplete.then(() => this._initSortable())\n }\n // Reinitialize Sortable when list changes in sort mode\n if (changed.has('_list') && this._sortMode) {\n // Small delay to let Lit finish DOM updates\n setTimeout(() => {\n if (this._sortable) {\n this._sortable.destroy()\n this._sortable = null\n }\n this._initSortable()\n }, 50)\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this._sortable?.destroy()\n this._sortable = null\n }\n\n private _initSortable() {\n if (!this._sortMode) { return }\n const el = this.querySelector<HTMLElement>('.sort-list')\n if (!el) { return }\n\n // Destroy existing instance first\n if (this._sortable) {\n this._sortable.destroy()\n this._sortable = null\n }\n\n // Small delay to ensure DOM is ready after previous destroy\n requestAnimationFrame(() => {\n const currentEl = this.querySelector<HTMLElement>('.sort-list')\n if (!currentEl || this._sortable) { return }\n\n this._sortable = Sortable.create(currentEl, {\n handle: '.sort-handle',\n animation: 200,\n ghostClass: 'sort-ghost',\n chosenClass: 'sort-chosen',\n onEnd: (evt) => {\n const { oldIndex, newIndex } = evt\n if (oldIndex === undefined || newIndex === undefined || oldIndex === newIndex) { return }\n const arr = [...this._list]\n const [item] = arr.splice(oldIndex, 1)\n arr.splice(newIndex, 0, item)\n this._list = arr\n this._emitListChange()\n },\n })\n })\n }\n\n private _emit(name: string, detail?: unknown) {\n this.dispatchEvent(new CustomEvent(name, { bubbles: true, composed: true, detail: detail ?? null }))\n }\n\n private _emitListChange() {\n this._emit('change', this._list)\n if (this._useModel) {\n this._modelValueAttr = JSON.stringify(this._list)\n this._emit('list-change', this._list)\n }\n }\n\n async toJSON(): Promise<any[]> {\n const subjectEls = this.querySelectorAll<any>(\n 'qxs-subject-single, qxs-blank-fill, qxs-text-fill, qxs-scale, qxs-subject-rich-text',\n )\n if (!subjectEls || subjectEls.length === 0) {\n return []\n }\n\n const results: any[] = []\n const errors: SubjectError[] = []\n\n for (const el of subjectEls) {\n if (typeof el.toJSON === 'function') {\n try {\n const data = await el.toJSON()\n results.push(data)\n }\n catch (err: any) {\n if (err instanceof SubjectError) {\n errors.push(err)\n }\n else {\n errors.push(new SubjectError(err.message || '未知错误', 'UNKNOWN', 'unknown'))\n }\n }\n }\n }\n\n if (errors.length > 0) {\n throw errors\n }\n\n return results\n }\n\n async validate(): Promise<{ valid: boolean, errors: SubjectError[] }> {\n const subjectEls = this.querySelectorAll<any>(\n 'qxs-subject-single, qxs-blank-fill, qxs-text-fill, qxs-scale',\n )\n if (!subjectEls || subjectEls.length === 0) {\n return { valid: true, errors: [] }\n }\n\n const errors: SubjectError[] = []\n\n for (const el of subjectEls) {\n if (typeof el.validate === 'function') {\n const errs = el.validate()\n if (errs?.length) {\n errors.push(...errs)\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n }\n\n // ── public API ────────────────────────────────────────────────\n get currentList() { return this._list }\n\n addSubject(type: string, index?: number, examAnswerRelationType: number | null = null) {\n const item = {\n customId: uid(), answerType: type, title: '',\n answers: [], analysis: '', scaleQuestionList: [],\n isEdit: true, isSave: false, isRealCanDel: true, hasSet: false,\n isKey: false, answerCheckType: 1,\n examAnswerRelationType: examAnswerRelationType ?? 0,\n }\n const arr = [...this._list]\n if (typeof index === 'number' && index >= 0) {\n arr.splice(index + 1, 0, item)\n }\n else { arr.push(item) }\n this._list = arr\n this.requestUpdate()\n this._emitListChange()\n }\n\n addExam(items: any[]) {\n const newItems: any[] = []\n items.forEach((v: any) => {\n const item: any = {\n ...v,\n customId: v.customId || uid(),\n answers: v.answers?.map((c: any) => ({ ...c, title: c.answer, answerId: c.examAnswerId, isCorrect: c.isCorrect })) || [],\n isEdit: true, isSave: false, isRealCanDel: true, hasSet: false,\n }\n if (!v.richTextContent) {\n item.answerType = v.examTypeEnum\n }\n newItems.push(item)\n })\n this._list = [...this._list, ...newItems]\n this._emitListChange()\n }\n\n uploadExcel(list: any[]) {\n this._list = [...this._list, ...list.map((i: any) => ({ ...i, customId: i.customId || uid(), isRealCanDel: true }))]\n this._emitListChange()\n }\n\n setAnswerRelation(answerRelations: any, customId: string, customAnswerId: string) {\n const item = this._list.find((v: any) => v.customId === customId)\n if (item) {\n const ans = item.answers?.find((c: any) => c.customAnswerId === customAnswerId)\n if (ans) { ans.answerRelations = answerRelations }\n }\n this.requestUpdate()\n this._emitListChange()\n }\n\n // ── private helpers ───────────────────────────────────────────\n private _orderIndex(customId: string) {\n let n = 0; let out = 0\n this._list.forEach((v: any) => {\n n++; if (v.customId === customId) { out = n }\n })\n return out - 1\n }\n\n private _move(index: number, dir: 'up' | 'down') {\n const arr = [...this._list]\n if (dir === 'up' && index > 0) { [arr[index - 1], arr[index]] = [arr[index], arr[index - 1]] }\n else if (dir === 'down' && index < arr.length - 1) { [arr[index], arr[index + 1]] = [arr[index + 1], arr[index]] }\n this._list = arr\n this._emitListChange()\n }\n\n private _save(index: number, e: CustomEvent) {\n this._list = this._list.map((item, i) =>\n i === index ? { ...item, ...e.detail, isEdit: false, isSave: true } : item,\n )\n this._emitListChange()\n }\n\n private _deleteByCustomId(customId: string) {\n this._list = this._list.filter(item => item.customId !== customId)\n this._emitListChange()\n }\n\n private _delete(index: number) {\n const arr = [...this._list]\n arr.splice(index, 1)\n this._list = arr\n this._emitListChange()\n }\n\n private _setEdit(index: number, val: boolean) {\n this._list = this._list.map((item, i) => i === index ? { ...item, isEdit: val } : item)\n }\n\n private _renderItem(item: any, index: number) {\n const common = {\n 'order-index': this._orderIndex(item.customId),\n '?is-edit': item.isEdit || false,\n '?is-set': item.hasSet || false,\n '?is-save': !item.isRealCanDel,\n '?show-action': !this._isPreviewValue,\n 'exam-answer-relation-type': item.examAnswerRelationType ?? 0,\n }\n const onMove = (e: CustomEvent) => this._move(index, e.detail as 'up' | 'down')\n const onDelete = () => this._deleteByCustomId(item.customId)\n const onSave = (e: CustomEvent) => this._save(index, e)\n const onEdit = () => this._setEdit(index, true)\n const onAdd = (e: CustomEvent) => this.addSubject(e.detail?.type ?? e.detail, index)\n\n if ([SubjectType.SINGLE, SubjectType.MULTIPLE, SubjectType.SORT].includes(item.answerType)) {\n return html`<qxs-subject-single\n .title=${item.title || ''}\n .answerList=${item.answers || []}\n .uploadImage=${this.uploadImage}\n order-index=${common['order-index']}\n ?is-edit=${item.isEdit}\n ?is-set=${item.hasSet}\n ?is-save=${!item.isRealCanDel}\n ?show-action=${!this._isPreviewValue}\n ?is-key=${item.isKey}\n question-type=${String(item.answerType)}\n answer-check-type=${item.answerCheckType ?? 1}\n exam-answer-relation-type=${item.examAnswerRelationType ?? 0}\n rich-text-content=${item.examRichTextContent || ''}\n analysis=${item.analysis || ''}\n least-answer-count=${item.leastAnswerCount ?? 2}\n exam-expand=${item.examExpand || ''}\n custom-id=${item.customId || ''}\n exam-id=${item.examId ?? 0}\n @move=${onMove} @delete=${onDelete} @save=${onSave} @edit=${onEdit} @add=${onAdd}\n @set-key=${(e: CustomEvent) => {\n this._list = this._list.map((item, i) =>\n i === index ? { ...item, isKey: e.detail.value } : item,\n )\n this._emitListChange()\n }}\n @set-relation=${(e: CustomEvent) => this._emit('set-relation', e.detail)}\n ></qxs-subject-single>`\n }\n if (item.answerType === SubjectType.BLANK_FILL) {\n return html`<qxs-blank-fill\n .title=${item.title || ''}\n .answerList=${item.answers || []}\n .examAnswerSetting=${item.examAnswerSettingVO || {}}\n .uploadImage=${this.uploadImage}\n order-index=${common['order-index']}\n ?is-edit=${item.isEdit} ?is-set=${item.hasSet} ?is-save=${!item.isRealCanDel} ?show-action=${!this._isPreviewValue}\n exam-answer-relation-type=${item.examAnswerRelationType ?? 0}\n exam-expand=${item.examExpand || ''}\n rich-text-content=${item.examRichTextContent || ''}\n analysis=${item.analysis || ''}\n custom-id=${item.customId || ''}\n @move=${onMove} @delete=${onDelete} @save=${onSave} @edit=${onEdit} @add=${onAdd}\n ></qxs-blank-fill>`\n }\n if (item.answerType === SubjectType.TEXT_FILL) {\n return html`<qxs-text-fill\n .title=${item.title || ''}\n .answerList=${item.answers || []}\n .examAnswerSetting=${item.examAnswerSettingVO || {}}\n .uploadImage=${this.uploadImage}\n order-index=${common['order-index']}\n ?is-edit=${item.isEdit} ?is-set=${item.hasSet} ?is-save=${!item.isRealCanDel} ?show-action=${!this._isPreviewValue}\n exam-answer-relation-type=${item.examAnswerRelationType ?? 0}\n exam-expand=${item.examExpand || ''}\n rich-text-content=${item.examRichTextContent || ''}\n analysis=${item.analysis || ''}\n custom-id=${item.customId || ''}\n @move=${onMove} @delete=${onDelete} @save=${onSave} @edit=${onEdit} @add=${onAdd}\n ></qxs-text-fill>`\n }\n if (item.answerType === SubjectType.SCALE) {\n return html`<qxs-scale\n .title=${item.title || ''}\n .answerList=${item.answers || []}\n .scaleQuestions=${item.scaleQuestionList || []}\n .uploadImage=${this.uploadImage}\n order-index=${common['order-index']}\n ?is-edit=${item.isEdit} ?is-set=${item.hasSet} ?is-save=${!item.isRealCanDel} ?show-action=${!this._isPreviewValue}\n exam-answer-relation-type=${item.examAnswerRelationType ?? 0}\n rich-text-content=${item.examRichTextContent || ''}\n analysis=${item.analysis || ''}\n custom-id=${item.customId || ''}\n @move=${onMove} @delete=${onDelete} @save=${onSave} @edit=${onEdit} @add=${onAdd}\n ></qxs-scale>`\n }\n return html`<div style=\"color:#909399;padding:8px\">未知题型: ${item.answerType}</div>`\n }\n\n render() {\n return html`\n <div class=\"subject-list\">\n ${this._list.map((item, index) => this._renderItem(item, index))}\n </div>\n `\n }\n}\n\nexport function register() {}\n"],"names":["SubjectType","SINGLE","MULTIPLE","SORT","BLANK_FILL","TEXT_FILL","SCALE","QxsSubjectList","LitElement","constructor","super","arguments","this","isPreview","useModelAttr","_modelValueAttr","uploadImage","async","Promise","resolve","reject","reader","FileReader","onload","e","target","result","onerror","readAsDataURL","file","_list","_sortMode","_sortable","_initialDataProcessed","modelValue","JSON","stringify","v","parsed","parse","Array","isArray","map","i","customId","uid","requestUpdate","_useModel","hasAttribute","subjectList","attributeChangedCallback","name","oldVal","newVal","length","includes","_isPreviewValue","val","connectedCallback","then","_processAttributeList","attr","getAttribute","firstUpdated","updateComplete","_initSortable","updated","changed","has","destroy","setTimeout","disconnectedCallback","querySelector","requestAnimationFrame","currentEl","Sortable","create","handle","animation","ghostClass","chosenClass","onEnd","evt","oldIndex","newIndex","arr","item","splice","_emitListChange","_emit","detail","dispatchEvent","CustomEvent","bubbles","composed","toJSON","subjectEls","querySelectorAll","results","errors","el","data","push","err","SubjectError","message","validate","valid","errs","currentList","addSubject","type","index","examAnswerRelationType","undefined","answerType","title","answers","analysis","scaleQuestionList","isEdit","isSave","isRealCanDel","hasSet","isKey","answerCheckType","addExam","items","newItems","forEach","c","answer","answerId","examAnswerId","isCorrect","richTextContent","examTypeEnum","uploadExcel","list","setAnswerRelation","answerRelations","customAnswerId","find","ans","_orderIndex","n","out","_move","dir","_save","_deleteByCustomId","filter","_delete","_setEdit","_renderItem","common","onMove","onDelete","onSave","onEdit","onAdd","html","String","examRichTextContent","leastAnswerCount","examExpand","examId","value","examAnswerSettingVO","render","styles","css","__decorateClass","property","attribute","prototype","Object","state","safeCustomElement"],"mappings":"ywBAmBGA,EAAAA,YAAYC,OAAiBD,EAAAA,YAAYE,SAAmBF,EAAAA,YAAYG,KACxEH,EAAAA,YAAYI,WAAqBJ,EAAAA,YAAYK,UAAoBL,EAAAA,YAAYM,MAInEC,QAAAA,eAAN,cAA6BC,EAAAA,WAA7BC,WAAAA,GAAAC,SAAAC,WAyBkCC,KAAAC,WAAY,EAGbD,KAAAE,aAA8B,KAqBpEF,KAAQG,gBAAkB,GAG1BH,KAAAI,YAA+CC,SACtC,IAAIC,QAAQ,CAACC,EAASC,KAC3B,MAAMC,EAAS,IAAIC,WACnBD,EAAOE,OAASC,GAAKL,EAAQK,EAAEC,QAAQC,QACvCL,EAAOM,QAAUP,EACjBC,EAAOO,cAAcC,KAkDhBjB,KAAQkB,MAAe,GACvBlB,KAAQmB,WAAY,EAC7BnB,KAAQoB,UAA6B,KAOrCpB,KAAQqB,uBAAwB,CAAA,CAtFhC,cAAIC,GAAuB,OAAOC,KAAKC,UAAUxB,KAAKkB,MAAO,CAE7D,cAAII,CAAWG,GACb,GAAKA,GAAKA,IAAMzB,KAAKG,gBAArB,CACAH,KAAKG,gBAAkBsB,EACvB,IACE,MAAMC,EAASH,KAAKI,MAAMF,GACtBG,MAAMC,QAAQH,KAChB1B,KAAKkB,MAAQQ,EAAOI,IAAKC,IAAA,IAAiBA,EAAGC,SAAUD,EAAEC,UAAYC,EAAAA,SACrEjC,KAAKkC,gBAET,CAAA,MACmC,CATY,CAUjD,CAEA,aAAYC,GACV,MAA6B,SAAtBnC,KAAKE,cAAiD,KAAtBF,KAAKE,cAAuBF,KAAKoC,aAAa,YACvF,CAeA,eAAIC,GAAgB,OAAOrC,KAAKkB,KAAM,CAEtC,eAAImB,CAAYZ,GACd,GAAKA,EAAL,CAIA,GAAiB,iBAANA,EACT,IACEA,EAAIF,KAAKI,MAAMF,EACjB,CAAA,MAIE,OAFAzB,KAAKkB,MAAQ,QACblB,KAAKkC,eAEP,CAEF,IAAKN,MAAMC,QAAQJ,GAGjB,OAFAzB,KAAKkB,MAAQ,QACblB,KAAKkC,gBAGPlC,KAAKkB,MAAQO,EAAEK,IAAKC,IAAA,IAAiBA,EAAGC,SAAUD,EAAEC,UAAYC,EAAAA,SAChEjC,KAAKkC,eAjBL,MAFElC,KAAKkB,MAAQ,EAoBjB,CAEAoB,wBAAAA,CAAyBC,EAAcC,EAAuBC,GAE5D,GADA3C,MAAMwC,yBAAyBC,EAAMC,EAAQC,GAChC,iBAATF,GAA2BE,IAAWzC,KAAKkB,MAAMwB,OAAQ,CAC3D,GAAID,EAAOE,SAAS,mBAClB,OAEF,IACE,MAAMjB,EAASH,KAAKI,MAAMc,GACtBb,MAAMC,QAAQH,KAChB1B,KAAKkB,MAAQQ,EAAOI,IAAKC,IAAA,IAAiBA,EAAGC,SAAUD,EAAEC,UAAYC,EAAAA,SACrEjC,KAAKkC,gBAET,CAAA,MAGA,CACF,CACF,CAMA,mBAAYU,GACV,MAAMC,EAAO7C,KAAaC,UAC1B,MAAsB,iBAAR4C,EAA2B,UAARA,IAAoBA,CACvD,CAIAC,iBAAAA,GACEhD,MAAMgD,oBACD9C,KAAKqB,wBACRrB,KAAKqB,uBAAwB,EAC7Bf,QAAQC,UAAUwC,KAAK,KACK,IAAtB/C,KAAKkB,MAAMwB,QACb1C,KAAKgD,0BAIb,CAEQA,qBAAAA,GACN,MAAMC,EAAOjD,KAAKkD,aAAa,gBAC/B,GAAKD,GAAiB,OAATA,IACTA,EAAKN,SAAS,mBAGlB,IACE,MAAMjB,EAASH,KAAKI,MAAMsB,GACtBrB,MAAMC,QAAQH,IAAWA,EAAOgB,OAAS,IAC3C1C,KAAKkB,MAAQQ,EAAOI,IAAKC,IAAA,IAAiBA,EAAGC,SAAUD,EAAEC,UAAYC,EAAAA,SACrEjC,KAAKkC,gBAET,CAAA,MAGA,CACF,CAEAiB,YAAAA,GACEnD,KAAKoD,eAAeL,KAAK,IAAM/C,KAAKqD,gBACtC,CAEAC,OAAAA,CAAQC,GACFA,EAAQC,IAAI,eACdxD,KAAKoB,WAAWqC,UAChBzD,KAAKoB,UAAY,KACjBpB,KAAKoD,eAAeL,KAAK,IAAM/C,KAAKqD,kBAGlCE,EAAQC,IAAI,UAAYxD,KAAKmB,WAE/BuC,WAAW,KACL1D,KAAKoB,YACPpB,KAAKoB,UAAUqC,UACfzD,KAAKoB,UAAY,MAEnBpB,KAAKqD,iBACJ,GAEP,CAEAM,oBAAAA,GACE7D,MAAM6D,uBACN3D,KAAKoB,WAAWqC,UAChBzD,KAAKoB,UAAY,IACnB,CAEQiC,aAAAA,GACN,IAAKrD,KAAKmB,UAAa,OACZnB,KAAK4D,cAA2B,gBAIvC5D,KAAKoB,YACPpB,KAAKoB,UAAUqC,UACfzD,KAAKoB,UAAY,MAInByC,sBAAsB,KACpB,MAAMC,EAAY9D,KAAK4D,cAA2B,cAC7CE,IAAa9D,KAAKoB,YAEvBpB,KAAKoB,UAAY2C,EAASC,OAAOF,EAAW,CAC1CG,OAAQ,eACRC,UAAW,IACXC,WAAY,aACZC,YAAa,cACbC,MAAQC,IACN,MAAMC,SAAEA,EAAAC,SAAUA,GAAaF,EAC/B,QAAiB,IAAbC,QAAuC,IAAbC,GAA0BD,IAAaC,EAAY,OACjF,MAAMC,EAAM,IAAIzE,KAAKkB,QACdwD,GAAQD,EAAIE,OAAOJ,EAAU,GACpCE,EAAIE,OAAOH,EAAU,EAAGE,GACxB1E,KAAKkB,MAAQuD,EACbzE,KAAK4E,wBAIb,CAEQC,KAAAA,CAAMtC,EAAcuC,GAC1B9E,KAAK+E,cAAc,IAAIC,YAAYzC,EAAM,CAAE0C,SAAS,EAAMC,UAAU,EAAMJ,OAAQA,GAAU,OAC9F,CAEQF,eAAAA,GACN5E,KAAK6E,MAAM,SAAU7E,KAAKkB,OACtBlB,KAAKmC,YACPnC,KAAKG,gBAAkBoB,KAAKC,UAAUxB,KAAKkB,OAC3ClB,KAAK6E,MAAM,cAAe7E,KAAKkB,OAEnC,CAEA,YAAMiE,GACJ,MAAMC,EAAapF,KAAKqF,iBACtB,uFAEF,IAAKD,GAAoC,IAAtBA,EAAW1C,OAC5B,MAAO,GAGT,MAAM4C,EAAiB,GACjBC,EAAyB,GAE/B,IAAA,MAAWC,KAAMJ,EACf,GAAyB,mBAAdI,EAAGL,OACZ,IACE,MAAMM,QAAaD,EAAGL,SACtBG,EAAQI,KAAKD,EACf,OACOE,GACDA,aAAeC,EAAAA,aACjBL,EAAOG,KAAKC,GAGZJ,EAAOG,KAAK,IAAIE,eAAaD,EAAIE,SAAW,OAAQ,UAAW,WAEnE,CAIJ,GAAIN,EAAO7C,OAAS,EAClB,MAAM6C,EAGR,OAAOD,CACT,CAEA,cAAMQ,GACJ,MAAMV,EAAapF,KAAKqF,iBACtB,gEAEF,IAAKD,GAAoC,IAAtBA,EAAW1C,OAC5B,MAAO,CAAEqD,OAAO,EAAMR,OAAQ,IAGhC,MAAMA,EAAyB,GAE/B,IAAA,MAAWC,KAAMJ,EACf,GAA2B,mBAAhBI,EAAGM,SAAyB,CACrC,MAAME,EAAOR,EAAGM,WACZE,GAAMtD,QACR6C,EAAOG,QAAQM,EAEnB,CAGF,MAAO,CACLD,MAAyB,IAAlBR,EAAO7C,OACd6C,SAEJ,CAGA,eAAIU,GAAgB,OAAOjG,KAAKkB,KAAM,CAEtCgF,UAAAA,CAAWC,EAAcC,GAA8D,IAA9CC,EAAAtG,UAAA2C,OAAA,QAAA4D,IAAAvG,UAAA,GAAAA,UAAA,GAAwC,KAC/E,MAAM2E,EAAO,CACX1C,SAAUC,EAAAA,MAAOsE,WAAYJ,EAAMK,MAAO,GAC1CC,QAAS,GAAIC,SAAU,GAAIC,kBAAmB,GAC9CC,QAAQ,EAAMC,QAAQ,EAAOC,cAAc,EAAMC,QAAQ,EACzDC,OAAO,EAAOC,gBAAiB,EAC/BZ,uBAAwBA,GAA0B,GAE9C5B,EAAM,IAAIzE,KAAKkB,OACA,iBAAVkF,GAAsBA,GAAS,EACxC3B,EAAIE,OAAOyB,EAAQ,EAAG,EAAG1B,GAEpBD,EAAIiB,KAAKhB,GAChB1E,KAAKkB,MAAQuD,EACbzE,KAAKkC,gBACLlC,KAAK4E,iBACP,CAEAsC,OAAAA,CAAQC,GACN,MAAMC,EAAkB,GACxBD,EAAME,QAAS5F,IACb,MAAMiD,EAAY,IACbjD,EACHO,SAAUP,EAAEO,UAAYC,QACxBwE,QAAShF,EAAEgF,SAAS3E,IAAKwF,IAAA,IAAiBA,EAAGd,MAAOc,EAAEC,OAAQC,SAAUF,EAAEG,aAAcC,UAAWJ,EAAEI,cAAiB,GACtHd,QAAQ,EAAMC,QAAQ,EAAOC,cAAc,EAAMC,QAAQ,GAEtDtF,EAAEkG,kBACLjD,EAAK6B,WAAa9E,EAAEmG,cAEtBR,EAAS1B,KAAKhB,KAEhB1E,KAAKkB,MAAQ,IAAIlB,KAAKkB,SAAUkG,GAChCpH,KAAK4E,iBACP,CAEAiD,WAAAA,CAAYC,GACV9H,KAAKkB,MAAQ,IAAIlB,KAAKkB,SAAU4G,EAAKhG,IAAKC,IAAA,IAAiBA,EAAGC,SAAUD,EAAEC,UAAYC,QAAO6E,cAAc,MAC3G9G,KAAK4E,iBACP,CAEAmD,iBAAAA,CAAkBC,EAAsBhG,EAAkBiG,GACxD,MAAMvD,EAAO1E,KAAKkB,MAAMgH,KAAMzG,GAAWA,EAAEO,WAAaA,GACxD,GAAI0C,EAAM,CACR,MAAMyD,EAAMzD,EAAK+B,SAASyB,KAAMZ,GAAWA,EAAEW,iBAAmBA,GAC5DE,IAAOA,EAAIH,gBAAkBA,EACnC,CACAhI,KAAKkC,gBACLlC,KAAK4E,iBACP,CAGQwD,WAAAA,CAAYpG,GAClB,IAAIqG,EAAI,EAAOC,EAAM,EAIrB,OAHAtI,KAAKkB,MAAMmG,QAAS5F,IAClB4G,IAAS5G,EAAEO,WAAaA,IAAYsG,EAAMD,KAErCC,EAAM,CACf,CAEQC,KAAAA,CAAMnC,EAAeoC,GAC3B,MAAM/D,EAAM,IAAIzE,KAAKkB,OACT,OAARsH,GAAgBpC,EAAQ,GAAM3B,EAAI2B,EAAQ,GAAI3B,EAAI2B,IAAU,CAAC3B,EAAI2B,GAAQ3B,EAAI2B,EAAQ,IACxE,SAARoC,GAAkBpC,EAAQ3B,EAAI/B,OAAS,KAAM+B,EAAI2B,GAAQ3B,EAAI2B,EAAQ,IAAM,CAAC3B,EAAI2B,EAAQ,GAAI3B,EAAI2B,KACzGpG,KAAKkB,MAAQuD,EACbzE,KAAK4E,iBACP,CAEQ6D,KAAAA,CAAMrC,EAAexF,GAC3BZ,KAAKkB,MAAQlB,KAAKkB,MAAMY,IAAI,CAAC4C,EAAM3C,IACjCA,IAAMqE,EAAQ,IAAK1B,KAAS9D,EAAEkE,OAAQ8B,QAAQ,EAAOC,QAAQ,GAASnC,GAExE1E,KAAK4E,iBACP,CAEQ8D,iBAAAA,CAAkB1G,GACxBhC,KAAKkB,MAAQlB,KAAKkB,MAAMyH,OAAOjE,GAAQA,EAAK1C,WAAaA,GACzDhC,KAAK4E,iBACP,CAEQgE,OAAAA,CAAQxC,GACd,MAAM3B,EAAM,IAAIzE,KAAKkB,OACrBuD,EAAIE,OAAOyB,EAAO,GAClBpG,KAAKkB,MAAQuD,EACbzE,KAAK4E,iBACP,CAEQiE,QAAAA,CAASzC,EAAevD,GAC9B7C,KAAKkB,MAAQlB,KAAKkB,MAAMY,IAAI,CAAC4C,EAAM3C,IAAMA,IAAMqE,EAAQ,IAAK1B,EAAMkC,OAAQ/D,GAAQ6B,EACpF,CAEQoE,WAAAA,CAAYpE,EAAW0B,GAC7B,MAAM2C,EACW/I,KAAKoI,YAAY1D,EAAK1C,UAOjCgH,GANQtE,EAAKkC,OACNlC,EAAKqC,OACHrC,EAAKoC,aACD9G,KAAK4C,gBACO8B,EAAK2B,uBAEpBzF,GAAmBZ,KAAKuI,MAAMnC,EAAOxF,EAAEkE,SACjDmE,EAAWA,IAAMjJ,KAAK0I,kBAAkBhE,EAAK1C,UAC7CkH,EAAUtI,GAAmBZ,KAAKyI,MAAMrC,EAAOxF,GAC/CuI,EAASA,IAAMnJ,KAAK6I,SAASzC,GAAO,GACpCgD,EAASxI,GAAmBZ,KAAKkG,WAAWtF,EAAEkE,QAAQqB,MAAQvF,EAAEkE,OAAQsB,GAE9E,MAAI,CAAChH,EAAAA,YAAYC,OAAQD,EAAAA,YAAYE,SAAUF,cAAYG,MAAMoD,SAAS+B,EAAK6B,YACtE8C,MAAA;iBACI3E,EAAK8B,OAAS;sBACT9B,EAAK+B,SAAW;uBACfzG,KAAKI;sBACN2I;mBACHrE,EAAKkC;kBACNlC,EAAKqC;oBACHrC,EAAKoC;wBACD9G,KAAK4C;kBACX8B,EAAKsC;wBACCsC,OAAO5E,EAAK6B;4BACR7B,EAAKuC,iBAAmB;oCAChBvC,EAAK2B,wBAA0B;4BACvC3B,EAAK6E,qBAAuB;mBACrC7E,EAAKgC,UAAY;6BACPhC,EAAK8E,kBAAoB;sBAChC9E,EAAK+E,YAAc;oBACrB/E,EAAK1C,UAAY;kBACnB0C,EAAKgF,QAAU;gBACjBV,aAAkBC,WAAkBC,WAAgBC,UAAeC;mBAC/DxI,IACVZ,KAAKkB,MAAQlB,KAAKkB,MAAMY,IAAI,CAAC4C,EAAM3C,IACjCA,IAAMqE,EAAQ,IAAK1B,EAAMsC,MAAOpG,EAAEkE,OAAO6E,OAAUjF,GAErD1E,KAAK4E;wBAEUhE,GAAmBZ,KAAK6E,MAAM,eAAgBjE,EAAEkE;8BAGjEJ,EAAK6B,aAAenH,EAAAA,YAAYI,WAC3B6J,MAAA;iBACI3E,EAAK8B,OAAS;sBACT9B,EAAK+B,SAAW;6BACT/B,EAAKkF,qBAAuB,CAAA;uBAClC5J,KAAKI;sBACN2I;mBACHrE,EAAKkC,kBAAkBlC,EAAKqC,oBAAoBrC,EAAKoC,8BAA8B9G,KAAK4C;oCACvE8B,EAAK2B,wBAA0B;sBAC7C3B,EAAK+E,YAAc;4BACb/E,EAAK6E,qBAAuB;mBACrC7E,EAAKgC,UAAY;oBAChBhC,EAAK1C,UAAY;gBACrBgH,aAAkBC,WAAkBC,WAAgBC,UAAeC;0BAG3E1E,EAAK6B,aAAenH,EAAAA,YAAYK,UAC3B4J,MAAA;iBACI3E,EAAK8B,OAAS;sBACT9B,EAAK+B,SAAW;6BACT/B,EAAKkF,qBAAuB,CAAA;uBAClC5J,KAAKI;sBACN2I;mBACHrE,EAAKkC,kBAAkBlC,EAAKqC,oBAAoBrC,EAAKoC,8BAA8B9G,KAAK4C;oCACvE8B,EAAK2B,wBAA0B;sBAC7C3B,EAAK+E,YAAc;4BACb/E,EAAK6E,qBAAuB;mBACrC7E,EAAKgC,UAAY;oBAChBhC,EAAK1C,UAAY;gBACrBgH,aAAkBC,WAAkBC,WAAgBC,UAAeC;yBAG3E1E,EAAK6B,aAAenH,EAAAA,YAAYM,MAC3B2J,MAAA;iBACI3E,EAAK8B,OAAS;sBACT9B,EAAK+B,SAAW;0BACZ/B,EAAKiC,mBAAqB;uBAC7B3G,KAAKI;sBACN2I;mBACHrE,EAAKkC,kBAAkBlC,EAAKqC,oBAAoBrC,EAAKoC,8BAA8B9G,KAAK4C;oCACvE8B,EAAK2B,wBAA0B;4BACvC3B,EAAK6E,qBAAuB;mBACrC7E,EAAKgC,UAAY;oBAChBhC,EAAK1C,UAAY;gBACrBgH,aAAkBC,WAAkBC,WAAgBC,UAAeC;qBAGxEC,EAAAA,IAAA,gDAAoD3E,EAAK6B,kBAClE,CAEAsD,MAAAA,GACE,OAAOR,EAAAA,IAAA;;UAEDrJ,KAAKkB,MAAMY,IAAI,CAAC4C,EAAM0B,IAAUpG,KAAK8I,YAAYpE,EAAM0B;;KAG/D,GA9dWzG,QAAAA,eACJmK,OAASC,EAAAA,GAAA;;;;;;;;;;;;;;;;;;;;;;KAwBuBC,EAAA,CAAtCC,EAAAA,SAAS,CAAEC,UAAW,gBAzBZvK,QAAAA,eAyB4BwK,UAAA,YAAA,GAGDH,EAAA,CAArCC,EAAAA,SAAS,CAAEC,UAAW,eA5BZvK,QAAAA,eA4B2BwK,UAAA,eAAA,GAElCH,EAAA,CADHC,EAAAA,SAAS,CAAEC,UAAW,iBA7BZvK,QAAAA,eA8BPwK,UAAA,aAAA,GAsBJH,EAAA,CADCC,EAAAA,SAAS,CAAE9D,KAAMiE,UAnDPzK,QAAAA,eAoDXwK,UAAA,cAAA,GAUIH,EAAA,CADHC,EAAAA,SAAS,CAAE9D,KAAMvE,SA7DPjC,QAAAA,eA8DPwK,UAAA,cAAA,GA6CaH,EAAA,CAAhBK,EAAAA,SA3GU1K,QAAAA,eA2GMwK,UAAA,QAAA,GACAH,EAAA,CAAhBK,EAAAA,SA5GU1K,QAAAA,eA4GMwK,UAAA,YAAA,GA5GNxK,QAAAA,eAANqK,EAAA,CADNM,EAAAA,kBAAkB,qBACN3K,QAAAA"}
1
+ {"version":3,"file":"list.cjs","sources":["../../../../packages/components-wc/src/subject/list.ts"],"sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\nimport Sortable from 'sortablejs'\nimport { safeCustomElement } from '../base/define'\nimport { uid } from '../base/uid'\nimport { SubjectError } from './single'\nimport { SubjectType } from './types'\n\n// 导入子组件以确保它们被注册为 Custom Elements\nimport './action'\nimport './blank-fill'\nimport './layout'\nimport './text-fill'\nimport './scale'\nimport './page-end'\nimport './type'\n\nconst TYPE_LABEL: Record<string, string> = {\n [SubjectType.SINGLE]: '单选题', [SubjectType.MULTIPLE]: '多选题', [SubjectType.SORT]: '排序题',\n [SubjectType.BLANK_FILL]: '填空题', [SubjectType.TEXT_FILL]: '问答题', [SubjectType.SCALE]: '量表题',\n}\n\n@safeCustomElement('qxs-subject-list')\nexport class QxsSubjectList extends LitElement {\n static styles = css`\n :host { display: block; font-family: system-ui, -apple-system, \"PingFang SC\", \"Microsoft YaHei\", sans-serif; font-size: 13px; }\n *, ::before, ::after { box-sizing: border-box; }\n .sort-mode-toggle { display: flex; justify-content: flex-end; margin-bottom: 12px; }\n .btn { display: inline-flex; align-items: center; gap: 4px; height: 28px; padding: 0 12px; font-size: 12px; border: 1px solid #dcdfe6; border-radius: 3px; background: #fff; color: #606266; cursor: pointer; transition: all 0.2s; }\n .btn:hover { color: #3D61E3; border-color: #3D61E3; background: #ecf5ff; }\n .btn.primary { background: #3D61E3; border-color: #3D61E3; color: #fff; }\n .btn.primary:hover { background: #3D61E3; border-color: #3D61E3; }\n .subject-list { display: flex; flex-direction: column; }\n .subject-content { flex: 1; min-width: 0; }\n .ghost { opacity: 0.5; background: #ecf5ff; }\n .chosen { box-shadow: 0 4px 16px rgba(64,158,255,.3); }\n .sort-list { display: flex; flex-direction: column; gap: 8px; }\n .sort-item { display: flex; align-items: center; padding: 12px 16px; background: #f8f9fa; border: 1px solid #e4e7ed; border-radius: 6px; cursor: grab; transition: all 0.3s ease; }\n .sort-item:hover { background: #ecf5ff; border-color: #c6e2ff; }\n .sort-item:active { cursor: grabbing; }\n .sort-item.sort-ghost { opacity: 0.5; background: #ecf5ff; border: 2px dashed #409eff; }\n .sort-item.sort-chosen { background: #ecf5ff; border-color: #409eff; box-shadow: 0 4px 16px rgba(64,158,255,.3); transform: scale(1.02); }\n .sort-handle { display: flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin-right: 12px; color: #909399; flex-shrink: 0; }\n .sort-index { font-size: 13px; color: #606266; font-weight: 500; margin-right: 8px; min-width: 24px; flex-shrink: 0; }\n .sort-title { flex: 1; font-size: 14px; color: #303133; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .sort-type { font-size: 12px; color: #909399; margin-left: 12px; padding: 2px 8px; background: #f0f0f0; border-radius: 4px; flex-shrink: 0; }\n `\n\n @property({ attribute: 'is-preview' }) isPreview = false\n\n // use-model: enables two-way binding via model-value attribute + list-change event\n @property({ attribute: 'use-model' }) useModelAttr: string | null = null\n @property({ attribute: 'model-value' })\n get modelValue(): string { return JSON.stringify(this._list) }\n\n set modelValue(v: string) {\n if (!v || v === this._modelValueAttr) { return }\n this._modelValueAttr = v\n try {\n const parsed = JSON.parse(v)\n if (Array.isArray(parsed)) {\n this._list = parsed.map((i: any) => ({ ...i, customId: i.customId || uid() }))\n this.requestUpdate()\n }\n }\n catch { /* invalid JSON, ignore */ }\n }\n\n private get _useModel(): boolean {\n return this.useModelAttr === 'true' || this.useModelAttr === '' || this.hasAttribute('use-model')\n }\n\n private _modelValueAttr = ''\n\n @property({ type: Object })\n uploadImage: (file: File) => Promise<string> = async (file: File) => {\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = e => resolve(e.target?.result as string)\n reader.onerror = reject\n reader.readAsDataURL(file)\n })\n }\n\n @property({ type: Array })\n get subjectList() { return this._list }\n\n set subjectList(v: any) {\n if (!v) {\n this._list = []\n return\n }\n if (typeof v === 'string') {\n try {\n v = JSON.parse(v)\n }\n catch {\n this._list = []\n this.requestUpdate()\n return\n }\n }\n if (!Array.isArray(v)) {\n this._list = []\n this.requestUpdate()\n return\n }\n this._list = v.map((i: any) => ({ ...i, customId: i.customId || uid() }))\n this.requestUpdate()\n }\n\n attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null) {\n super.attributeChangedCallback(name, oldVal, newVal)\n if (name === 'subject-list' && newVal && !this._list.length) {\n if (newVal.includes('[object Object]')) {\n return\n }\n try {\n const parsed = JSON.parse(newVal)\n if (Array.isArray(parsed)) {\n this._list = parsed.map((i: any) => ({ ...i, customId: i.customId || uid() }))\n this.requestUpdate()\n }\n }\n catch {\n // Not valid JSON, ignore\n }\n }\n }\n\n @state() private _list: any[] = []\n @state() private _sortMode = false\n private _sortable: Sortable | null = null\n\n private get _isPreviewValue(): boolean {\n const val = (this as any).isPreview\n return typeof val === 'string' ? val !== 'false' : !!val\n }\n\n private _initialDataProcessed = false\n\n connectedCallback() {\n super.connectedCallback()\n if (!this._initialDataProcessed) {\n this._initialDataProcessed = true\n Promise.resolve().then(() => {\n if (this._list.length === 0) {\n this._processAttributeList()\n }\n })\n }\n }\n\n private _processAttributeList() {\n const attr = this.getAttribute('subject-list')\n if (!attr || attr === '[]') { return }\n if (attr.includes('[object Object]')) {\n return\n }\n try {\n const parsed = JSON.parse(attr)\n if (Array.isArray(parsed) && parsed.length > 0) {\n this._list = parsed.map((i: any) => ({ ...i, customId: i.customId || uid() }))\n this.requestUpdate()\n }\n }\n catch {\n // Not valid JSON, ignore\n }\n }\n\n firstUpdated() {\n this.updateComplete.then(() => this._initSortable())\n }\n\n updated(changed: Map<string, unknown>) {\n if (changed.has('_sortMode')) {\n this._sortable?.destroy()\n this._sortable = null\n this.updateComplete.then(() => this._initSortable())\n }\n // Reinitialize Sortable when list changes in sort mode\n if (changed.has('_list') && this._sortMode) {\n // Small delay to let Lit finish DOM updates\n setTimeout(() => {\n if (this._sortable) {\n this._sortable.destroy()\n this._sortable = null\n }\n this._initSortable()\n }, 50)\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this._sortable?.destroy()\n this._sortable = null\n }\n\n private _initSortable() {\n if (!this._sortMode) { return }\n const el = this.querySelector<HTMLElement>('.sort-list')\n if (!el) { return }\n\n // Destroy existing instance first\n if (this._sortable) {\n this._sortable.destroy()\n this._sortable = null\n }\n\n // Small delay to ensure DOM is ready after previous destroy\n requestAnimationFrame(() => {\n const currentEl = this.querySelector<HTMLElement>('.sort-list')\n if (!currentEl || this._sortable) { return }\n\n this._sortable = Sortable.create(currentEl, {\n handle: '.sort-handle',\n animation: 200,\n ghostClass: 'sort-ghost',\n chosenClass: 'sort-chosen',\n onEnd: (evt) => {\n const { oldIndex, newIndex } = evt\n if (oldIndex === undefined || newIndex === undefined || oldIndex === newIndex) { return }\n const arr = [...this._list]\n const [item] = arr.splice(oldIndex, 1)\n arr.splice(newIndex, 0, item)\n this._list = arr\n this._emitListChange()\n },\n })\n })\n }\n\n private _emit(name: string, detail?: unknown) {\n this.dispatchEvent(new CustomEvent(name, { bubbles: true, composed: true, detail: detail ?? null }))\n }\n\n private _emitListChange() {\n this._emit('change', this._list)\n if (this._useModel) {\n this._modelValueAttr = JSON.stringify(this._list)\n this._emit('list-change', this._list)\n }\n }\n\n async toJSON(): Promise<any[]> {\n const subjectEls = this.querySelectorAll<any>(\n 'qxs-subject-single, qxs-blank-fill, qxs-text-fill, qxs-scale, qxs-subject-rich-text',\n )\n if (!subjectEls || subjectEls.length === 0) {\n return []\n }\n\n const results: any[] = []\n const errors: SubjectError[] = []\n\n for (const el of subjectEls) {\n if (typeof el.toJSON === 'function') {\n try {\n const data = await el.toJSON()\n results.push(data)\n }\n catch (err: any) {\n if (err instanceof SubjectError) {\n errors.push(err)\n }\n else {\n errors.push(new SubjectError(err.message || '未知错误', 'UNKNOWN', 'unknown'))\n }\n }\n }\n }\n\n if (errors.length > 0) {\n throw errors\n }\n\n return results\n }\n\n async validate(): Promise<{ valid: boolean, errors: SubjectError[] }> {\n const subjectEls = this.querySelectorAll<any>(\n 'qxs-subject-single, qxs-blank-fill, qxs-text-fill, qxs-scale',\n )\n if (!subjectEls || subjectEls.length === 0) {\n return { valid: true, errors: [] }\n }\n\n const errors: SubjectError[] = []\n\n for (const el of subjectEls) {\n if (typeof el.validate === 'function') {\n const errs = el.validate()\n if (errs?.length) {\n errors.push(...errs)\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n }\n\n // ── public API ────────────────────────────────────────────────\n get currentList() { return this._list }\n\n addSubject(type: string, index?: number, examAnswerRelationType: number | null = null) {\n const item = {\n customId: uid(), answerType: type, title: '',\n answers: [], analysis: '', scaleQuestionList: [],\n isEdit: true, isSave: false, isRealCanDel: true, hasSet: false,\n isKey: false, answerCheckType: 1,\n examAnswerRelationType: examAnswerRelationType ?? 0,\n }\n const arr = [...this._list]\n if (typeof index === 'number' && index >= 0) {\n arr.splice(index + 1, 0, item)\n }\n else { arr.push(item) }\n this._list = arr\n this.requestUpdate()\n this._emitListChange()\n }\n\n addExam(items: any[]) {\n const newItems: any[] = []\n items.forEach((v: any) => {\n const item: any = {\n ...v,\n customId: v.customId || uid(),\n answers: v.answers?.map((c: any) => ({ ...c, title: c.answer, answerId: c.examAnswerId, isCorrect: c.isCorrect })) || [],\n isEdit: true, isSave: false, isRealCanDel: true, hasSet: false,\n }\n if (!v.richTextContent) {\n item.answerType = v.examTypeEnum\n }\n newItems.push(item)\n })\n this._list = [...this._list, ...newItems]\n this._emitListChange()\n }\n\n uploadExcel(list: any[]) {\n this._list = [...this._list, ...list.map((i: any) => ({ ...i, customId: i.customId || uid(), isRealCanDel: true }))]\n this._emitListChange()\n }\n\n setAnswerRelation(answerRelations: any, customId: string, customAnswerId: string) {\n const item = this._list.find((v: any) => v.customId === customId)\n if (item) {\n const ans = item.answers?.find((c: any) => c.customAnswerId === customAnswerId)\n if (ans) { ans.answerRelations = answerRelations }\n }\n this.requestUpdate()\n this._emitListChange()\n }\n\n // ── private helpers ───────────────────────────────────────────\n private _orderIndex(customId: string) {\n let n = 0; let out = 0\n this._list.forEach((v: any) => {\n n++; if (v.customId === customId) { out = n }\n })\n return out - 1\n }\n\n private _move(index: number, dir: 'up' | 'down') {\n const arr = [...this._list]\n if (dir === 'up' && index > 0) { [arr[index - 1], arr[index]] = [arr[index], arr[index - 1]] }\n else if (dir === 'down' && index < arr.length - 1) { [arr[index], arr[index + 1]] = [arr[index + 1], arr[index]] }\n this._list = arr\n this._emitListChange()\n }\n\n private _save(index: number, e: CustomEvent) {\n this._list = this._list.map((item, i) =>\n i === index ? { ...item, ...e.detail, isEdit: false, isSave: true } : item,\n )\n this._emitListChange()\n }\n\n private _deleteByCustomId(customId: string) {\n this._list = this._list.filter(item => item.customId !== customId)\n this._emitListChange()\n }\n\n private _delete(index: number) {\n const arr = [...this._list]\n arr.splice(index, 1)\n this._list = arr\n this._emitListChange()\n }\n\n private _setEdit(index: number, val: boolean) {\n this._list = this._list.map((item, i) => i === index ? { ...item, isEdit: val } : item)\n }\n\n private _renderItem(item: any, index: number) {\n const common = {\n 'order-index': this._orderIndex(item.customId),\n '?is-edit': item.isEdit || false,\n '?is-set': item.hasSet || false,\n '?is-save': !item.isRealCanDel,\n '?show-action': !this._isPreviewValue,\n 'exam-answer-relation-type': item.examAnswerRelationType ?? 0,\n }\n const onMove = (e: CustomEvent) => this._move(index, e.detail as 'up' | 'down')\n const onDelete = () => this._deleteByCustomId(item.customId)\n const onSave = (e: CustomEvent) => this._save(index, e)\n const onEdit = () => this._setEdit(index, true)\n const onAdd = (e: CustomEvent) => this.addSubject(e.detail?.type ?? e.detail, index)\n\n if ([SubjectType.SINGLE, SubjectType.MULTIPLE, SubjectType.SORT].includes(item.answerType)) {\n return html`<qxs-subject-single\n .title=${item.title || ''}\n .answerList=${item.answers || []}\n .uploadImage=${this.uploadImage}\n order-index=${common['order-index']}\n ?is-edit=${item.isEdit}\n ?is-set=${item.hasSet}\n ?is-save=${!item.isRealCanDel}\n ?show-action=${!this._isPreviewValue}\n ?is-key=${item.isKey}\n question-type=${String(item.answerType)}\n answer-check-type=${item.answerCheckType ?? 1}\n exam-answer-relation-type=${item.examAnswerRelationType ?? 0}\n rich-text-content=${item.examRichTextContent || ''}\n analysis=${item.analysis || ''}\n least-answer-count=${item.leastAnswerCount ?? 2}\n exam-expand=${item.examExpand || ''}\n custom-id=${item.customId || ''}\n exam-id=${item.examId ?? 0}\n @move=${onMove} @delete=${onDelete} @save=${onSave} @edit=${onEdit} @add=${onAdd}\n @set-key=${(e: CustomEvent) => {\n this._list[index].isKey = e.detail.value\n this.requestUpdate()\n }}\n @set-relation=${(e: CustomEvent) => this._emit('set-relation', e.detail)}\n ></qxs-subject-single>`\n }\n if (item.answerType === SubjectType.BLANK_FILL) {\n return html`<qxs-blank-fill\n .title=${item.title || ''}\n .answerList=${item.answers || []}\n .examAnswerSetting=${item.examAnswerSettingVO || {}}\n .uploadImage=${this.uploadImage}\n order-index=${common['order-index']}\n ?is-edit=${item.isEdit} ?is-set=${item.hasSet} ?is-save=${!item.isRealCanDel} ?show-action=${!this._isPreviewValue}\n exam-answer-relation-type=${item.examAnswerRelationType ?? 0}\n exam-expand=${item.examExpand || ''}\n rich-text-content=${item.examRichTextContent || ''}\n analysis=${item.analysis || ''}\n custom-id=${item.customId || ''}\n @move=${onMove} @delete=${onDelete} @save=${onSave} @edit=${onEdit} @add=${onAdd}\n ></qxs-blank-fill>`\n }\n if (item.answerType === SubjectType.TEXT_FILL) {\n return html`<qxs-text-fill\n .title=${item.title || ''}\n .answerList=${item.answers || []}\n .examAnswerSetting=${item.examAnswerSettingVO || {}}\n .uploadImage=${this.uploadImage}\n order-index=${common['order-index']}\n ?is-edit=${item.isEdit} ?is-set=${item.hasSet} ?is-save=${!item.isRealCanDel} ?show-action=${!this._isPreviewValue}\n exam-answer-relation-type=${item.examAnswerRelationType ?? 0}\n exam-expand=${item.examExpand || ''}\n rich-text-content=${item.examRichTextContent || ''}\n analysis=${item.analysis || ''}\n custom-id=${item.customId || ''}\n @move=${onMove} @delete=${onDelete} @save=${onSave} @edit=${onEdit} @add=${onAdd}\n ></qxs-text-fill>`\n }\n if (item.answerType === SubjectType.SCALE) {\n return html`<qxs-scale\n .title=${item.title || ''}\n .answerList=${item.answers || []}\n .scaleQuestions=${item.scaleQuestionList || []}\n .uploadImage=${this.uploadImage}\n order-index=${common['order-index']}\n ?is-edit=${item.isEdit} ?is-set=${item.hasSet} ?is-save=${!item.isRealCanDel} ?show-action=${!this._isPreviewValue}\n exam-answer-relation-type=${item.examAnswerRelationType ?? 0}\n rich-text-content=${item.examRichTextContent || ''}\n analysis=${item.analysis || ''}\n custom-id=${item.customId || ''}\n @move=${onMove} @delete=${onDelete} @save=${onSave} @edit=${onEdit} @add=${onAdd}\n ></qxs-scale>`\n }\n return html`<div style=\"color:#909399;padding:8px\">未知题型: ${item.answerType}</div>`\n }\n\n render() {\n return html`\n <div class=\"subject-list\">\n ${this._list.map((item, index) => this._renderItem(item, index))}\n </div>\n `\n }\n}\n\nexport function register() {}\n"],"names":["SubjectType","SINGLE","MULTIPLE","SORT","BLANK_FILL","TEXT_FILL","SCALE","QxsSubjectList","LitElement","constructor","super","arguments","this","isPreview","useModelAttr","_modelValueAttr","uploadImage","async","Promise","resolve","reject","reader","FileReader","onload","e","target","result","onerror","readAsDataURL","file","_list","_sortMode","_sortable","_initialDataProcessed","modelValue","JSON","stringify","v","parsed","parse","Array","isArray","map","i","customId","uid","requestUpdate","_useModel","hasAttribute","subjectList","attributeChangedCallback","name","oldVal","newVal","length","includes","_isPreviewValue","val","connectedCallback","then","_processAttributeList","attr","getAttribute","firstUpdated","updateComplete","_initSortable","updated","changed","has","destroy","setTimeout","disconnectedCallback","querySelector","requestAnimationFrame","currentEl","Sortable","create","handle","animation","ghostClass","chosenClass","onEnd","evt","oldIndex","newIndex","arr","item","splice","_emitListChange","_emit","detail","dispatchEvent","CustomEvent","bubbles","composed","toJSON","subjectEls","querySelectorAll","results","errors","el","data","push","err","SubjectError","message","validate","valid","errs","currentList","addSubject","type","index","examAnswerRelationType","undefined","answerType","title","answers","analysis","scaleQuestionList","isEdit","isSave","isRealCanDel","hasSet","isKey","answerCheckType","addExam","items","newItems","forEach","c","answer","answerId","examAnswerId","isCorrect","richTextContent","examTypeEnum","uploadExcel","list","setAnswerRelation","answerRelations","customAnswerId","find","ans","_orderIndex","n","out","_move","dir","_save","_deleteByCustomId","filter","_delete","_setEdit","_renderItem","common","onMove","onDelete","onSave","onEdit","onAdd","html","String","examRichTextContent","leastAnswerCount","examExpand","examId","value","examAnswerSettingVO","render","styles","css","__decorateClass","property","attribute","prototype","Object","state","safeCustomElement"],"mappings":"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"}