@vervedoc/core 3.0.11 → 3.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +194 -71
  2. package/dist/assets/editor-worker-CG2Et0Mg.js +244 -0
  3. package/dist/assets/editor-worker-CG2Et0Mg.js.map +1 -0
  4. package/dist/assets/thumbnail-worker-BGjZ82h0.js +52 -0
  5. package/dist/assets/thumbnail-worker-BGjZ82h0.js.map +1 -0
  6. package/dist/command-chain.d.ts +40 -0
  7. package/dist/constants.d.ts +21 -0
  8. package/dist/core.js +16405 -3930
  9. package/dist/core.js.map +1 -1
  10. package/dist/core.umd.cjs +413 -134
  11. package/dist/core.umd.cjs.map +1 -1
  12. package/dist/docx-editor.d.ts +110 -0
  13. package/dist/index.d.ts +20 -23
  14. package/dist/shortcut.d.ts +60 -0
  15. package/dist/workers/compute.d.ts +17 -0
  16. package/dist/workers/thumbnail-manager.d.ts +19 -0
  17. package/dist/workers/worker-manager.d.ts +44 -0
  18. package/package.json +53 -60
  19. package/dist/DocxEditor.d.ts +0 -17
  20. package/dist/actuator/Actuator.d.ts +0 -22
  21. package/dist/assets/runtime.worker-glNChxsd.js.map +0 -1
  22. package/dist/docxParser/constants.d.ts +0 -42
  23. package/dist/docxParser/docx.parser.d.ts +0 -13
  24. package/dist/docxParser/index.d.ts +0 -13
  25. package/dist/docxParser/types.d.ts +0 -170
  26. package/dist/docxParser/worker/builder/element.builder.d.ts +0 -6
  27. package/dist/docxParser/worker/numbering.resolver.d.ts +0 -29
  28. package/dist/docxParser/worker/parsers/chart.parser.d.ts +0 -16
  29. package/dist/docxParser/worker/parsers/comment.parser.d.ts +0 -5
  30. package/dist/docxParser/worker/parsers/hyperlink.parser.d.ts +0 -14
  31. package/dist/docxParser/worker/parsers/image.parser.d.ts +0 -12
  32. package/dist/docxParser/worker/parsers/list.parser.d.ts +0 -6
  33. package/dist/docxParser/worker/parsers/ooxml.chart.parser.d.ts +0 -4
  34. package/dist/docxParser/worker/parsers/paragraph.parser.d.ts +0 -10
  35. package/dist/docxParser/worker/parsers/run.parser.d.ts +0 -22
  36. package/dist/docxParser/worker/parsers/section.parser.d.ts +0 -20
  37. package/dist/docxParser/worker/parsers/table.parser.d.ts +0 -11
  38. package/dist/docxParser/worker/parsers/toc.parser.d.ts +0 -13
  39. package/dist/docxParser/worker/relationship.resolver.d.ts +0 -17
  40. package/dist/docxParser/worker/style.resolver.d.ts +0 -33
  41. package/dist/docxParser/worker/theme.resolver.d.ts +0 -21
  42. package/dist/docxParser/worker/xml.helper.d.ts +0 -36
  43. package/dist/export/ExportComponent.d.ts +0 -9
  44. package/dist/i18n/I18n.d.ts +0 -14
  45. package/dist/index-DCzhFl4v.js +0 -16770
  46. package/dist/index-DCzhFl4v.js.map +0 -1
  47. package/dist/table-contextmenu/TableContextMenu.d.ts +0 -48
  48. package/dist/table-contextmenu/TableContextMenuComponent.d.ts +0 -7
  49. package/dist/utils/clipboard.d.ts +0 -11
  50. package/dist/utils/print.d.ts +0 -7
  51. package/dist/worker/WorkerComponent.d.ts +0 -8
  52. package/dist/worker/WorkerManager.d.ts +0 -21
  53. package/dist/worker/WorkerMessage.d.ts +0 -21
  54. /package/dist/{docxParser/worker/docx.parse.worker.d.ts → workers/editor-worker.d.ts} +0 -0
  55. /package/dist/{worker/runtime.worker.d.ts → workers/thumbnail-worker.d.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor-worker-CG2Et0Mg.js","sources":["../../../plugins/docx-editor-schema/src/constants.ts","../../../node_modules/.pnpm/rfdc@1.4.1/node_modules/rfdc/index.js","../../../plugins/docx-editor-schema/src/walk.ts","../src/workers/compute.ts","../src/workers/editor-worker.ts"],"sourcesContent":["/**\r\n * VerveDocs Schema —— 常量\r\n */\r\n\r\nimport type { IEditorOption } from './types'\r\n\r\n/** 当前 Schema 版本号 */\r\nexport const SCHEMA_VERSION = '4.0.0-tree'\r\n\r\n/** 默认编辑器选项 */\r\nexport const DEFAULT_EDITOR_OPTION: Required<Pick<IEditorOption,\r\n 'defaultFont' | 'defaultSize' | 'defaultLineHeight' | 'defaultRowMargin' |\r\n 'pageMode' | 'pageWidth' | 'pageHeight' | 'pageMargins' | 'scale' | 'devicePixelRatio' |\r\n 'historyMaxRecordCount'\r\n>> = {\r\n defaultFont: 'Microsoft YaHei',\r\n defaultSize: 16,\r\n defaultLineHeight: 1.5,\r\n defaultRowMargin: 5,\r\n pageMode: 'paging',\r\n pageWidth: 794, // A4 @ 96dpi\r\n pageHeight: 1123,\r\n pageMargins: [100, 120, 100, 120],\r\n scale: 1,\r\n devicePixelRatio: typeof window !== 'undefined' ? (window.devicePixelRatio || 1) : 1,\r\n historyMaxRecordCount: 100\r\n}\r\n\r\n/** 段落级属性字段名(用于从 run 上剥离/继承) */\r\nexport const PARAGRAPH_ATTR_KEYS = [\r\n 'rowFlex',\r\n 'paragraphStyleId',\r\n 'paragraphFirstLineIndent',\r\n 'paragraphIndentLeft',\r\n 'paragraphSpacingBefore',\r\n 'paragraphSpacingAfter',\r\n 'lineHeight',\r\n 'lineHeightRule',\r\n 'groupIds'\r\n] as const\r\n\r\n/** 段落容器类型 */\r\nexport const PARAGRAPH_CONTAINER_TYPES = new Set(['title', 'list'])\r\n\r\n/** 段落级块类型(占独立段) */\r\nexport const BLOCK_LEVEL_TYPES = new Set([\r\n 'title', 'list', 'table', 'image', 'pageBreak', 'separator', 'block'\r\n])\r\n\r\n/** 列表类型 */\r\nexport const LIST_TYPE = {\r\n UL: 'ul',\r\n OL: 'ol'\r\n} as const\r\n\r\n/** 列表样式(项目符号 16 种 + 编号格式 13 种,对齐 WPS 全量) */\r\nexport const LIST_STYLE = {\r\n // 项目符号\r\n DISC: 'disc',\r\n CIRCLE: 'circle',\r\n SQUARE: 'square',\r\n EMPTY_SQUARE: 'emptySquare',\r\n FILLED_DIAMOND: 'filledDiamond',\r\n DIAMOND: 'diamond',\r\n ARROW: 'arrow',\r\n ARROW_FILLED: 'arrowFilled',\r\n CHECK: 'check',\r\n CROSS: 'cross',\r\n BULLET: 'bullet',\r\n TRIANGLE: 'triangle',\r\n STAR: 'star',\r\n HEART: 'heart',\r\n DASH: 'dash',\r\n HYPHEN: 'hyphen',\r\n // 编号格式\r\n DECIMAL: 'decimal',\r\n DECIMAL_ZERO: 'decimalZero',\r\n LOWER_LETTER: 'lowerLetter',\r\n UPPER_LETTER: 'upperLetter',\r\n LOWER_ROMAN: 'lowerRoman',\r\n UPPER_ROMAN: 'upperRoman',\r\n CHINESE_COUNTING: 'chineseCounting',\r\n CHINESE_COUNTING_THOUSAND: 'chineseCountingThousand',\r\n IDEOGRAPH_DIGITAL: 'ideographDigital',\r\n JAPANESE_COUNTING: 'japaneseCounting',\r\n KOREAN_COUNTING: 'koreanCounting',\r\n TAIWANESE_COUNTING: 'taiwaneseCounting'\r\n} as const\r\n\r\n/** 段落对齐方式 */\r\nexport const ROW_FLEX = {\r\n LEFT: 'left',\r\n CENTER: 'center',\r\n RIGHT: 'right',\r\n JUSTIFY: 'justify',\r\n ALIGNMENT: 'alignment',\r\n DISTRIBUTE: 'distribute'\r\n} as const\r\n\r\n/** 标题级别 */\r\nexport const TITLE_LEVEL = {\r\n FIRST: 'first',\r\n SECOND: 'second',\r\n THIRD: 'third',\r\n FOURTH: 'fourth',\r\n FIFTH: 'fifth',\r\n SIXTH: 'sixth'\r\n} as const\r\n\r\n/** 字体族常量(对齐 WPS 常用字体,代码内引用用) */\r\nexport const FONT_FAMILY = {\r\n SIM_SUN: 'SimSun',\r\n SIM_HEI: 'SimHei',\r\n KAI_TI: 'KaiTi',\r\n FANG_SONG: 'FangSong',\r\n MICROSOFT_YAHEI: 'Microsoft YaHei',\r\n DENG_XIAN: 'DengXian',\r\n ST_SONG: 'STSong',\r\n ST_HEITI: 'STHeiti',\r\n ST_KAITI: 'STKaiti',\r\n ST_FANGSONG: 'STFangsong',\r\n ST_ZHONGSONG: 'STZhongsong',\r\n ST_XIHEI: 'STXihei',\r\n ST_XINGKAI: 'STXingkai',\r\n ST_LITI: 'STLiti',\r\n ST_XINWEI: 'STXinwei',\r\n ST_CAIYUN: 'STCaiyun',\r\n TIMES_NEW_ROMAN: 'Times New Roman',\r\n ARIAL: 'Arial',\r\n CALIBRI: 'Calibri',\r\n COURIER_NEW: 'Courier New',\r\n VERDANA: 'Verdana'\r\n} as const\r\n\r\n/**\r\n * 字体映射条目(三层结构)\r\n * - label: 显示名(工具栏下拉显示)\r\n * - value: 存储名(文档里存的,WPS/Office 兼容)\r\n * - css: CSS font-family 值(带跨平台 fallback,引用系统字体不侵权 + 开源字体兜底)\r\n * - aliases: 文档里可能存的其他名字(中文名、大小写变体等)\r\n */\r\nexport interface FontFamilyEntry {\r\n label: string\r\n value: string\r\n css: string\r\n aliases?: string[]\r\n}\r\n\r\n/**\r\n * WPS 常用字体完整映射表(16 中文字体 + 5 英文字体)\r\n * CSS fallback 策略:Windows 系统字体 → macOS 对应字体 → 开源字体兜底 → 通用字体族\r\n */\r\nexport const FONT_FAMILY_MAP: FontFamilyEntry[] = [\r\n { label: '宋体', value: 'SimSun', css: '\"SimSun\", \"Songti SC\", \"Noto Serif CJK SC\", serif', aliases: ['宋体', 'simsun'] },\r\n { label: '黑体', value: 'SimHei', css: '\"SimHei\", \"STHeiti\", \"PingFang SC\", \"Noto Sans CJK SC\", sans-serif', aliases: ['黑体', 'simhei'] },\r\n { label: '楷体', value: 'KaiTi', css: '\"KaiTi\", \"Kaiti SC\", \"STKaiti\", \"LXGW WenKai\", serif', aliases: ['楷体', 'kaiti'] },\r\n { label: '仿宋', value: 'FangSong', css: '\"FangSong\", \"STFangsong\", \"Noto Serif CJK SC\", serif', aliases: ['仿宋', 'fangsong'] },\r\n { label: '微软雅黑', value: 'Microsoft YaHei', css: '\"Microsoft YaHei\", \"PingFang SC\", \"Noto Sans CJK SC\", sans-serif', aliases: ['微软雅黑', 'microsoft yahei'] },\r\n { label: '等线', value: 'DengXian', css: '\"DengXian\", \"Noto Sans CJK SC\", sans-serif', aliases: ['等线', 'dengxian'] },\r\n { label: '华文宋体', value: 'STSong', css: '\"STSong\", \"SimSun\", \"Songti SC\", \"Noto Serif CJK SC\", serif', aliases: ['华文宋体'] },\r\n { label: '华文黑体', value: 'STHeiti', css: '\"STHeiti\", \"SimHei\", \"PingFang SC\", \"Noto Sans CJK SC\", sans-serif', aliases: ['华文黑体'] },\r\n { label: '华文楷体', value: 'STKaiti', css: '\"STKaiti\", \"KaiTi\", \"Kaiti SC\", \"LXGW WenKai\", serif', aliases: ['华文楷体'] },\r\n { label: '华文仿宋', value: 'STFangsong', css: '\"STFangsong\", \"FangSong\", \"Noto Serif CJK SC\", serif', aliases: ['华文仿宋'] },\r\n { label: '华文中宋', value: 'STZhongsong', css: '\"STZhongsong\", \"STSong\", \"SimSun\", \"Noto Serif CJK SC\", serif', aliases: ['华文中宋'] },\r\n { label: '华文细黑', value: 'STXihei', css: '\"STXihei\", \"STHeiti\", \"SimHei\", \"Noto Sans CJK SC\", sans-serif', aliases: ['华文细黑'] },\r\n { label: '华文行楷', value: 'STXingkai', css: '\"STXingkai\", \"STKaiti\", \"KaiTi\", \"LXGW WenKai\", serif', aliases: ['华文行楷'] },\r\n { label: '华文隶书', value: 'STLiti', css: '\"STLiti\", \"STFangsong\", \"FangSong\", \"Noto Serif CJK SC\", serif', aliases: ['华文隶书'] },\r\n { label: '华文新魏', value: 'STXinwei', css: '\"STXinwei\", \"STXihei\", \"SimHei\", \"Noto Sans CJK SC\", sans-serif', aliases: ['华文新魏'] },\r\n { label: '华文彩云', value: 'STCaiyun', css: '\"STCaiyun\", \"STSong\", \"SimSun\", \"Noto Serif CJK SC\", serif', aliases: ['华文彩云'] },\r\n { label: 'Times New Roman', value: 'Times New Roman', css: '\"Times New Roman\", \"Liberation Serif\", serif' },\r\n { label: 'Arial', value: 'Arial', css: 'Arial, \"Liberation Sans\", sans-serif' },\r\n { label: 'Calibri', value: 'Calibri', css: 'Calibri, \"Liberation Sans\", sans-serif' },\r\n { label: 'Courier New', value: 'Courier New', css: '\"Courier New\", \"Liberation Mono\", monospace' },\r\n { label: 'Verdana', value: 'Verdana', css: 'Verdana, \"DejaVu Sans\", sans-serif' }\r\n]\r\n\r\n/** 字体下拉选项(显示名列表,有序) */\r\nexport const FONT_FAMILY_LIST: string[] = FONT_FAMILY_MAP.map(e => e.label)\r\n\r\n/** 显示名 → 存储名(工具栏选中后存文档用) */\r\nexport const FONT_FAMILY_VALUE: Record<string, string> = Object.fromEntries(\r\n FONT_FAMILY_MAP.map(e => [e.label, e.value])\r\n)\r\n\r\n/** 存储名/别名 → 显示名(用于回显,认中文名和英文名) */\r\nexport const FONT_FAMILY_LABEL: Record<string, string> = Object.fromEntries(\r\n FONT_FAMILY_MAP.flatMap(e => [\r\n [e.value, e.label],\r\n ...(e.aliases ?? []).map(a => [a, e.label] as [string, string])\r\n ])\r\n)\r\n\r\n/** 存储名/别名 → CSS font-family 值(用于渲染,带跨平台 fallback) */\r\nexport const FONT_FAMILY_CSS: Record<string, string> = Object.fromEntries(\r\n FONT_FAMILY_MAP.flatMap(e => [\r\n [e.value, e.css],\r\n ...(e.aliases ?? []).map(a => [a, e.css] as [string, string])\r\n ])\r\n)\r\n\r\n/**\r\n * WPS 字号表(中文字号名 → pt 值)\r\n * 完整覆盖 WPS 全部预设字号:初号~八号 + 小初~小六\r\n */\r\nexport const FONT_SIZE: Record<string, number> = {\r\n '初号': 42,\r\n '小初': 36,\r\n '一号': 26,\r\n '小一': 24,\r\n '二号': 22,\r\n '小二': 18,\r\n '三号': 16,\r\n '小三': 15,\r\n '四号': 14,\r\n '小四': 12,\r\n '五号': 10.5,\r\n '小五': 9,\r\n '六号': 7.5,\r\n '小六': 6.5,\r\n '七号': 5.5,\r\n '八号': 5\r\n}\r\n\r\n/**\r\n * 字号下拉选项(有序,中文字号 + 常用数字字号)\r\n * WPS 风格:先列中文字号,再列常用数字字号\r\n */\r\nexport const FONT_SIZE_LIST = [\r\n '初号', '小初', '一号', '小一', '二号', '小二', '三号', '小三', '四号', '小四',\r\n '五号', '小五', '六号', '小六', '七号', '八号',\r\n '5', '5.5', '6.5', '7.5', '8', '9', '10', '10.5', '11', '12', '14', '15', '16',\r\n '18', '20', '22', '24', '26', '28', '30', '36', '42', '48', '54', '60', '72'\r\n] as const\r\n\r\n/* ========== 纸张方向 / 表格边框 ========== */\r\n\r\n/** 纸张方向 */\r\nexport const PaperDirection = {\r\n VERTICAL: 'vertical',\r\n HORIZONTAL: 'horizontal'\r\n} as const\r\n\r\n/** 表格边框类型 */\r\nexport const TableBorder = {\r\n NONE: 'none',\r\n OUTSIDE: 'outside',\r\n ALL: 'all',\r\n INSIDE: 'inside',\r\n INSIDE_HORIZONTAL: 'inside-horizontal',\r\n INSIDE_VERTICAL: 'inside-vertical',\r\n TOP: 'top',\r\n BOTTOM: 'bottom',\r\n LEFT: 'left',\r\n RIGHT: 'right'\r\n} as const\r\n\r\nexport type TableBorderPreset = typeof TableBorder[keyof typeof TableBorder]\r\n\r\n/* ========== 单位换算(96 DPI) ========== */\r\n\r\n/** 屏幕 DPI 常量 */\r\nexport const DPI = 96\r\n\r\n/**\r\n * 磅(pt)转像素(px)\r\n * @param pt 磅值\r\n * @returns 像素值(保留两位小数)\r\n */\r\nexport function ptToPx(pt: number): number {\r\n return Math.round(pt * (DPI / 72) * 100) / 100\r\n}\r\n\r\n/**\r\n * 像素(px)转磅(pt)\r\n * @param px 像素值\r\n * @returns 磅值(保留一位小数,0.5 步进)\r\n */\r\nexport function pxToPt(px: number): number {\r\n return Math.round(px * (72 / DPI) * 2) / 2\r\n}\r\n\r\n/* ========== 纸张大小(对齐 WPS/Office,96 DPI) ========== */\r\n\r\nexport interface PaperSize {\r\n /** 纸张标识(唯一 key) */\r\n key: string\r\n /** 显示名称 */\r\n label: string\r\n /** 纸张宽度(px @ 96dpi) */\r\n width: number\r\n /** 纸张高度(px @ 96dpi) */\r\n height: number\r\n /** 分类 */\r\n category: 'a-series' | 'b-series' | 'us' | 'cn' | 'envelope' | 'other'\r\n}\r\n\r\n/**\r\n * WPS/Office 纸张预设列表(覆盖 80%+ 常用纸张)\r\n * 像素值按 96 DPI 换算:px = mm * 96 / 25.4\r\n */\r\nexport const PAPER_SIZE_LIST: PaperSize[] = [\r\n // A 系列(ISO 216)\r\n { key: 'a0', label: 'A0 (84.1×118.9cm)', width: 3179, height: 4494, category: 'a-series' },\r\n { key: 'a1', label: 'A1 (59.4×84.1cm)', width: 2245, height: 3179, category: 'a-series' },\r\n { key: 'a2', label: 'A2 (42×59.4cm)', width: 1587, height: 2245, category: 'a-series' },\r\n { key: 'a3', label: 'A3 (29.7×42cm)', width: 1123, height: 1587, category: 'a-series' },\r\n { key: 'a4', label: 'A4 (21×29.7cm)', width: 794, height: 1123, category: 'a-series' },\r\n { key: 'a5', label: 'A5 (14.8×21cm)', width: 559, height: 794, category: 'a-series' },\r\n { key: 'a6', label: 'A6 (10.5×14.8cm)', width: 397, height: 559, category: 'a-series' },\r\n // B 系列(JIS)\r\n { key: 'b4', label: 'B4 (25.7×36.4cm)', width: 971, height: 1376, category: 'b-series' },\r\n { key: 'b5', label: 'B5 (18.2×25.7cm)', width: 688, height: 971, category: 'b-series' },\r\n { key: 'b6', label: 'B6 (12.8×18.2cm)', width: 484, height: 688, category: 'b-series' },\r\n // 美式\r\n { key: 'letter', label: 'Letter (21.6×27.9cm)', width: 816, height: 1056, category: 'us' },\r\n { key: 'legal', label: 'Legal (21.6×35.6cm)', width: 816, height: 1344, category: 'us' },\r\n { key: 'tabloid', label: 'Tabloid (27.9×43.2cm)', width: 1056, height: 1633, category: 'us' },\r\n { key: 'executive', label: 'Executive (18.4×26.7cm)', width: 696, height: 1009, category: 'us' },\r\n { key: 'statement', label: 'Statement (14×21.6cm)', width: 529, height: 816, category: 'us' },\r\n { key: 'folio', label: 'Folio (21.6×33cm)', width: 816, height: 1247, category: 'us' },\r\n // 中式\r\n { key: '16k', label: '16K (19.5×27cm)', width: 737, height: 1020, category: 'cn' },\r\n { key: '32k', label: '32K (13×19cm)', width: 491, height: 718, category: 'cn' },\r\n { key: '32k-large', label: '大32K (14×20.3cm)', width: 529, height: 767, category: 'cn' },\r\n // 信封\r\n { key: 'env-10', label: '信封 #10 (10.5×24.1cm)', width: 397, height: 910, category: 'envelope' },\r\n { key: 'env-dl', label: '信封 DL (11×22cm)', width: 416, height: 831, category: 'envelope' },\r\n { key: 'env-c5', label: '信封 C5 (16.2×22.9cm)', width: 612, height: 865, category: 'envelope' },\r\n { key: 'env-c6', label: '信封 C6 (11.4×16.2cm)', width: 430, height: 612, category: 'envelope' },\r\n { key: 'env-monarch', label: '信封 Monarch (9.8×19cm)', width: 370, height: 718, category: 'envelope' },\r\n // 其他\r\n { key: 'photo-4x6', label: '照片 4×6 (10.2×15.2cm)', width: 386, height: 574, category: 'other' },\r\n { key: 'postcard', label: '明信片 (10×14.8cm)', width: 378, height: 559, category: 'other' }\r\n]\r\n\r\n/** 默认纸张大小(A4) */\r\nexport const DEFAULT_PAPER_SIZE: PaperSize = PAPER_SIZE_LIST[4]\r\n\r\n/* ========== 项目符号 / 编号样式 ========== */\r\n\r\n/** 项目符号样式 */\r\nexport const BULLET_STYLES = [\r\n { style: 'disc', icon: '●', label: '实心圆点' },\r\n { style: 'circle', icon: '○', label: '空心圆点' },\r\n { style: 'square', icon: '■', label: '实心方块' },\r\n { style: 'hollow-square', icon: '□', label: '空心方块' },\r\n { style: 'diamond', icon: '◆', label: '实心菱形' },\r\n { style: 'hollow-diamond', icon: '◇', label: '空心菱形' },\r\n { style: 'arrow', icon: '▶', label: '箭头' },\r\n { style: 'check', icon: '✓', label: '对勾' }\r\n]\r\n\r\n/** 编号样式 */\r\nexport const NUMBER_STYLES = [\r\n { style: 'decimal', numFmt: 'decimal', lvlText: '%1.', samples: ['1.', '2.', '3.'], label: '阿拉伯数字' },\r\n { style: 'decimal-bracket', numFmt: 'decimal', lvlText: '%1)', samples: ['1)', '2)', '3)'], label: '数字右括号' },\r\n { style: 'decimal-paren', numFmt: 'decimal', lvlText: '(%1)', samples: ['(1)', '(2)', '(3)'], label: '数字括号' },\r\n { style: 'upper-alpha', numFmt: 'upperLetter', lvlText: '%1.', samples: ['A.', 'B.', 'C.'], label: '大写字母' },\r\n { style: 'lower-alpha-dot', numFmt: 'lowerLetter', lvlText: '%1.', samples: ['a.', 'b.', 'c.'], label: '小写字母' },\r\n { style: 'chinese', numFmt: 'chineseCounting', lvlText: '%1、', samples: ['一、', '二、', '三、'], label: '中文数字' },\r\n { style: 'chinese-bracket', numFmt: 'chineseCounting', lvlText: '(%1)', samples: ['(一)', '(二)', '(三)'], label: '中文括号' },\r\n { style: 'decimal-circle', numFmt: 'decimalEnclosedCircle', lvlText: '%1', samples: ['①', '②', '③'], label: '圈码' }\r\n]\r\n\r\n/* ========== 行距 / 页边距 / 缩放 ========== */\r\n\r\n/** 行距选项 */\r\nexport const LINE_HEIGHT_OPTIONS = [\r\n { value: 1, label: '单倍行距' },\r\n { value: 1.15, label: '1.15 倍行距' },\r\n { value: 1.5, label: '1.5 倍行距' },\r\n { value: 2, label: '双倍行距' },\r\n { value: 2.5, label: '2.5 倍行距' },\r\n { value: 3, label: '三倍行距' }\r\n]\r\n\r\n/** 页边距预设 */\r\nexport const MARGIN_PRESETS = [\r\n { name: '普通', margins: [96, 120, 96, 120], style: { margin: '14px 18px' } },\r\n { name: '窄', margins: [48, 48, 48, 48], style: { margin: '7px 7px' } },\r\n { name: '适中', margins: [96, 72, 96, 72], style: { margin: '14px 11px' } },\r\n { name: '宽', margins: [96, 192, 96, 192], style: { margin: '14px 28px' } }\r\n]\r\n\r\n/** 缩放级别 */\r\nexport const ZOOM_LEVELS = [50, 75, 100, 125, 150, 200]\r\n\r\n/* ========== 分割线样式 ========== */\r\n\r\n/** 分割线样式 */\r\nexport const SEPARATOR_STYLES = [\r\n { name: '极细实线', type: 'solid', width: 0.5, dashArray: [0, 0] },\r\n { name: '细实线', type: 'solid', width: 1, dashArray: [0, 0] },\r\n { name: '中实线', type: 'solid', width: 2, dashArray: [0, 0] },\r\n { name: '粗实线', type: 'solid', width: 3, dashArray: [0, 0] },\r\n { name: '特粗实线', type: 'solid', width: 4, dashArray: [0, 0] },\r\n { name: '细点线', type: 'dotted', width: 0.5, dashArray: [1, 1] },\r\n { name: '点线', type: 'dotted', width: 1, dashArray: [1, 1] },\r\n { name: '粗点线', type: 'dotted', width: 2, dashArray: [1, 1] },\r\n { name: '大点线', type: 'dotted', width: 3, dashArray: [2, 2] },\r\n { name: '细短虚线', type: 'dashed', width: 0.5, dashArray: [3, 2] },\r\n { name: '短虚线', type: 'dashed', width: 1, dashArray: [3, 2] },\r\n { name: '粗短虚线', type: 'dashed', width: 2, dashArray: [3, 2] },\r\n { name: '细长虚线', type: 'dashed', width: 0.5, dashArray: [6, 3] },\r\n { name: '长虚线', type: 'dashed', width: 1, dashArray: [6, 3] },\r\n { name: '粗长虚线', type: 'dashed', width: 2, dashArray: [6, 3] },\r\n { name: '特长虚线', type: 'dashed', width: 1, dashArray: [10, 5] },\r\n { name: '点划线', type: 'dashed', width: 1, dashArray: [6, 2, 1, 2] },\r\n { name: '粗点划线', type: 'dashed', width: 2, dashArray: [6, 2, 1, 2] },\r\n { name: '双点划线', type: 'dashed', width: 1, dashArray: [6, 2, 1, 2, 1, 2] },\r\n { name: '粗双点划线', type: 'dashed', width: 2, dashArray: [6, 2, 1, 2, 1, 2] },\r\n { name: '细双线', type: 'double', width: 2, dashArray: [0, 0] },\r\n { name: '双线', type: 'double', width: 3, dashArray: [0, 0] },\r\n { name: '粗双线', type: 'double', width: 4, dashArray: [0, 0] },\r\n { name: '特粗双线', type: 'double', width: 5, dashArray: [0, 0] },\r\n { name: '三线', type: 'triple', width: 4, dashArray: [0, 0] },\r\n { name: '细波浪线', type: 'wavy', width: 0.5, dashArray: [0, 0] },\r\n { name: '波浪线', type: 'wavy', width: 1, dashArray: [0, 0] },\r\n { name: '粗波浪线', type: 'wavy', width: 2, dashArray: [0, 0] },\r\n { name: '渐变线', type: 'gradient', width: 2, dashArray: [0, 0] },\r\n { name: '阴影线', type: 'shadow', width: 2, dashArray: [0, 0] },\r\n { name: '浮雕线', type: 'emboss', width: 3, dashArray: [0, 0] }\r\n]\r\n\r\n/* ========== 标题级别映射 ========== */\r\n\r\n/** 标题级别映射 */\r\nexport const TITLE_LEVEL_MAP: Record<string, string> = {\r\n first: '标题1',\r\n second: '标题2',\r\n third: '标题3',\r\n fourth: '标题4',\r\n fifth: '标题5',\r\n sixth: '标题6'\r\n}\r\n","'use strict'\nmodule.exports = rfdc\n\nfunction copyBuffer (cur) {\n if (cur instanceof Buffer) {\n return Buffer.from(cur)\n }\n\n return new cur.constructor(cur.buffer.slice(), cur.byteOffset, cur.length)\n}\n\nfunction rfdc (opts) {\n opts = opts || {}\n if (opts.circles) return rfdcCircles(opts)\n\n const constructorHandlers = new Map()\n constructorHandlers.set(Date, (o) => new Date(o))\n constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)))\n constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)))\n if (opts.constructorHandlers) {\n for (const handler of opts.constructorHandlers) {\n constructorHandlers.set(handler[0], handler[1])\n }\n }\n\n let handler = null\n\n return opts.proto ? cloneProto : clone\n\n function cloneArray (a, fn) {\n const keys = Object.keys(a)\n const a2 = new Array(keys.length)\n for (let i = 0; i < keys.length; i++) {\n const k = keys[i]\n const cur = a[k]\n if (typeof cur !== 'object' || cur === null) {\n a2[k] = cur\n } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {\n a2[k] = handler(cur, fn)\n } else if (ArrayBuffer.isView(cur)) {\n a2[k] = copyBuffer(cur)\n } else {\n a2[k] = fn(cur)\n }\n }\n return a2\n }\n\n function clone (o) {\n if (typeof o !== 'object' || o === null) return o\n if (Array.isArray(o)) return cloneArray(o, clone)\n if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {\n return handler(o, clone)\n }\n const o2 = {}\n for (const k in o) {\n if (Object.hasOwnProperty.call(o, k) === false) continue\n const cur = o[k]\n if (typeof cur !== 'object' || cur === null) {\n o2[k] = cur\n } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {\n o2[k] = handler(cur, clone)\n } else if (ArrayBuffer.isView(cur)) {\n o2[k] = copyBuffer(cur)\n } else {\n o2[k] = clone(cur)\n }\n }\n return o2\n }\n\n function cloneProto (o) {\n if (typeof o !== 'object' || o === null) return o\n if (Array.isArray(o)) return cloneArray(o, cloneProto)\n if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {\n return handler(o, cloneProto)\n }\n const o2 = {}\n for (const k in o) {\n const cur = o[k]\n if (typeof cur !== 'object' || cur === null) {\n o2[k] = cur\n } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {\n o2[k] = handler(cur, cloneProto)\n } else if (ArrayBuffer.isView(cur)) {\n o2[k] = copyBuffer(cur)\n } else {\n o2[k] = cloneProto(cur)\n }\n }\n return o2\n }\n}\n\nfunction rfdcCircles (opts) {\n const refs = []\n const refsNew = []\n\n const constructorHandlers = new Map()\n constructorHandlers.set(Date, (o) => new Date(o))\n constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)))\n constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)))\n if (opts.constructorHandlers) {\n for (const handler of opts.constructorHandlers) {\n constructorHandlers.set(handler[0], handler[1])\n }\n }\n\n let handler = null\n return opts.proto ? cloneProto : clone\n\n function cloneArray (a, fn) {\n const keys = Object.keys(a)\n const a2 = new Array(keys.length)\n for (let i = 0; i < keys.length; i++) {\n const k = keys[i]\n const cur = a[k]\n if (typeof cur !== 'object' || cur === null) {\n a2[k] = cur\n } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {\n a2[k] = handler(cur, fn)\n } else if (ArrayBuffer.isView(cur)) {\n a2[k] = copyBuffer(cur)\n } else {\n const index = refs.indexOf(cur)\n if (index !== -1) {\n a2[k] = refsNew[index]\n } else {\n a2[k] = fn(cur)\n }\n }\n }\n return a2\n }\n\n function clone (o) {\n if (typeof o !== 'object' || o === null) return o\n if (Array.isArray(o)) return cloneArray(o, clone)\n if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {\n return handler(o, clone)\n }\n const o2 = {}\n refs.push(o)\n refsNew.push(o2)\n for (const k in o) {\n if (Object.hasOwnProperty.call(o, k) === false) continue\n const cur = o[k]\n if (typeof cur !== 'object' || cur === null) {\n o2[k] = cur\n } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {\n o2[k] = handler(cur, clone)\n } else if (ArrayBuffer.isView(cur)) {\n o2[k] = copyBuffer(cur)\n } else {\n const i = refs.indexOf(cur)\n if (i !== -1) {\n o2[k] = refsNew[i]\n } else {\n o2[k] = clone(cur)\n }\n }\n }\n refs.pop()\n refsNew.pop()\n return o2\n }\n\n function cloneProto (o) {\n if (typeof o !== 'object' || o === null) return o\n if (Array.isArray(o)) return cloneArray(o, cloneProto)\n if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {\n return handler(o, cloneProto)\n }\n const o2 = {}\n refs.push(o)\n refsNew.push(o2)\n for (const k in o) {\n const cur = o[k]\n if (typeof cur !== 'object' || cur === null) {\n o2[k] = cur\n } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {\n o2[k] = handler(cur, cloneProto)\n } else if (ArrayBuffer.isView(cur)) {\n o2[k] = copyBuffer(cur)\n } else {\n const i = refs.indexOf(cur)\n if (i !== -1) {\n o2[k] = refsNew[i]\n } else {\n o2[k] = cloneProto(cur)\n }\n }\n }\n refs.pop()\n refsNew.pop()\n return o2\n }\n}\n","\r\n/**\r\n * VerveDocs Schema —— 树遍历与路径寻址\r\n *\r\n * 所有遍历严格保持树形语义,不做扁平化。\r\n */\r\n\r\nimport rfdc from 'rfdc'\r\nimport type { IElement, Path, PathSegment, IPosition, ITableElement, ITd, ITr } from './types'\r\n\r\n/* -------------------- 深拷贝 -------------------- */\r\n\r\n/** rfdc 深拷贝实例(关闭原型拷贝与循环引用检测以提升性能) */\r\nconst _clone = rfdc({ proto: false, circles: false })\r\n\r\n/**\r\n * 深拷贝树节点。\r\n * @param node 待拷贝的节点\r\n * @returns 拷贝后的新节点(基本类型直接返回)\r\n */\r\nexport function cloneTree<T>(node: T): T {\r\n if (node === null || typeof node !== 'object') return node\r\n return _clone(node)\r\n}\r\n\r\n/* -------------------- 类型守卫 -------------------- */\r\n\r\n/**\r\n * 判断元素是否为段落容器(title/list 且拥有 valueList 数组)。\r\n * @param el 待判断元素\r\n * @returns 是段落容器则返回 true,并收窄类型\r\n */\r\nexport function isParagraphContainer(el: IElement): el is IElement & { valueList: IElement[] } {\r\n return (el?.type === 'title' || el?.type === 'list') && Array.isArray((el as { valueList?: unknown }).valueList)\r\n}\r\n\r\n/**\r\n * 判断元素是否为表格(type='table' 且拥有 trList 数组)。\r\n * @param el 待判断元素\r\n * @returns 是表格则返回 true,并收窄类型\r\n */\r\nexport function isTable(el: IElement): el is ITableElement {\r\n return el?.type === 'table' && Array.isArray((el as ITableElement).trList)\r\n}\r\n\r\n/* -------------------- 访问器 -------------------- */\r\n\r\n/** 遍历上下文:携带父节点、路径与索引信息 */\r\nexport interface VisitContext {\r\n /** 父节点(数组或单个元素,根数组时为 null) */\r\n parent: IElement[] | IElement | null\r\n /** 当前节点路径 */\r\n path: Path\r\n /** 在父容器中的索引 */\r\n index: number\r\n}\r\n\r\n/** 访问者函数类型:返回 false 可跳过当前节点的子树 */\r\nexport type Visitor = (node: IElement, ctx: VisitContext) => void | boolean\r\n\r\n/**\r\n * 深度优先遍历(返回 false 可跳过子树)。\r\n * 遍历顺序:elements[i] → 若为段落容器则 valueList[i];若为 table 则 trList[j].tdList[k].value[m]。\r\n */\r\nexport function walkTree(elements: IElement[], visitor: Visitor, parentPath: Path = []): void {\r\n for (let i = 0; i < elements.length; i++) {\r\n const node = elements[i]\r\n const path: Path = [...parentPath, i]\r\n const shouldDescend = visitor(node, { parent: elements, path, index: i })\r\n if (shouldDescend === false) continue\r\n\r\n if (isParagraphContainer(node)) {\r\n walkTree(node.valueList, visitor, [...path, 'valueList'])\r\n } else if (isTable(node)) {\r\n for (let tr = 0; tr < node.trList.length; tr++) {\r\n const row = node.trList[tr]\r\n for (let td = 0; td < row.tdList.length; td++) {\r\n const cell = row.tdList[td]\r\n walkTree(cell.value, visitor, [...path, 'trList', tr, 'tdList', td, 'value'])\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/* -------------------- 路径寻址 -------------------- */\r\n\r\n/**\r\n * 根据路径获取节点。\r\n * 路径示例:\r\n * [3] → elements[3]\r\n * [3, 'valueList', 1] → elements[3].valueList[1]\r\n * [5, 'trList', 0, 'tdList', 2, 'value', 1] → table 第 0 行第 2 单元格第 1 子元素\r\n */\r\nexport function getByPath(root: IElement[], path: Path): IElement | null {\r\n if (path.length === 0) return null\r\n let current: unknown = root\r\n for (const seg of path) {\r\n if (current == null) return null\r\n if (typeof seg === 'number') {\r\n if (!Array.isArray(current)) return null\r\n current = current[seg]\r\n } else {\r\n current = (current as Record<string, unknown>)[seg]\r\n }\r\n }\r\n return (current as IElement) ?? null\r\n}\r\n\r\n/**\r\n * 获取路径末段对应的父容器数组。\r\n * @param root 根元素数组\r\n * @param path 目标路径\r\n * @returns 父容器数组;若路径非法或末段不是数组索引则返回 null\r\n */\r\nexport function getParentContainer(root: IElement[], path: Path): IElement[] | null {\r\n if (path.length === 0) return null\r\n const parentPath = path.slice(0, -1)\r\n const lastSeg = path[path.length - 1]\r\n if (typeof lastSeg !== 'number') return null // 末段必须是数组索引\r\n if (parentPath.length === 0) return root\r\n let current: unknown = root\r\n for (const seg of parentPath) {\r\n if (typeof seg === 'number') {\r\n if (!Array.isArray(current)) return null\r\n current = current[seg]\r\n } else {\r\n current = (current as Record<string, unknown>)[seg]\r\n }\r\n }\r\n return Array.isArray(current) ? (current as IElement[]) : null\r\n}\r\n\r\n/**\r\n * 在路径指定位置替换节点。\r\n * @param root 根元素数组\r\n * @param path 目标路径\r\n * @param node 新节点\r\n * @returns 替换成功返回 true,路径非法返回 false\r\n */\r\nexport function replaceAtPath(root: IElement[], path: Path, node: IElement): boolean {\r\n const parent = getParentContainer(root, path)\r\n if (!parent) return false\r\n const idx = path[path.length - 1] as number\r\n parent[idx] = node\r\n return true\r\n}\r\n\r\n/**\r\n * 在路径指定位置插入节点(插入到该索引前)。\r\n * @param root 根元素数组\r\n * @param path 目标路径\r\n * @param node 待插入节点\r\n * @returns 插入成功返回 true,路径非法返回 false\r\n */\r\nexport function insertAtPath(root: IElement[], path: Path, node: IElement): boolean {\r\n const parent = getParentContainer(root, path)\r\n if (!parent) return false\r\n const idx = path[path.length - 1] as number\r\n parent.splice(idx, 0, node)\r\n return true\r\n}\r\n\r\n/**\r\n * 移除路径指定位置的节点。\r\n * @param root 根元素数组\r\n * @param path 目标路径\r\n * @returns 被移除的节点;路径非法返回 null\r\n */\r\nexport function removeAtPath(root: IElement[], path: Path): IElement | null {\r\n const parent = getParentContainer(root, path)\r\n if (!parent) return null\r\n const idx = path[path.length - 1] as number\r\n const [removed] = parent.splice(idx, 1)\r\n return removed ?? null\r\n}\r\n\r\n/* -------------------- 位置工具 -------------------- */\r\n\r\n/**\r\n * 判断两条路径是否完全相同。\r\n * @param a 路径 a\r\n * @param b 路径 b\r\n * @returns 相同返回 true\r\n */\r\nexport function isSamePath(a: Path, b: Path): boolean {\r\n if (a.length !== b.length) return false\r\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false\r\n return true\r\n}\r\n\r\n/**\r\n * 比较两条路径的字典序(数字段按数值比较,字符串段按字符串比较)。\r\n * @param a 路径 a\r\n * @param b 路径 b\r\n * @returns a<b 返回负数,a=b 返回 0,a>b 返回正数\r\n */\r\nexport function comparePath(a: Path, b: Path): number {\r\n const n = Math.min(a.length, b.length)\r\n for (let i = 0; i < n; i++) {\r\n const av = a[i]; const bv = b[i]\r\n if (av === bv) continue\r\n if (typeof av === 'number' && typeof bv === 'number') return av - bv\r\n return String(av) < String(bv) ? -1 : 1\r\n }\r\n return a.length - b.length\r\n}\r\n\r\n/**\r\n * 比较两个文档位置:先比较路径,路径相同再比较 offset。\r\n * @param a 位置 a\r\n * @param b 位置 b\r\n * @returns a<b 返回负数,a=b 返回 0,a>b 返回正数\r\n */\r\nexport function comparePosition(a: IPosition, b: IPosition): number {\r\n const c = comparePath(a.path, b.path)\r\n if (c !== 0) return c\r\n return a.offset - b.offset\r\n}\r\n\r\n/* -------------------- 表格辅助 -------------------- */\r\n\r\n/**\r\n * 遍历表格所有单元格,对每个单元格调用回调。\r\n * @param table 表格元素\r\n * @param fn 回调函数,接收单元格、行、行索引、列索引\r\n */\r\nexport function forEachCell(\r\n table: ITableElement,\r\n fn: (cell: ITd, tr: ITr, trIndex: number, tdIndex: number) => void\r\n) {\r\n for (let i = 0; i < table.trList.length; i++) {\r\n const row = table.trList[i]\r\n for (let j = 0; j < row.tdList.length; j++) {\r\n fn(row.tdList[j], row, i, j)\r\n }\r\n }\r\n}\r\n\r\n/** 计算表格列数(不考虑合并) */\r\nexport function getTableColCount(table: ITableElement): number {\r\n if (Array.isArray(table.colgroup)) return table.colgroup.length\r\n return table.trList[0]?.tdList.reduce((sum, td) => sum + (td.colspan || 1), 0) ?? 0\r\n}\r\n\r\n/** 计算某段路径所在的段落容器(title/list/纯段落用父数组表示) */\r\nexport function _pathSegAsKey(seg: PathSegment): string {\r\n return typeof seg === 'number' ? String(seg) : seg\r\n}\r\n","import { walkTree } from '@vervedoc/docx-editor-schema'\r\nimport type { IElement, ITitleElement, ITextElement, PathSegment } from '@vervedoc/docx-editor-schema'\r\n\r\nconst levelMap: Record<string, number> = { first: 1, second: 2, third: 3, fourth: 4, fifth: 5, sixth: 6 }\r\n\r\nexport function computeToc(elements: IElement[]) {\r\n const toc: { id: string; level: number; name: string; number?: string }[] = []\r\n const counters = new Map<string, number>()\r\n walkTree(elements, (node, ctx) => {\r\n if (node.type !== 'title') return\r\n const t = node as ITitleElement\r\n const name = (t.valueList ?? []).map(v => v.type === 'text' ? (v as ITextElement).value : '').join('')\r\n const level = levelMap[t.level] ?? 1\r\n let number: string | undefined\r\n const num = (t as unknown as { listNumbering?: { numFmt: string; lvlText: string; start: number; numId?: string; abstractNumId?: string; level?: number } }).listNumbering\r\n if (num && num.numFmt !== 'bullet') {\r\n const numId = num.numId ?? num.abstractNumId ?? 'default'\r\n const numLevel = num.level ?? 0\r\n const key = `${numId}:${numLevel}`\r\n const prev = counters.get(key)\r\n const current = (prev == null ? (num.start ?? 1) - 1 : prev) + 1\r\n counters.set(key, current)\r\n for (const k of counters.keys()) {\r\n if (k.startsWith(`${numId}:`) && Number(k.slice(numId.length + 1)) > numLevel) counters.delete(k)\r\n }\r\n number = (num.lvlText ?? '%1.').replace(/%([1-9])/g, (_, d: string) => {\r\n const lvl = Number(d) - 1\r\n return String(lvl === numLevel ? current : counters.get(`${numId}:${lvl}`) ?? (num.start ?? 1))\r\n })\r\n }\r\n toc.push({ id: JSON.stringify(ctx.path), level, name, number })\r\n })\r\n return { toc }\r\n}\r\n\r\nexport function computeSearch(elements: IElement[], keyword: string) {\r\n const results: { path: PathSegment[]; offset: number; length: number }[] = []\r\n if (!keyword) return { results, count: 0 }\r\n const lowerKeyword = keyword.toLowerCase()\r\n walkTree(elements, (node, ctx) => {\r\n if (node.type !== 'text') return\r\n const text = ((node as ITextElement).value || '').toLowerCase()\r\n let idx = text.indexOf(lowerKeyword)\r\n while (idx !== -1) {\r\n results.push({ path: [...ctx.path], offset: idx, length: keyword.length })\r\n idx = text.indexOf(lowerKeyword, idx + 1)\r\n }\r\n })\r\n return { results, count: results.length }\r\n}\r\n","/// <reference lib=\"webworker\" />\r\nimport { cloneTree } from '@vervedoc/docx-editor-schema'\r\nimport type { IElement } from '@vervedoc/docx-editor-schema'\r\nimport { computeToc, computeSearch } from './compute'\r\n\r\ntype WorkerRequest =\r\n | { type: 'update'; elements: IElement[] }\r\n | { type: 'search'; keyword: string }\r\n | { type: 'clone'; data: unknown }\r\n\r\nlet currentElements: IElement[] = []\r\nself.onmessage = (e: MessageEvent<WorkerRequest>): void => {\r\n try {\r\n const req = e.data\r\n switch (req.type) {\r\n case 'update':\r\n currentElements = req.elements\r\n self.postMessage({ type: 'toc-result', ...computeToc(currentElements) })\r\n break\r\n case 'search':\r\n self.postMessage({ type: 'search-result', ...computeSearch(currentElements, req.keyword) })\r\n break\r\n case 'clone':\r\n self.postMessage({ type: 'clone-result', data: cloneTree(req.data) })\r\n break\r\n }\r\n } catch (error: any) {\r\n self.postMessage({ type: 'error', message: error?.message || String(error) })\r\n }\r\n}\r\n"],"names":["FONT_FAMILY_MAP","e","a","rfdc_1","rfdc","copyBuffer","cur","opts","rfdcCircles","constructorHandlers","o","fn","cloneArray","handler","cloneProto","clone","keys","a2","i","k","o2","refs","refsNew","index","_clone","cloneTree","node","isParagraphContainer","el","isTable","walkTree","elements","visitor","parentPath","path","tr","row","td","cell","levelMap","computeToc","toc","counters","ctx","t","name","v","level","number","num","numId","numLevel","key","prev","current","_","d","lvl","computeSearch","keyword","results","lowerKeyword","text","idx","currentElements","req","error"],"mappings":"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","x_google_ignoreList":[1]}
@@ -0,0 +1,52 @@
1
+ let p = [], t = null, g = !1;
2
+ const l = /* @__PURE__ */ new Map(), w = new FileReaderSync();
3
+ self.onmessage = (n) => {
4
+ const s = n.data;
5
+ s.sources && (p = s.sources), t = { ...s, sources: p }, y();
6
+ };
7
+ async function y() {
8
+ if (!g) {
9
+ g = !0;
10
+ try {
11
+ for (; t; ) {
12
+ const n = t;
13
+ t = null;
14
+ const s = [];
15
+ try {
16
+ const o = n.sources;
17
+ for (const [e, i] of l)
18
+ o[e] !== i.source && (i.bitmap.close(), l.delete(e));
19
+ for (let e = 0; e < o.length && !t; e++) {
20
+ const i = o[e];
21
+ if (!i) {
22
+ s.push("");
23
+ continue;
24
+ }
25
+ let r = l.get(e);
26
+ if (!r) {
27
+ const m = await (await fetch(i)).blob();
28
+ let a = await createImageBitmap(m);
29
+ if (a.width > 360) {
30
+ const h = Math.max(1, Math.round(a.height * 360 / a.width)), u = new OffscreenCanvas(360, h);
31
+ u.getContext("2d").drawImage(a, 0, 0, 360, h), a.close(), a = u.transferToImageBitmap();
32
+ }
33
+ r = { source: i, bitmap: a }, l.set(e, r);
34
+ }
35
+ if (t) break;
36
+ const { bitmap: f } = r, c = new OffscreenCanvas(f.width, f.height), d = c.getContext("2d");
37
+ d.fillStyle = n.color, d.fillRect(0, 0, c.width, c.height), d.drawImage(f, 0, 0);
38
+ const b = await c.convertToBlob({ type: "image/png" });
39
+ if (t) break;
40
+ s.push(w.readAsDataURL(b));
41
+ }
42
+ t || self.postMessage({ id: n.id, images: s });
43
+ } catch (o) {
44
+ self.postMessage({ id: n.id, error: String(o) });
45
+ }
46
+ }
47
+ } finally {
48
+ g = !1;
49
+ }
50
+ }
51
+ }
52
+ //# sourceMappingURL=thumbnail-worker-BGjZ82h0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thumbnail-worker-BGjZ82h0.js","sources":["../src/workers/thumbnail-worker.ts"],"sourcesContent":["/// <reference lib=\"webworker\" />\r\nexport {}\r\n\r\ntype Request = { id: number; color: string; sources?: string[] }\r\nlet sources: string[] = []\r\nlet pending: (Request & { sources: string[] }) | null = null\r\nlet running = false\r\nconst bitmaps = new Map<number, { source: string; bitmap: ImageBitmap }>()\r\nconst reader = new FileReaderSync()\r\n\r\nself.onmessage = (event: MessageEvent<Request>) => {\r\n const request = event.data\r\n if (request.sources) sources = request.sources\r\n pending = { ...request, sources }\r\n void drain()\r\n}\r\n\r\nasync function drain(): Promise<void> {\r\n if (running) return\r\n running = true\r\n try {\r\n while (pending) {\r\n const request = pending\r\n pending = null\r\n const images: string[] = []\r\n try {\r\n const snapshot = request.sources\r\n for (const [index, entry] of bitmaps) {\r\n if (snapshot[index] !== entry.source) {\r\n entry.bitmap.close()\r\n bitmaps.delete(index)\r\n }\r\n }\r\n for (let index = 0; index < snapshot.length; index++) {\r\n if (pending) break\r\n const source = snapshot[index]\r\n if (!source) { images.push(''); continue }\r\n let entry = bitmaps.get(index)\r\n if (!entry) {\r\n const blob = await (await fetch(source)).blob()\r\n let bitmap = await createImageBitmap(blob)\r\n if (bitmap.width > 360) {\r\n const height = Math.max(1, Math.round(bitmap.height * 360 / bitmap.width))\r\n const resized = new OffscreenCanvas(360, height)\r\n resized.getContext('2d')!.drawImage(bitmap, 0, 0, 360, height)\r\n bitmap.close()\r\n bitmap = resized.transferToImageBitmap()\r\n }\r\n entry = { source, bitmap }\r\n bitmaps.set(index, entry)\r\n }\r\n if (pending) break\r\n const { bitmap } = entry\r\n const canvas = new OffscreenCanvas(bitmap.width, bitmap.height)\r\n const ctx = canvas.getContext('2d')!\r\n ctx.fillStyle = request.color\r\n ctx.fillRect(0, 0, canvas.width, canvas.height)\r\n ctx.drawImage(bitmap, 0, 0)\r\n const blob = await canvas.convertToBlob({ type: 'image/png' })\r\n if (pending) break\r\n images.push(reader.readAsDataURL(blob))\r\n }\r\n if (!pending) self.postMessage({ id: request.id, images })\r\n } catch (error) {\r\n self.postMessage({ id: request.id, error: String(error) })\r\n }\r\n }\r\n } finally {\r\n running = false\r\n }\r\n}\r\n"],"names":["sources","pending","running","bitmaps","reader","event","request","drain","images","snapshot","index","entry","source","blob","bitmap","height","resized","canvas","ctx","error"],"mappings":"AAIA,IAAIA,IAAoB,CAAA,GACpBC,IAAoD,MACpDC,IAAU;AACd,MAAMC,wBAAc,IAAA,GACdC,IAAS,IAAI,eAAA;AAEnB,KAAK,YAAY,CAACC,MAAiC;AACjD,QAAMC,IAAUD,EAAM;AACtB,EAAIC,EAAQ,YAASN,IAAUM,EAAQ,UACvCL,IAAU,EAAE,GAAGK,GAAS,SAAAN,EAAA,GACnBO,EAAA;AACP;AAEA,eAAeA,IAAuB;AACpC,MAAI,CAAAL,GACJ;AAAA,IAAAA,IAAU;AACV,QAAI;AACF,aAAOD,KAAS;AACd,cAAMK,IAAUL;AAChB,QAAAA,IAAU;AACV,cAAMO,IAAmB,CAAA;AACzB,YAAI;AACF,gBAAMC,IAAWH,EAAQ;AACzB,qBAAW,CAACI,GAAOC,CAAK,KAAKR;AAC3B,YAAIM,EAASC,CAAK,MAAMC,EAAM,WAC5BA,EAAM,OAAO,MAAA,GACbR,EAAQ,OAAOO,CAAK;AAGxB,mBAASA,IAAQ,GAAGA,IAAQD,EAAS,UAC/B,CAAAR,GADuCS,KAAS;AAEpD,kBAAME,IAASH,EAASC,CAAK;AAC7B,gBAAI,CAACE,GAAQ;AAAE,cAAAJ,EAAO,KAAK,EAAE;AAAG;AAAA,YAAS;AACzC,gBAAIG,IAAQR,EAAQ,IAAIO,CAAK;AAC7B,gBAAI,CAACC,GAAO;AACV,oBAAME,IAAO,OAAO,MAAM,MAAMD,CAAM,GAAG,KAAA;AACzC,kBAAIE,IAAS,MAAM,kBAAkBD,CAAI;AACzC,kBAAIC,EAAO,QAAQ,KAAK;AACtB,sBAAMC,IAAS,KAAK,IAAI,GAAG,KAAK,MAAMD,EAAO,SAAS,MAAMA,EAAO,KAAK,CAAC,GACnEE,IAAU,IAAI,gBAAgB,KAAKD,CAAM;AAC/C,gBAAAC,EAAQ,WAAW,IAAI,EAAG,UAAUF,GAAQ,GAAG,GAAG,KAAKC,CAAM,GAC7DD,EAAO,MAAA,GACPA,IAASE,EAAQ,sBAAA;AAAA,cACnB;AACA,cAAAL,IAAQ,EAAE,QAAAC,GAAQ,QAAAE,EAAAA,GAClBX,EAAQ,IAAIO,GAAOC,CAAK;AAAA,YAC1B;AACA,gBAAIV,EAAS;AACb,kBAAM,EAAE,QAAAa,MAAWH,GACbM,IAAS,IAAI,gBAAgBH,EAAO,OAAOA,EAAO,MAAM,GACxDI,IAAMD,EAAO,WAAW,IAAI;AAClC,YAAAC,EAAI,YAAYZ,EAAQ,OACxBY,EAAI,SAAS,GAAG,GAAGD,EAAO,OAAOA,EAAO,MAAM,GAC9CC,EAAI,UAAUJ,GAAQ,GAAG,CAAC;AAC1B,kBAAMD,IAAO,MAAMI,EAAO,cAAc,EAAE,MAAM,aAAa;AAC7D,gBAAIhB,EAAS;AACb,YAAAO,EAAO,KAAKJ,EAAO,cAAcS,CAAI,CAAC;AAAA,UACxC;AACA,UAAKZ,KAAS,KAAK,YAAY,EAAE,IAAIK,EAAQ,IAAI,QAAAE,GAAQ;AAAA,QAC3D,SAASW,GAAO;AACd,eAAK,YAAY,EAAE,IAAIb,EAAQ,IAAI,OAAO,OAAOa,CAAK,GAAG;AAAA,QAC3D;AAAA,MACF;AAAA,IACF,UAAA;AACE,MAAAjB,IAAU;AAAA,IACZ;AAAA;AACF;"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * 命令分发责任链(Chain of Responsibility)
3
+ *
4
+ * 将命令分发从 if-else 硬编码改为可插拔的 handler 链。
5
+ * 每个 handler 决定是否处理命令,或调 next() 传递给下一个 handler。
6
+ * 支持运行时插入中间件(日志/权限/撤销重做等)而不侵入核心逻辑。
7
+ */
8
+ /** 传递给下一个 handler 的函数,调 next() 表示"我不处理,交给下一个" */
9
+ export type CommandNext = () => any;
10
+ /** 命令处理器:(command, args, next) → result | next() */
11
+ export type CommandHandler = (command: string, args: any[], next: CommandNext) => any;
12
+ /**
13
+ * 命令责任链。
14
+ *
15
+ * 用法:
16
+ * ```ts
17
+ * const chain = new CommandChain()
18
+ * .use((cmd, args, next) => {
19
+ * if (cmd === 'foo') return handleFoo(...args)
20
+ * return next() // 不归我管,交给下一个
21
+ * })
22
+ * .use((cmd, args, next) => {
23
+ * // 兜底 handler
24
+ * return defaultHandler(cmd, ...args)
25
+ * })
26
+ * chain.dispatch('foo', 1, 2) // → handleFoo(1, 2)
27
+ * ```
28
+ */
29
+ export declare class CommandChain {
30
+ /** 有序 handler 列表 */
31
+ private readonly handlers;
32
+ /** 注册 handler,返回 this 支持链式调用 */
33
+ use(handler: CommandHandler): this;
34
+ /**
35
+ * 沿链分发命令。
36
+ * 从第一个 handler 开始,依次调用;handler 返回 next() 时传递给下一个。
37
+ * 所有 handler 都不处理时返回 undefined。
38
+ */
39
+ dispatch(command: string, ...args: any[]): any;
40
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * VerveDocs Core —— UI 常量与枚举
3
+ *
4
+ * PaperDirection / TableBorder 已在 schema/constants.ts 定义,通过 export * 透传。
5
+ * 字体字号从 schema 已有常量转换,不重复定义数据。
6
+ */
7
+ /** 编辑器字体选项(从 schema FONT_FAMILY_MAP 转换为 { label, value } 格式) */
8
+ export declare const EDITOR_FONT_OPTIONS: {
9
+ label: string;
10
+ value: string;
11
+ }[];
12
+ /** 编辑器字号选项(从 schema FONT_SIZE / FONT_SIZE_LIST 转换为 { label, value } 格式) */
13
+ export declare const EDITOR_SIZE_OPTIONS: {
14
+ label: string;
15
+ value: number;
16
+ }[];
17
+ /** 水印字号选项(对齐 Word 标准水印字号) */
18
+ export declare const WATERMARK_SIZE_OPTIONS: {
19
+ label: string;
20
+ value: number;
21
+ }[];