@veltra/desktop 1.1.25 → 1.1.27

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 (243) hide show
  1. package/dist/components/action/action-group.vue.d.ts +2 -2
  2. package/dist/components/action/action.js.map +1 -1
  3. package/dist/components/action/action.vue.d.ts +1 -1
  4. package/dist/components/badge/badge.js.map +1 -1
  5. package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
  6. package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
  7. package/dist/components/batch-edit/batch-edit.js.map +1 -1
  8. package/dist/components/batch-edit/batch-edit.vue.d.ts +2 -2
  9. package/dist/components/breadcrumb/breadcrumb.js.map +1 -1
  10. package/dist/components/button/button-group.js.map +1 -1
  11. package/dist/components/button/button.js.map +1 -1
  12. package/dist/components/calendar/calendar.js.map +1 -1
  13. package/dist/components/card/card-action.js.map +1 -1
  14. package/dist/components/card/card-content.js.map +1 -1
  15. package/dist/components/card/card-cover.js.map +1 -1
  16. package/dist/components/card/card.js.map +1 -1
  17. package/dist/components/cascade/cascade-panel-item.js.map +1 -1
  18. package/dist/components/cascade/cascade.js.map +1 -1
  19. package/dist/components/cascade/cascade.vue.d.ts +3 -3
  20. package/dist/components/check-tag/check-tag.js.map +1 -1
  21. package/dist/components/checkbox/checkbox-button.js.map +1 -1
  22. package/dist/components/checkbox/checkbox-button.vue.d.ts +1 -1
  23. package/dist/components/checkbox/checkbox.js.map +1 -1
  24. package/dist/components/checkbox-group/checkbox-group.js.map +1 -1
  25. package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
  26. package/dist/components/code-editor/code-editor.js.map +1 -1
  27. package/dist/components/collapse/collapse-item.js.map +1 -1
  28. package/dist/components/collapse/collapse.js.map +1 -1
  29. package/dist/components/condition-editor/components/condition-row.js.map +1 -1
  30. package/dist/components/condition-editor/condition-editor.js.map +1 -1
  31. package/dist/components/context-menu/context-menu-item.js.map +1 -1
  32. package/dist/components/context-menu/context-menu.js.map +1 -1
  33. package/dist/components/date-panel/date-panel.js.map +1 -1
  34. package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
  35. package/dist/components/date-panel/headers/day.js.map +1 -1
  36. package/dist/components/date-panel/headers/month.js.map +1 -1
  37. package/dist/components/date-panel/headers/year.js.map +1 -1
  38. package/dist/components/date-panel/panels/day.js.map +1 -1
  39. package/dist/components/date-panel/panels/month.js.map +1 -1
  40. package/dist/components/date-panel/panels/year.js.map +1 -1
  41. package/dist/components/date-picker/date-picker.js.map +1 -1
  42. package/dist/components/date-picker/date-picker.vue.d.ts +1 -1
  43. package/dist/components/date-range-picker/date-range-picker.js.map +1 -1
  44. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +1 -1
  45. package/dist/components/dialog/dialog.js.map +1 -1
  46. package/dist/components/drawer/drawer.js.map +1 -1
  47. package/dist/components/empty/empty.js.map +1 -1
  48. package/dist/components/expression-editor/components/path-preview.js.map +1 -1
  49. package/dist/components/expression-editor/components/variable-picker.js.map +1 -1
  50. package/dist/components/expression-editor/expression-editor.js.map +1 -1
  51. package/dist/components/file-picker/file-picker.js.map +1 -1
  52. package/dist/components/file-picker/file-picker.vue.d.ts +1 -1
  53. package/dist/components/file-viewer/file-viewer.js.map +1 -1
  54. package/dist/components/file-viewer/previewers/pdf-previewer.js.map +1 -1
  55. package/dist/components/file-viewer/previewers/pdf-viewport-scroll.js.map +1 -1
  56. package/dist/components/file-viewer/previewers/pdf-zoom-bridge.js.map +1 -1
  57. package/dist/components/file-viewer/previewers/sheet-previewer.js.map +1 -1
  58. package/dist/components/float-button/float-button.js.map +1 -1
  59. package/dist/components/form/form-model.d.ts +2 -2
  60. package/dist/components/form/form-model.js.map +1 -1
  61. package/dist/components/form/form.js.map +1 -1
  62. package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js.map +1 -1
  63. package/dist/components/gantt-chart/gantt-chart.js.map +1 -1
  64. package/dist/components/grid/grid-item.js.map +1 -1
  65. package/dist/components/grid/grid.js.map +1 -1
  66. package/dist/components/grid-input/grid-input.js.map +1 -1
  67. package/dist/components/group-input/group-input.js.map +1 -1
  68. package/dist/components/icon/icon.js.map +1 -1
  69. package/dist/components/input/input.js.map +1 -1
  70. package/dist/components/input/input.vue.d.ts +2 -2
  71. package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js.map +1 -1
  72. package/dist/components/layout/layout-resizer.js.map +1 -1
  73. package/dist/components/layout/layout.js.map +1 -1
  74. package/dist/components/list/list-item.js.map +1 -1
  75. package/dist/components/list/list.js.map +1 -1
  76. package/dist/components/loading/loading.js.map +1 -1
  77. package/dist/components/menu/menu-icon.js.map +1 -1
  78. package/dist/components/menu/menu-sub-collapsed.js.map +1 -1
  79. package/dist/components/menu/menu.js.map +1 -1
  80. package/dist/components/message/message-box.js.map +1 -1
  81. package/dist/components/message/message.js.map +1 -1
  82. package/dist/components/message-confirm/message-confirm.js.map +1 -1
  83. package/dist/components/multi-select/multi-select-option.js.map +1 -1
  84. package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
  85. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +3 -3
  86. package/dist/components/notification/notification.js.map +1 -1
  87. package/dist/components/notification/notification.vue.d.ts +1 -1
  88. package/dist/components/number/number.js.map +1 -1
  89. package/dist/components/number/number.vue.d.ts +1 -1
  90. package/dist/components/number-input/number-input.js.map +1 -1
  91. package/dist/components/number-range-input/number-range-input.js.map +1 -1
  92. package/dist/components/paginator/paginator.js.map +1 -1
  93. package/dist/components/palette/palette-alpha.js.map +1 -1
  94. package/dist/components/palette/palette-color-switch.js.map +1 -1
  95. package/dist/components/palette/palette-hue.js.map +1 -1
  96. package/dist/components/palette/palette-sv.js.map +1 -1
  97. package/dist/components/palette/palette.js.map +1 -1
  98. package/dist/components/pop-confirm/pop-confirm.js.map +1 -1
  99. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
  100. package/dist/components/progress/progress.js.map +1 -1
  101. package/dist/components/progress-nodes/progress-nodes.js.map +1 -1
  102. package/dist/components/radio/radio.js.map +1 -1
  103. package/dist/components/radio-group/radio-group.js.map +1 -1
  104. package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
  105. package/dist/components/scroll/scroll-bar.js.map +1 -1
  106. package/dist/components/scroll/scroll.js.map +1 -1
  107. package/dist/components/select/select.vue.d.ts +2 -2
  108. package/dist/components/slider/slider-thumb.js.map +1 -1
  109. package/dist/components/slider/slider.js.map +1 -1
  110. package/dist/components/steps/steps.js.map +1 -1
  111. package/dist/components/switch/switch.js.map +1 -1
  112. package/dist/components/table/table-body.js.map +1 -1
  113. package/dist/components/table/table-cell.js.map +1 -1
  114. package/dist/components/table/table-foot.js.map +1 -1
  115. package/dist/components/table/table.vue.d.ts +2 -2
  116. package/dist/components/table-editor/table-editor.js.map +1 -1
  117. package/dist/components/tabs/tabs-horizontal.js.map +1 -1
  118. package/dist/components/tabs/tabs-horizontal.vue.d.ts +3 -3
  119. package/dist/components/tabs/tabs-vertical.js.map +1 -1
  120. package/dist/components/tabs/tabs-vertical.vue.d.ts +2 -2
  121. package/dist/components/tabs/tabs.js.map +1 -1
  122. package/dist/components/tabs/tabs.vue.d.ts +3 -3
  123. package/dist/components/tag/tag.js.map +1 -1
  124. package/dist/components/text/text.js.map +1 -1
  125. package/dist/components/textarea/textarea.js.map +1 -1
  126. package/dist/components/textarea/textarea.vue.d.ts +3 -3
  127. package/dist/components/theme/theme.js.map +1 -1
  128. package/dist/components/tip/tip.js.map +1 -1
  129. package/dist/components/tip/tip.vue.d.ts +1 -1
  130. package/dist/components/tree/tree-node.js.map +1 -1
  131. package/dist/components/tree/tree.js.map +1 -1
  132. package/dist/components/tree-select/tree-select.vue.d.ts +3 -3
  133. package/dist/components/watermark/watermark.js.map +1 -1
  134. package/package.json +6 -6
  135. package/src/components/action/action.vue +1 -4
  136. package/src/components/badge/badge.vue +3 -9
  137. package/src/components/batch-edit/batch-edit-form.vue +1 -5
  138. package/src/components/batch-edit/batch-edit-list.vue +2 -6
  139. package/src/components/batch-edit/batch-edit.vue +2 -12
  140. package/src/components/breadcrumb/breadcrumb.vue +4 -13
  141. package/src/components/button/button-group.vue +2 -6
  142. package/src/components/button/button.vue +3 -9
  143. package/src/components/calendar/calendar.vue +1 -3
  144. package/src/components/card/card-action.vue +1 -3
  145. package/src/components/card/card-content.vue +1 -6
  146. package/src/components/card/card-cover.vue +1 -3
  147. package/src/components/card/card.vue +2 -6
  148. package/src/components/cascade/cascade-panel-item.vue +2 -8
  149. package/src/components/cascade/cascade.vue +5 -37
  150. package/src/components/check-tag/check-tag.vue +1 -3
  151. package/src/components/checkbox/checkbox-button.vue +2 -6
  152. package/src/components/checkbox/checkbox.vue +1 -3
  153. package/src/components/checkbox-group/checkbox-group.vue +1 -3
  154. package/src/components/code-editor/code-editor.vue +4 -12
  155. package/src/components/collapse/collapse-item.vue +1 -3
  156. package/src/components/collapse/collapse.vue +2 -8
  157. package/src/components/condition-editor/components/condition-row.vue +2 -8
  158. package/src/components/condition-editor/condition-editor.vue +2 -6
  159. package/src/components/context-menu/context-menu-item.vue +3 -10
  160. package/src/components/context-menu/context-menu.vue +5 -17
  161. package/src/components/date-panel/date-panel.vue +3 -11
  162. package/src/components/date-panel/headers/day.vue +1 -3
  163. package/src/components/date-panel/headers/month.vue +1 -3
  164. package/src/components/date-panel/headers/year.vue +1 -3
  165. package/src/components/date-panel/panels/day.vue +1 -4
  166. package/src/components/date-panel/panels/month.vue +1 -3
  167. package/src/components/date-panel/panels/year.vue +1 -3
  168. package/src/components/date-picker/date-picker.vue +1 -3
  169. package/src/components/date-range-picker/date-range-picker.vue +1 -3
  170. package/src/components/dialog/dialog.vue +7 -24
  171. package/src/components/drawer/drawer.vue +3 -11
  172. package/src/components/empty/empty.vue +2 -7
  173. package/src/components/expression-editor/components/path-preview.vue +2 -6
  174. package/src/components/expression-editor/components/variable-picker.vue +1 -3
  175. package/src/components/expression-editor/expression-editor.vue +2 -6
  176. package/src/components/expression-editor/style.scss +1 -1
  177. package/src/components/file-picker/file-picker.vue +2 -7
  178. package/src/components/file-viewer/file-viewer.vue +4 -22
  179. package/src/components/file-viewer/previewers/pdf-previewer.vue +1 -5
  180. package/src/components/file-viewer/previewers/pdf-viewport-scroll.vue +1 -7
  181. package/src/components/file-viewer/previewers/pdf-zoom-bridge.vue +2 -7
  182. package/src/components/file-viewer/previewers/sheet-previewer.vue +4 -10
  183. package/src/components/float-button/float-button.vue +1 -3
  184. package/src/components/form/form-model.ts +9 -2
  185. package/src/components/form/form.vue +3 -13
  186. package/src/components/gantt-chart/gantt-chart.vue +1 -3
  187. package/src/components/grid/grid-item.vue +3 -9
  188. package/src/components/grid/grid.vue +5 -18
  189. package/src/components/grid-input/grid-input.vue +2 -6
  190. package/src/components/group-input/group-input.vue +2 -7
  191. package/src/components/icon/icon.vue +2 -6
  192. package/src/components/input/input.vue +2 -6
  193. package/src/components/layout/layout-resizer.vue +1 -3
  194. package/src/components/layout/layout.vue +3 -9
  195. package/src/components/list/list-item.vue +1 -3
  196. package/src/components/list/list.vue +2 -6
  197. package/src/components/loading/loading.vue +3 -9
  198. package/src/components/menu/menu-icon.vue +2 -6
  199. package/src/components/menu/menu-sub-collapsed.vue +2 -8
  200. package/src/components/menu/menu.vue +3 -9
  201. package/src/components/menu/style.scss +1 -1
  202. package/src/components/message/message-box.vue +3 -10
  203. package/src/components/message/message.vue +3 -9
  204. package/src/components/message-confirm/message-confirm.vue +2 -6
  205. package/src/components/multi-select/multi-select-option.vue +3 -9
  206. package/src/components/notification/notification.vue +3 -11
  207. package/src/components/number/number.vue +4 -14
  208. package/src/components/number-input/number-input.vue +7 -36
  209. package/src/components/number-range-input/number-range-input.vue +4 -17
  210. package/src/components/paginator/paginator.vue +7 -22
  211. package/src/components/palette/palette-alpha.vue +2 -6
  212. package/src/components/palette/palette-color-switch.vue +1 -3
  213. package/src/components/palette/palette-hue.vue +2 -6
  214. package/src/components/palette/palette-sv.vue +5 -17
  215. package/src/components/palette/palette.vue +2 -12
  216. package/src/components/pop-confirm/pop-confirm.vue +2 -6
  217. package/src/components/progress/progress.vue +2 -7
  218. package/src/components/progress-nodes/progress-nodes.vue +2 -7
  219. package/src/components/radio/radio.vue +2 -6
  220. package/src/components/radio-group/radio-group.vue +1 -3
  221. package/src/components/scroll/scroll-bar.vue +5 -17
  222. package/src/components/scroll/scroll.vue +5 -16
  223. package/src/components/slider/slider-thumb.vue +4 -12
  224. package/src/components/slider/slider.vue +3 -14
  225. package/src/components/steps/steps.vue +3 -10
  226. package/src/components/switch/switch.vue +2 -7
  227. package/src/components/table/table-body.vue +2 -8
  228. package/src/components/table/table-cell.vue +2 -7
  229. package/src/components/table/table-foot.vue +2 -9
  230. package/src/components/table-editor/table-editor.vue +1 -3
  231. package/src/components/tabs/tabs-horizontal.vue +2 -6
  232. package/src/components/tabs/tabs-vertical.vue +1 -3
  233. package/src/components/tabs/tabs.vue +1 -3
  234. package/src/components/tag/tag.vue +2 -6
  235. package/src/components/text/text.vue +3 -9
  236. package/src/components/textarea/textarea.vue +1 -3
  237. package/src/components/theme/group-item.vue +1 -3
  238. package/src/components/theme/group.vue +1 -3
  239. package/src/components/theme/theme.vue +6 -26
  240. package/src/components/tip/tip.vue +1 -3
  241. package/src/components/tree/tree-node.vue +1 -3
  242. package/src/components/tree/tree.vue +7 -30
  243. package/src/components/watermark/watermark.vue +4 -15
@@ -1 +1 @@
1
- {"version":3,"file":"empty.js","names":[],"sources":["../../../src/components/empty/empty.vue"],"sourcesContent":["<template>\n <span :class=\"cls.b\">\n <u-icon :size=\"size\"> <Empty /> </u-icon>\n <div>{{ text }}</div>\n </span>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Empty } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\n\nimport type { EmptyProps } from '../../types'\nimport { UIcon } from '../icon'\n\ndefineOptions({\n name: 'Empty'\n})\n\nwithDefaults(defineProps<EmptyProps>(), {\n size: 48,\n text: '暂无数据'\n})\n\nconst cls = bem('empty')\n</script>\n"],"mappings":";;;;;;;;;;;;;EAuBA,MAAM,MAAM,IAAI,QAAO;;uBAtBrB,mBAGO,QAAA,EAHA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,EAAA,EAAA,CACjB,YAAyC,MAAA,YAAA,EAAA,EAAhC,MAAM,QAAA,MAAI,EAAA;2BAAY,CAAT,YAAS,MAAA,MAAA,CAAA,CAAA,CAAA;;oBAC/B,mBAAqB,OAAA,MAAA,gBAAb,QAAA,KAAI,EAAA,EAAA,CAAA,EAAA,EAAA"}
1
+ {"version":3,"file":"empty.js","names":[],"sources":["../../../src/components/empty/empty.vue"],"sourcesContent":["<template>\n <span :class=\"cls.b\">\n <u-icon :size=\"size\"> <Empty /> </u-icon>\n <div>{{ text }}</div>\n </span>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Empty } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\n\nimport type { EmptyProps } from '../../types'\nimport { UIcon } from '../icon'\n\ndefineOptions({ name: 'Empty' })\n\nwithDefaults(defineProps<EmptyProps>(), { size: 48, text: '暂无数据' })\n\nconst cls = bem('empty')\n</script>\n"],"mappings":";;;;;;;;;;;;;EAkBA,MAAM,MAAM,IAAI,QAAO;;uBAjBrB,mBAGO,QAAA,EAHA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,EAAA,EAAA,CACjB,YAAyC,MAAA,YAAA,EAAA,EAAhC,MAAM,QAAA,MAAI,EAAA;2BAAY,CAAT,YAAS,MAAA,MAAA,CAAA,CAAA,CAAA;;oBAC/B,mBAAqB,OAAA,MAAA,gBAAb,QAAA,KAAI,EAAA,EAAA,CAAA,EAAA,EAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"path-preview.js","names":[],"sources":["../../../../src/components/expression-editor/components/path-preview.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('path-preview')\">\n <div :class=\"cls.e('path-preview-title')\">变量路径</div>\n <ul :class=\"cls.e('path-tree')\">\n <li\n v-for=\"(node, i) in path\"\n :key=\"`${i}-${node.value || node.label}`\"\n :class=\"[cls.e('path-tree-item'), bem.is('active', i === path.length - 1)]\"\n :style=\"{ paddingLeft: `${i * 14}px` }\"\n >\n <span v-if=\"i > 0\" :class=\"cls.e('path-tree-branch')\">└</span>\n <span :class=\"cls.e('path-tree-label')\">{{ node.label }}</span>\n </li>\n </ul>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\n\nimport type { VariableItem } from '../../../types'\n\ndefineOptions({\n name: 'ExpressionPathPreview'\n})\n\ndefineProps<{\n path: VariableItem[]\n}>()\n\nconst cls = bem('expression-editor')\n</script>\n"],"mappings":";;;;;;;;EA8BA,MAAM,MAAM,IAAI,oBAAmB;;uBA7BjC,mBAaM,OAAA,EAbA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,eAAA,CAAA,EAAA,EAAA,CAChB,mBAAoD,OAAA,EAA9C,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,qBAAA,CAAA,EAAA,EAAwB,QAAI,EAAA,EAC9C,mBAUK,MAAA,EAVA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,YAAA,CAAA,EAAA,EAAA,EAAA,UAAA,KAAA,EACf,mBAQK,UAAA,MAAA,WAPiB,QAAA,OAAZ,MAAM,MAAC;wBADjB,mBAQK,MAAA;KANF,KAAG,GAAK,EAAC,GAAI,KAAK,SAAS,KAAK;KAChC,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,iBAAA,EAAoB,MAAA,IAAA,CAAI,GAAE,UAAW,MAAM,QAAA,KAAK,SAAM,EAAA,CAAA,CAAA;KACnE,OAAK,eAAA,EAAA,aAAA,GAAoB,IAAC,GAAA,KAAA,CAAA;QAEf,IAAC,KAAA,WAAA,EAAb,mBAA8D,QAAA;;KAA1C,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,mBAAA,CAAA;OAAsB,KAAC,EAAA,IAAA,mBAAA,QAAA,KAAA,EACvD,mBAA+D,QAAA,EAAxD,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,kBAAA,CAAA,EAAA,EAAA,gBAAwB,KAAK,MAAK,EAAA,EAAA,CAAA,EAAA,EAAA"}
1
+ {"version":3,"file":"path-preview.js","names":[],"sources":["../../../../src/components/expression-editor/components/path-preview.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('path-preview')\">\n <div :class=\"cls.e('path-preview-title')\">变量路径</div>\n <ul :class=\"cls.e('path-tree')\">\n <li\n v-for=\"(node, i) in path\"\n :key=\"`${i}-${node.value || node.label}`\"\n :class=\"[cls.e('path-tree-item'), bem.is('active', i === path.length - 1)]\"\n :style=\"{ paddingLeft: `${i * 14}px` }\"\n >\n <span v-if=\"i > 0\" :class=\"cls.e('path-tree-branch')\">└</span>\n <span :class=\"cls.e('path-tree-label')\">{{ node.label }}</span>\n </li>\n </ul>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\n\nimport type { VariableItem } from '../../../types'\n\ndefineOptions({ name: 'ExpressionPathPreview' })\n\ndefineProps<{ path: VariableItem[] }>()\n\nconst cls = bem('expression-editor')\n</script>\n"],"mappings":";;;;;;;;EA0BA,MAAM,MAAM,IAAI,oBAAmB;;uBAzBjC,mBAaM,OAAA,EAbA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,eAAA,CAAA,EAAA,EAAA,CAChB,mBAAoD,OAAA,EAA9C,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,qBAAA,CAAA,EAAA,EAAwB,QAAI,EAAA,EAC9C,mBAUK,MAAA,EAVA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,YAAA,CAAA,EAAA,EAAA,EAAA,UAAA,KAAA,EACf,mBAQK,UAAA,MAAA,WAPiB,QAAA,OAAZ,MAAM,MAAC;wBADjB,mBAQK,MAAA;KANF,KAAG,GAAK,EAAC,GAAI,KAAK,SAAS,KAAK;KAChC,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,iBAAA,EAAoB,MAAA,IAAA,CAAI,GAAE,UAAW,MAAM,QAAA,KAAK,SAAM,EAAA,CAAA,CAAA;KACnE,OAAK,eAAA,EAAA,aAAA,GAAoB,IAAC,GAAA,KAAA,CAAA;QAEf,IAAC,KAAA,WAAA,EAAb,mBAA8D,QAAA;;KAA1C,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,mBAAA,CAAA;OAAsB,KAAC,EAAA,IAAA,mBAAA,QAAA,KAAA,EACvD,mBAA+D,QAAA,EAAxD,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,kBAAA,CAAA,EAAA,EAAA,gBAAwB,KAAK,MAAK,EAAA,EAAA,CAAA,EAAA,EAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"variable-picker.js","names":[],"sources":["../../../../src/components/expression-editor/components/variable-picker.vue"],"sourcesContent":["<template>\n <u-tip\n hide-arrow\n alignment=\"start\"\n direction=\"bottom\"\n trigger=\"click\"\n :trigger-dom=\"triggerDom\"\n :visible=\"visible\"\n @update:visible=\"handleVisibleChange($event)\"\n >\n <template #content>\n <div :class=\"cls.e('picker')\" @mousedown.prevent>\n <!-- 面包屑:仅逐级模式且非根级显示 -->\n <div v-if=\"!isFlat && navPath.length > 0\" :class=\"cls.e('breadcrumbs')\">\n <span :class=\"cls.e('breadcrumb-item')\">\n <span :class=\"cls.e('breadcrumb-link')\" @click=\"navigateTo(0)\">全部变量</span>\n <u-icon :class=\"cls.e('breadcrumb-separator')\">\n <ArrowRight />\n </u-icon>\n </span>\n <span\n v-for=\"(crumb, i) in navPath\"\n :key=\"`${i}-${crumb.value}`\"\n :class=\"cls.e('breadcrumb-item')\"\n >\n <span\n :class=\"[\n cls.e('breadcrumb-link'),\n { [cls.em('breadcrumb-link', 'active')]: i === navPath.length - 1 }\n ]\"\n @click=\"navigateTo(i + 1)\"\n >{{ crumb.label }}</span\n >\n <u-icon v-if=\"i < navPath.length - 1\" :class=\"cls.e('breadcrumb-separator')\">\n <ArrowRight />\n </u-icon>\n </span>\n </div>\n\n <div :class=\"cls.e('picker-body')\">\n <div :class=\"cls.e('panel')\" v-if=\"currentList.length > 0\">\n <u-scroll tag=\"ul\" :class=\"cls.e('panel-list')\" :content-class=\"cls.e('panel-content')\">\n <li\n v-for=\"(item, idx) in currentList\"\n :key=\"`${idx}-${item.value}`\"\n :data-idx=\"idx\"\n :class=\"getItemCls(item, idx)\"\n @click=\"handleItemClick(item, idx)\"\n @mouseenter=\"activeIndex = idx\"\n >\n <span :class=\"cls.e('item-label')\">{{ item.label }}</span>\n <u-icon v-if=\"!isFlat && hasChildren(item)\" :class=\"cls.e('item-expand')\">\n <ArrowRight />\n </u-icon>\n </li>\n </u-scroll>\n </div>\n <div v-else :class=\"cls.e('empty')\">\n <UEmpty description=\"暂无可用变量\" />\n </div>\n\n <PathPreview v-if=\"isFlat && activePath.length > 0\" :path=\"activePath\" />\n </div>\n </div>\n </template>\n </u-tip>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ArrowRight } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, nextTick, ref, watch } from 'vue'\n\nimport type { VariableItem } from '../../../types'\nimport { UEmpty } from '../../empty'\nimport { UIcon } from '../../icon'\nimport { UScroll } from '../../scroll'\nimport { UTip } from '../../tip'\nimport PathPreview from './path-preview.vue'\n\ndefineOptions({\n name: 'VariablePicker'\n})\n\ninterface FlatItem extends VariableItem {\n /** 仅扁平模式使用:从根到当前节点的路径 */\n __path: VariableItem[]\n}\n\nconst props = defineProps<{\n visible: boolean\n triggerDom?: HTMLElement\n /** 顶层变量树 */\n variables?: VariableItem[]\n /** 来自编辑器 mention 状态的过滤字符串。空 = 逐级模式;非空 = 扁平模式。 */\n filter: string\n /** 是否允许选中分支节点 */\n selectableLevels: 'leaf' | 'any'\n}>()\n\nconst emit = defineEmits<{\n (e: 'select', item: VariableItem): void\n (e: 'update:visible', visible: boolean): void\n /** 用户主动取消(按 Esc)。编辑器据此把 mention 状态置为 dismissed。 */\n (e: 'dismiss'): void\n}>()\n\nconst cls = bem('expression-editor')\n\nconst navPath = ref<VariableItem[]>([])\nconst activeIndex = ref(0)\n\nconst isFlat = computed(() => props.filter !== '')\n\nfunction hasChildren(item: VariableItem): boolean {\n return !!item.children && item.children.length > 0\n}\n\nfunction isLeaf(item: VariableItem): boolean {\n return !hasChildren(item)\n}\n\n/** 当前层级展示的列表(来源依模式而定) */\nconst currentList = computed<VariableItem[]>(() => {\n const variables = props.variables ?? []\n if (isFlat.value) return flatList.value\n let level: VariableItem[] = variables\n for (const node of navPath.value) {\n const found = level.find((it) => it.value === node.value)\n if (!found || !found.children) break\n level = found.children\n }\n return level\n})\n\n/** 扁平模式下:根据 selectableLevels 拍平 + 过滤 */\nconst flatList = computed<FlatItem[]>(() => {\n const variables = props.variables ?? []\n const out: FlatItem[] = []\n const includeBranches = props.selectableLevels === 'any'\n function walk(items: VariableItem[], path: VariableItem[]) {\n for (const it of items) {\n const nextPath = [...path, it]\n if (isLeaf(it)) {\n out.push({ ...it, __path: nextPath })\n } else {\n if (includeBranches) out.push({ ...it, __path: nextPath })\n walk(it.children!, nextPath)\n }\n }\n }\n walk(variables, [])\n const q = props.filter.toLowerCase()\n return out.filter((it) => it.label.toLowerCase().includes(q))\n})\n\n/** 当前 active 项;扁平模式下用于驱动路径预览 */\nconst activePath = computed<VariableItem[]>(() => {\n if (!isFlat.value) return []\n const item = flatList.value[activeIndex.value] as FlatItem | undefined\n return item ? item.__path : []\n})\n\nfunction getItemCls(_item: VariableItem, idx: number) {\n return [cls.e('item'), bem.is('active', idx === activeIndex.value)]\n}\n\nfunction navigateTo(i: number) {\n // 0 = 全部变量;i 之后表示进入到 navPath[i-1]\n navPath.value = navPath.value.slice(0, i)\n activeIndex.value = 0\n}\n\nfunction handleItemClick(item: VariableItem, idx: number) {\n activeIndex.value = idx\n selectActive()\n}\n\nfunction selectActive() {\n const item = currentList.value[activeIndex.value]\n if (!item) return\n\n if (isFlat.value) {\n // 扁平模式始终是「选中并替换」\n emit('select', flattenSourceFor(item))\n return\n }\n\n // 逐级模式\n if (hasChildren(item)) {\n if (props.selectableLevels === 'any') {\n // Enter 在分支项上:选中分支本身\n emit('select', item)\n return\n }\n // 默认 'leaf':进入下一级\n navPath.value = [...navPath.value, item]\n activeIndex.value = 0\n return\n }\n emit('select', item)\n}\n\nfunction flattenSourceFor(it: VariableItem): VariableItem {\n const flat = it as FlatItem\n // 还原为「不带 __path 的纯 VariableItem」,避免泄漏内部字段\n const out: VariableItem = { value: flat.value, label: flat.label }\n if (flat.type) out.type = flat.type\n if (flat.children) out.children = flat.children\n return out\n}\n\nfunction moveActive(delta: -1 | 1) {\n const max = currentList.value.length - 1\n if (max < 0) return\n let next = activeIndex.value + delta\n if (next < 0) next = 0\n if (next > max) next = max\n activeIndex.value = next\n scrollActiveIntoView()\n}\n\nfunction scrollActiveIntoView() {\n void nextTick(() => {\n const list = document.querySelector(`.${cls.e('panel-list')}`)\n if (!list) return\n const item = list.querySelector(`[data-idx=\"${activeIndex.value}\"]`)\n if (item && 'scrollIntoView' in item) {\n ;(item as HTMLElement).scrollIntoView({ block: 'nearest' })\n }\n })\n}\n\nfunction handleVisibleChange(v: boolean) {\n emit('update:visible', v)\n if (!v) reset()\n}\n\nfunction reset() {\n navPath.value = []\n activeIndex.value = 0\n}\n\nwatch(\n () => props.visible,\n (v) => {\n if (!v) reset()\n else activeIndex.value = 0\n }\n)\n\nwatch(\n () => props.filter,\n () => {\n // 过滤词变化:重置 active;逐级 → 扁平时清空 navPath\n activeIndex.value = 0\n if (isFlat.value) navPath.value = []\n }\n)\n\n/**\n * 由父级 forward 进来的键盘事件。\n * 返回 true 表示已处理(外部应 preventDefault)。\n */\nfunction handleKeydown(e: KeyboardEvent): boolean {\n if (!props.visible) return false\n\n switch (e.key) {\n case 'Escape':\n emit('dismiss')\n emit('update:visible', false)\n reset()\n return true\n case 'ArrowDown':\n moveActive(1)\n return true\n case 'ArrowUp':\n moveActive(-1)\n return true\n case 'ArrowLeft':\n // 仅逐级模式:返回上一级;扁平模式下不拦截,让光标正常移动并触发 mention dismiss\n if (!isFlat.value && navPath.value.length > 0) {\n navPath.value = navPath.value.slice(0, -1)\n activeIndex.value = 0\n return true\n }\n return false\n case 'ArrowRight': {\n if (isFlat.value) return false\n const item = currentList.value[activeIndex.value]\n if (item && hasChildren(item)) {\n navPath.value = [...navPath.value, item]\n activeIndex.value = 0\n return true\n }\n return false\n }\n case 'Enter':\n selectActive()\n return true\n default:\n return false\n }\n}\n\ndefineExpose({ handleKeydown })\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"variable-picker.js","names":[],"sources":["../../../../src/components/expression-editor/components/variable-picker.vue"],"sourcesContent":["<template>\n <u-tip\n hide-arrow\n alignment=\"start\"\n direction=\"bottom\"\n trigger=\"click\"\n :trigger-dom=\"triggerDom\"\n :visible=\"visible\"\n @update:visible=\"handleVisibleChange($event)\"\n >\n <template #content>\n <div :class=\"cls.e('picker')\" @mousedown.prevent>\n <!-- 面包屑:仅逐级模式且非根级显示 -->\n <div v-if=\"!isFlat && navPath.length > 0\" :class=\"cls.e('breadcrumbs')\">\n <span :class=\"cls.e('breadcrumb-item')\">\n <span :class=\"cls.e('breadcrumb-link')\" @click=\"navigateTo(0)\">全部变量</span>\n <u-icon :class=\"cls.e('breadcrumb-separator')\">\n <ArrowRight />\n </u-icon>\n </span>\n <span\n v-for=\"(crumb, i) in navPath\"\n :key=\"`${i}-${crumb.value}`\"\n :class=\"cls.e('breadcrumb-item')\"\n >\n <span\n :class=\"[\n cls.e('breadcrumb-link'),\n { [cls.em('breadcrumb-link', 'active')]: i === navPath.length - 1 }\n ]\"\n @click=\"navigateTo(i + 1)\"\n >{{ crumb.label }}</span\n >\n <u-icon v-if=\"i < navPath.length - 1\" :class=\"cls.e('breadcrumb-separator')\">\n <ArrowRight />\n </u-icon>\n </span>\n </div>\n\n <div :class=\"cls.e('picker-body')\">\n <div :class=\"cls.e('panel')\" v-if=\"currentList.length > 0\">\n <u-scroll tag=\"ul\" :class=\"cls.e('panel-list')\" :content-class=\"cls.e('panel-content')\">\n <li\n v-for=\"(item, idx) in currentList\"\n :key=\"`${idx}-${item.value}`\"\n :data-idx=\"idx\"\n :class=\"getItemCls(item, idx)\"\n @click=\"handleItemClick(item, idx)\"\n @mouseenter=\"activeIndex = idx\"\n >\n <span :class=\"cls.e('item-label')\">{{ item.label }}</span>\n <u-icon v-if=\"!isFlat && hasChildren(item)\" :class=\"cls.e('item-expand')\">\n <ArrowRight />\n </u-icon>\n </li>\n </u-scroll>\n </div>\n <div v-else :class=\"cls.e('empty')\">\n <UEmpty description=\"暂无可用变量\" />\n </div>\n\n <PathPreview v-if=\"isFlat && activePath.length > 0\" :path=\"activePath\" />\n </div>\n </div>\n </template>\n </u-tip>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ArrowRight } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, nextTick, ref, watch } from 'vue'\n\nimport type { VariableItem } from '../../../types'\nimport { UEmpty } from '../../empty'\nimport { UIcon } from '../../icon'\nimport { UScroll } from '../../scroll'\nimport { UTip } from '../../tip'\nimport PathPreview from './path-preview.vue'\n\ndefineOptions({ name: 'VariablePicker' })\n\ninterface FlatItem extends VariableItem {\n /** 仅扁平模式使用:从根到当前节点的路径 */\n __path: VariableItem[]\n}\n\nconst props = defineProps<{\n visible: boolean\n triggerDom?: HTMLElement\n /** 顶层变量树 */\n variables?: VariableItem[]\n /** 来自编辑器 mention 状态的过滤字符串。空 = 逐级模式;非空 = 扁平模式。 */\n filter: string\n /** 是否允许选中分支节点 */\n selectableLevels: 'leaf' | 'any'\n}>()\n\nconst emit = defineEmits<{\n (e: 'select', item: VariableItem): void\n (e: 'update:visible', visible: boolean): void\n /** 用户主动取消(按 Esc)。编辑器据此把 mention 状态置为 dismissed。 */\n (e: 'dismiss'): void\n}>()\n\nconst cls = bem('expression-editor')\n\nconst navPath = ref<VariableItem[]>([])\nconst activeIndex = ref(0)\n\nconst isFlat = computed(() => props.filter !== '')\n\nfunction hasChildren(item: VariableItem): boolean {\n return !!item.children && item.children.length > 0\n}\n\nfunction isLeaf(item: VariableItem): boolean {\n return !hasChildren(item)\n}\n\n/** 当前层级展示的列表(来源依模式而定) */\nconst currentList = computed<VariableItem[]>(() => {\n const variables = props.variables ?? []\n if (isFlat.value) return flatList.value\n let level: VariableItem[] = variables\n for (const node of navPath.value) {\n const found = level.find((it) => it.value === node.value)\n if (!found || !found.children) break\n level = found.children\n }\n return level\n})\n\n/** 扁平模式下:根据 selectableLevels 拍平 + 过滤 */\nconst flatList = computed<FlatItem[]>(() => {\n const variables = props.variables ?? []\n const out: FlatItem[] = []\n const includeBranches = props.selectableLevels === 'any'\n function walk(items: VariableItem[], path: VariableItem[]) {\n for (const it of items) {\n const nextPath = [...path, it]\n if (isLeaf(it)) {\n out.push({ ...it, __path: nextPath })\n } else {\n if (includeBranches) out.push({ ...it, __path: nextPath })\n walk(it.children!, nextPath)\n }\n }\n }\n walk(variables, [])\n const q = props.filter.toLowerCase()\n return out.filter((it) => it.label.toLowerCase().includes(q))\n})\n\n/** 当前 active 项;扁平模式下用于驱动路径预览 */\nconst activePath = computed<VariableItem[]>(() => {\n if (!isFlat.value) return []\n const item = flatList.value[activeIndex.value] as FlatItem | undefined\n return item ? item.__path : []\n})\n\nfunction getItemCls(_item: VariableItem, idx: number) {\n return [cls.e('item'), bem.is('active', idx === activeIndex.value)]\n}\n\nfunction navigateTo(i: number) {\n // 0 = 全部变量;i 之后表示进入到 navPath[i-1]\n navPath.value = navPath.value.slice(0, i)\n activeIndex.value = 0\n}\n\nfunction handleItemClick(item: VariableItem, idx: number) {\n activeIndex.value = idx\n selectActive()\n}\n\nfunction selectActive() {\n const item = currentList.value[activeIndex.value]\n if (!item) return\n\n if (isFlat.value) {\n // 扁平模式始终是「选中并替换」\n emit('select', flattenSourceFor(item))\n return\n }\n\n // 逐级模式\n if (hasChildren(item)) {\n if (props.selectableLevels === 'any') {\n // Enter 在分支项上:选中分支本身\n emit('select', item)\n return\n }\n // 默认 'leaf':进入下一级\n navPath.value = [...navPath.value, item]\n activeIndex.value = 0\n return\n }\n emit('select', item)\n}\n\nfunction flattenSourceFor(it: VariableItem): VariableItem {\n const flat = it as FlatItem\n // 还原为「不带 __path 的纯 VariableItem」,避免泄漏内部字段\n const out: VariableItem = { value: flat.value, label: flat.label }\n if (flat.type) out.type = flat.type\n if (flat.children) out.children = flat.children\n return out\n}\n\nfunction moveActive(delta: -1 | 1) {\n const max = currentList.value.length - 1\n if (max < 0) return\n let next = activeIndex.value + delta\n if (next < 0) next = 0\n if (next > max) next = max\n activeIndex.value = next\n scrollActiveIntoView()\n}\n\nfunction scrollActiveIntoView() {\n void nextTick(() => {\n const list = document.querySelector(`.${cls.e('panel-list')}`)\n if (!list) return\n const item = list.querySelector(`[data-idx=\"${activeIndex.value}\"]`)\n if (item && 'scrollIntoView' in item) {\n ;(item as HTMLElement).scrollIntoView({ block: 'nearest' })\n }\n })\n}\n\nfunction handleVisibleChange(v: boolean) {\n emit('update:visible', v)\n if (!v) reset()\n}\n\nfunction reset() {\n navPath.value = []\n activeIndex.value = 0\n}\n\nwatch(\n () => props.visible,\n (v) => {\n if (!v) reset()\n else activeIndex.value = 0\n }\n)\n\nwatch(\n () => props.filter,\n () => {\n // 过滤词变化:重置 active;逐级 → 扁平时清空 navPath\n activeIndex.value = 0\n if (isFlat.value) navPath.value = []\n }\n)\n\n/**\n * 由父级 forward 进来的键盘事件。\n * 返回 true 表示已处理(外部应 preventDefault)。\n */\nfunction handleKeydown(e: KeyboardEvent): boolean {\n if (!props.visible) return false\n\n switch (e.key) {\n case 'Escape':\n emit('dismiss')\n emit('update:visible', false)\n reset()\n return true\n case 'ArrowDown':\n moveActive(1)\n return true\n case 'ArrowUp':\n moveActive(-1)\n return true\n case 'ArrowLeft':\n // 仅逐级模式:返回上一级;扁平模式下不拦截,让光标正常移动并触发 mention dismiss\n if (!isFlat.value && navPath.value.length > 0) {\n navPath.value = navPath.value.slice(0, -1)\n activeIndex.value = 0\n return true\n }\n return false\n case 'ArrowRight': {\n if (isFlat.value) return false\n const item = currentList.value[activeIndex.value]\n if (item && hasChildren(item)) {\n navPath.value = [...navPath.value, item]\n activeIndex.value = 0\n return true\n }\n return false\n }\n case 'Enter':\n selectActive()\n return true\n default:\n return false\n }\n}\n\ndefineExpose({ handleKeydown })\n</script>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"expression-editor.js","names":[],"sources":["../../../src/components/expression-editor/expression-editor.vue"],"sourcesContent":["<template>\n <div :class=\"className\">\n <div\n ref=\"container\"\n :class=\"cls.e('container')\"\n :contenteditable=\"!readonly && !disabled\"\n :data-empty=\"isEmpty || undefined\"\n :data-placeholder=\"props.placeholder\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n ></div>\n\n <div v-if=\"showPlaceholder\" :class=\"cls.e('placeholder')\">\n {{ props.placeholder }}\n </div>\n\n <VariablePicker\n ref=\"pickerRef\"\n :visible=\"pickerVisible\"\n :trigger-dom=\"pickerTriggerDom\"\n :variables=\"props.variables\"\n :filter=\"pickerFilter\"\n :selectable-levels=\"props.selectableLevels ?? 'leaf'\"\n @select=\"onPickerSelect\"\n @dismiss=\"onPickerDismiss\"\n @update:visible=\"onPickerVisibleChange\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { bem } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n shallowRef,\n useTemplateRef,\n watch\n} from 'vue'\n\nimport type { ExpressionEditorProps, VariableItem } from '../../types'\nimport VariablePicker from './components/variable-picker.vue'\nimport { createEditor, type EditorAPI } from './core/editor'\nimport { createMention, type MentionAPI } from './core/mention'\nimport { parse, type Doc } from './core/model'\nimport { createVariableMap } from './di'\n\ndefineOptions({\n name: 'ExpressionEditor'\n})\n\nconst props = withDefaults(defineProps<ExpressionEditorProps>(), {\n placeholder: '请输入表达式,输入 @ 可插入变量',\n selectableLevels: 'leaf'\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n}>()\n\nconst cls = bem('expression-editor')\nconst { formProps } = injectFormContext()\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst containerRef = useTemplateRef<HTMLDivElement>('container')\nconst pickerRef = useTemplateRef<{ handleKeydown: (e: KeyboardEvent) => boolean }>('pickerRef')\n\nconst className = computed(() => [\n cls.b,\n cls.m(size.value),\n bem.is('disabled', disabled.value),\n bem.is('readonly', readonly.value)\n])\n\nconst variableMap = computed(() => createVariableMap(props.variables))\n\nconst editorRef = shallowRef<EditorAPI | null>(null)\nconst mention: MentionAPI = createMention()\n\nconst currentDoc = shallowRef<Doc>([])\nconst isEmpty = computed(() => currentDoc.value.length === 0)\nconst showPlaceholder = computed(() => isEmpty.value && !disabled.value)\n\nconst pickerMode = shallowRef<'mention' | 'reselect' | null>(null)\nconst pickerTriggerDom = shallowRef<HTMLElement | undefined>(undefined)\nconst reselectingSegIdx = shallowRef<number | null>(null)\nconst pickerFilter = shallowRef('')\n\nconst pickerVisible = computed(() => pickerMode.value !== null)\n\nfunction syncMention() {\n const editor = editorRef.value\n if (!editor) return\n if (pickerMode.value === 'reselect') return\n const caret = editor.getCaretOffset()\n const state = mention.update(currentDoc.value, caret)\n if (state) {\n pickerMode.value = 'mention'\n pickerFilter.value = state.filter\n pickerTriggerDom.value = containerRef.value ?? undefined\n } else if (pickerMode.value === 'mention') {\n closePicker()\n }\n}\n\nfunction closePicker() {\n pickerMode.value = null\n reselectingSegIdx.value = null\n pickerFilter.value = ''\n}\n\nonMounted(() => {\n if (!containerRef.value) return\n const initialDoc = parse(props.modelValue ?? '', variableMap.value)\n currentDoc.value = initialDoc\n\n const editor = createEditor({\n container: containerRef.value,\n cls,\n initialDoc,\n getVariableMap: () => variableMap.value,\n onChange: (doc) => {\n currentDoc.value = doc\n const value = serializeFromDoc(doc)\n if (value !== (props.modelValue ?? '')) emit('update:modelValue', value)\n syncMention()\n },\n onSelectionChange: () => {\n syncMention()\n },\n onChipReselect: ({ chipEl, segIndex }) => {\n if (disabled.value || readonly.value) return\n mention.commit()\n pickerMode.value = 'reselect'\n pickerFilter.value = ''\n pickerTriggerDom.value = chipEl\n reselectingSegIdx.value = segIndex\n },\n onChipRemove: ({ segIndex }) => {\n if (disabled.value || readonly.value) return\n editor.removeVarAt(segIndex)\n }\n })\n editorRef.value = editor\n})\n\nonBeforeUnmount(() => {\n editorRef.value?.dispose()\n})\n\nfunction serializeFromDoc(doc: Doc): string {\n let s = ''\n for (const seg of doc) s += seg.kind === 'text' ? seg.value : `{${seg.value}}`\n return s\n}\n\nwatch(\n () => props.modelValue,\n (v) => {\n const editor = editorRef.value\n if (!editor) return\n if (v === editor.getValue()) return\n editor.setValue(v ?? '')\n }\n)\n\nwatch(variableMap, () => {\n // variables 变化:重渲染以刷新 chip label / type\n const editor = editorRef.value\n if (!editor) return\n editor.setValue(editor.getValue())\n})\n\nfunction onKeydown(e: KeyboardEvent) {\n if (disabled.value || readonly.value) return\n // mention / reselect 激活时,优先把箭头键 / Enter / Esc 转给 picker\n if (pickerMode.value !== null) {\n const handledByPicker = pickerRef.value?.handleKeydown(e)\n if (handledByPicker) {\n e.preventDefault()\n return\n }\n }\n\n if (pickerMode.value === 'mention') {\n // 这些键导致 mention 退出(保留 @filter 文本,光标继续移动)\n if (e.key === ' ' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n mention.dismiss()\n closePicker()\n }\n }\n}\n\nfunction onBlur() {\n if (pickerMode.value === 'mention') {\n mention.dismiss()\n // 下一帧再关闭,避免和 picker 内 click 冲突\n void nextTick(() => closePicker())\n }\n}\n\nfunction onPickerSelect(item: VariableItem) {\n const editor = editorRef.value\n if (!editor) return\n\n if (pickerMode.value === 'mention') {\n const state = mention.getState()\n if (!state) return\n const anchor = state.anchorOffset\n const caret = editor.getCaretOffset() ?? anchor + state.filter.length + 1\n editor.replaceRangeWithVar(anchor, caret, {\n value: item.value,\n label: item.label,\n ...(item.type ? { type: item.type } : {})\n })\n mention.commit()\n } else if (pickerMode.value === 'reselect') {\n const idx = reselectingSegIdx.value\n if (idx !== null) {\n editor.replaceVarAt(idx, {\n value: item.value,\n label: item.label,\n ...(item.type ? { type: item.type } : {})\n })\n }\n }\n closePicker()\n}\n\nfunction onPickerDismiss() {\n if (pickerMode.value === 'mention') mention.dismiss()\n closePicker()\n}\n\nfunction onPickerVisibleChange(v: boolean) {\n if (!v && pickerMode.value !== null) {\n if (pickerMode.value === 'mention') mention.dismiss()\n closePicker()\n }\n}\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"expression-editor.js","names":[],"sources":["../../../src/components/expression-editor/expression-editor.vue"],"sourcesContent":["<template>\n <div :class=\"className\">\n <div\n ref=\"container\"\n :class=\"cls.e('container')\"\n :contenteditable=\"!readonly && !disabled\"\n :data-empty=\"isEmpty || undefined\"\n :data-placeholder=\"props.placeholder\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n ></div>\n\n <div v-if=\"showPlaceholder\" :class=\"cls.e('placeholder')\">\n {{ props.placeholder }}\n </div>\n\n <VariablePicker\n ref=\"pickerRef\"\n :visible=\"pickerVisible\"\n :trigger-dom=\"pickerTriggerDom\"\n :variables=\"props.variables\"\n :filter=\"pickerFilter\"\n :selectable-levels=\"props.selectableLevels ?? 'leaf'\"\n @select=\"onPickerSelect\"\n @dismiss=\"onPickerDismiss\"\n @update:visible=\"onPickerVisibleChange\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { bem } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n shallowRef,\n useTemplateRef,\n watch\n} from 'vue'\n\nimport type { ExpressionEditorProps, VariableItem } from '../../types'\nimport VariablePicker from './components/variable-picker.vue'\nimport { createEditor, type EditorAPI } from './core/editor'\nimport { createMention, type MentionAPI } from './core/mention'\nimport { parse, type Doc } from './core/model'\nimport { createVariableMap } from './di'\n\ndefineOptions({ name: 'ExpressionEditor' })\n\nconst props = withDefaults(defineProps<ExpressionEditorProps>(), {\n placeholder: '请输入表达式,输入 @ 可插入变量',\n selectableLevels: 'leaf'\n})\n\nconst emit = defineEmits<{ (e: 'update:modelValue', value: string): void }>()\n\nconst cls = bem('expression-editor')\nconst { formProps } = injectFormContext()\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst containerRef = useTemplateRef<HTMLDivElement>('container')\nconst pickerRef = useTemplateRef<{ handleKeydown: (e: KeyboardEvent) => boolean }>('pickerRef')\n\nconst className = computed(() => [\n cls.b,\n cls.m(size.value),\n bem.is('disabled', disabled.value),\n bem.is('readonly', readonly.value)\n])\n\nconst variableMap = computed(() => createVariableMap(props.variables))\n\nconst editorRef = shallowRef<EditorAPI | null>(null)\nconst mention: MentionAPI = createMention()\n\nconst currentDoc = shallowRef<Doc>([])\nconst isEmpty = computed(() => currentDoc.value.length === 0)\nconst showPlaceholder = computed(() => isEmpty.value && !disabled.value)\n\nconst pickerMode = shallowRef<'mention' | 'reselect' | null>(null)\nconst pickerTriggerDom = shallowRef<HTMLElement | undefined>(undefined)\nconst reselectingSegIdx = shallowRef<number | null>(null)\nconst pickerFilter = shallowRef('')\n\nconst pickerVisible = computed(() => pickerMode.value !== null)\n\nfunction syncMention() {\n const editor = editorRef.value\n if (!editor) return\n if (pickerMode.value === 'reselect') return\n const caret = editor.getCaretOffset()\n const state = mention.update(currentDoc.value, caret)\n if (state) {\n pickerMode.value = 'mention'\n pickerFilter.value = state.filter\n pickerTriggerDom.value = containerRef.value ?? undefined\n } else if (pickerMode.value === 'mention') {\n closePicker()\n }\n}\n\nfunction closePicker() {\n pickerMode.value = null\n reselectingSegIdx.value = null\n pickerFilter.value = ''\n}\n\nonMounted(() => {\n if (!containerRef.value) return\n const initialDoc = parse(props.modelValue ?? '', variableMap.value)\n currentDoc.value = initialDoc\n\n const editor = createEditor({\n container: containerRef.value,\n cls,\n initialDoc,\n getVariableMap: () => variableMap.value,\n onChange: (doc) => {\n currentDoc.value = doc\n const value = serializeFromDoc(doc)\n if (value !== (props.modelValue ?? '')) emit('update:modelValue', value)\n syncMention()\n },\n onSelectionChange: () => {\n syncMention()\n },\n onChipReselect: ({ chipEl, segIndex }) => {\n if (disabled.value || readonly.value) return\n mention.commit()\n pickerMode.value = 'reselect'\n pickerFilter.value = ''\n pickerTriggerDom.value = chipEl\n reselectingSegIdx.value = segIndex\n },\n onChipRemove: ({ segIndex }) => {\n if (disabled.value || readonly.value) return\n editor.removeVarAt(segIndex)\n }\n })\n editorRef.value = editor\n})\n\nonBeforeUnmount(() => {\n editorRef.value?.dispose()\n})\n\nfunction serializeFromDoc(doc: Doc): string {\n let s = ''\n for (const seg of doc) s += seg.kind === 'text' ? seg.value : `{${seg.value}}`\n return s\n}\n\nwatch(\n () => props.modelValue,\n (v) => {\n const editor = editorRef.value\n if (!editor) return\n if (v === editor.getValue()) return\n editor.setValue(v ?? '')\n }\n)\n\nwatch(variableMap, () => {\n // variables 变化:重渲染以刷新 chip label / type\n const editor = editorRef.value\n if (!editor) return\n editor.setValue(editor.getValue())\n})\n\nfunction onKeydown(e: KeyboardEvent) {\n if (disabled.value || readonly.value) return\n // mention / reselect 激活时,优先把箭头键 / Enter / Esc 转给 picker\n if (pickerMode.value !== null) {\n const handledByPicker = pickerRef.value?.handleKeydown(e)\n if (handledByPicker) {\n e.preventDefault()\n return\n }\n }\n\n if (pickerMode.value === 'mention') {\n // 这些键导致 mention 退出(保留 @filter 文本,光标继续移动)\n if (e.key === ' ' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n mention.dismiss()\n closePicker()\n }\n }\n}\n\nfunction onBlur() {\n if (pickerMode.value === 'mention') {\n mention.dismiss()\n // 下一帧再关闭,避免和 picker 内 click 冲突\n void nextTick(() => closePicker())\n }\n}\n\nfunction onPickerSelect(item: VariableItem) {\n const editor = editorRef.value\n if (!editor) return\n\n if (pickerMode.value === 'mention') {\n const state = mention.getState()\n if (!state) return\n const anchor = state.anchorOffset\n const caret = editor.getCaretOffset() ?? anchor + state.filter.length + 1\n editor.replaceRangeWithVar(anchor, caret, {\n value: item.value,\n label: item.label,\n ...(item.type ? { type: item.type } : {})\n })\n mention.commit()\n } else if (pickerMode.value === 'reselect') {\n const idx = reselectingSegIdx.value\n if (idx !== null) {\n editor.replaceVarAt(idx, {\n value: item.value,\n label: item.label,\n ...(item.type ? { type: item.type } : {})\n })\n }\n }\n closePicker()\n}\n\nfunction onPickerDismiss() {\n if (pickerMode.value === 'mention') mention.dismiss()\n closePicker()\n}\n\nfunction onPickerVisibleChange(v: boolean) {\n if (!v && pickerMode.value !== null) {\n if (pickerMode.value === 'mention') mention.dismiss()\n closePicker()\n }\n}\n</script>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-picker.js","names":[],"sources":["../../../src/components/file-picker/file-picker.vue"],"sourcesContent":["<template>\n <component\n :is=\"tag\"\n :class=\"cls.b\"\n @click.stop=\"handleClickPicker\"\n @dragover.prevent=\"handleDragover\"\n @dragleave=\"handleDragLeave\"\n @drop.prevent=\"handleDrop\"\n >\n <input\n :multiple=\"multiple\"\n :class=\"cls.e('native')\"\n type=\"file\"\n :accept=\"accept\"\n hidden\n placeholder=\"选择文件\"\n ref=\"fileRef\"\n @change=\"handleChange\"\n capture=\"environment\"\n />\n <slot :is-dragover=\"isDragover\" />\n </component>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { shallowRef, ref } from 'vue'\n\nimport type { UploaderProps, UploaderEmits } from '../../types'\nimport { matchAccept } from './helper'\n\ndefineOptions({\n name: 'FilePicker'\n})\n\nconst props = withDefaults(defineProps<UploaderProps>(), {\n tag: 'div',\n multiple: false\n})\n\nconst emit = defineEmits<UploaderEmits>()\n\nconst cls = bem('file-picker')\n\nconst fileRef = shallowRef<HTMLInputElement>()\nconst isDragover = ref(false)\n\nconst processFiles = (files: File[]) => {\n const filteredFiles = files.filter((file) => matchAccept(file, props.accept))\n emit('pick', filteredFiles)\n}\n\nconst handleChange = (e: Event) => {\n const target = e.target as HTMLInputElement\n const files = Array.from(target.files || [])\n processFiles(files)\n target.value = ''\n}\n\nconst handleDragover = (e: DragEvent) => {\n if (props.disabled) return\n isDragover.value = true\n}\n\nconst handleDragLeave = (e: DragEvent) => {\n if (props.disabled) return\n const currentTarget = e.currentTarget as HTMLElement\n const relatedTarget = e.relatedTarget as HTMLElement | null\n\n if (currentTarget.contains(relatedTarget)) return\n isDragover.value = false\n}\n\nconst handleDrop = (e: DragEvent) => {\n if (props.disabled) return\n isDragover.value = false\n const files = Array.from(e.dataTransfer?.files || [])\n processFiles(files)\n}\n\nfunction handleClickPicker() {\n if (props.disabled) return\n fileRef.value?.click()\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;EAmCA,MAAM,QAAQ;EAKd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,cAAa;EAE7B,MAAM,UAAU,YAA6B;EAC7C,MAAM,aAAa,IAAI,MAAK;EAE5B,MAAM,gBAAgB,UAAkB;GAEtC,KAAK,QADiB,MAAM,QAAQ,SAAS,YAAY,MAAM,MAAM,OAAO,CAClD,CAAA;;EAG5B,MAAM,gBAAgB,MAAa;GACjC,MAAM,SAAS,EAAE;GAEjB,aADc,MAAM,KAAK,OAAO,SAAS,EAAE,CACzB,CAAA;GAClB,OAAO,QAAQ;;EAGjB,MAAM,kBAAkB,MAAiB;GACvC,IAAI,MAAM,UAAU;GACpB,WAAW,QAAQ;;EAGrB,MAAM,mBAAmB,MAAiB;GACxC,IAAI,MAAM,UAAU;GACpB,MAAM,gBAAgB,EAAE;GACxB,MAAM,gBAAgB,EAAE;GAExB,IAAI,cAAc,SAAS,cAAa,EAAG;GAC3C,WAAW,QAAQ;;EAGrB,MAAM,cAAc,MAAiB;GACnC,IAAI,MAAM,UAAU;GACpB,WAAW,QAAQ;GAEnB,aADc,MAAM,KAAK,EAAE,cAAc,SAAS,EAAE,CAClC,CAAA;;EAGpB,SAAS,oBAAoB;GAC3B,IAAI,MAAM,UAAU;GACpB,QAAQ,OAAO,OAAM;;;uBAjFrB,YAoBY,wBAnBL,QAAA,IAAG,EAAA;IACP,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC;IACZ,SAAK,cAAO,mBAAiB,CAAA,OAAA,CAAA;IAC7B,YAAQ,cAAU,gBAAc,CAAA,UAAA,CAAA;IAChC,aAAW;IACX,QAAI,cAAU,YAAU,CAAA,UAAA,CAAA;;2BAYvB,CAVF,mBAUE,SAAA;KATC,UAAU,QAAA;KACV,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,SAAA,CAAA;KACb,MAAK;KACJ,QAAQ,QAAA;KACT,QAAA;KACA,aAAY;cACR;KAAJ,KAAI;KACH,UAAQ;KACT,SAAQ;8BAEV,WAAkC,KAAA,QAAA,WAAA,EAA3B,YAAa,WAAA,OAAU,CAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"file-picker.js","names":[],"sources":["../../../src/components/file-picker/file-picker.vue"],"sourcesContent":["<template>\n <component\n :is=\"tag\"\n :class=\"cls.b\"\n @click.stop=\"handleClickPicker\"\n @dragover.prevent=\"handleDragover\"\n @dragleave=\"handleDragLeave\"\n @drop.prevent=\"handleDrop\"\n >\n <input\n :multiple=\"multiple\"\n :class=\"cls.e('native')\"\n type=\"file\"\n :accept=\"accept\"\n hidden\n placeholder=\"选择文件\"\n ref=\"fileRef\"\n @change=\"handleChange\"\n capture=\"environment\"\n />\n <slot :is-dragover=\"isDragover\" />\n </component>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { shallowRef, ref } from 'vue'\n\nimport type { UploaderProps, UploaderEmits } from '../../types'\nimport { matchAccept } from './helper'\n\ndefineOptions({ name: 'FilePicker' })\n\nconst props = withDefaults(defineProps<UploaderProps>(), { tag: 'div', multiple: false })\n\nconst emit = defineEmits<UploaderEmits>()\n\nconst cls = bem('file-picker')\n\nconst fileRef = shallowRef<HTMLInputElement>()\nconst isDragover = ref(false)\n\nconst processFiles = (files: File[]) => {\n const filteredFiles = files.filter((file) => matchAccept(file, props.accept))\n emit('pick', filteredFiles)\n}\n\nconst handleChange = (e: Event) => {\n const target = e.target as HTMLInputElement\n const files = Array.from(target.files || [])\n processFiles(files)\n target.value = ''\n}\n\nconst handleDragover = (e: DragEvent) => {\n if (props.disabled) return\n isDragover.value = true\n}\n\nconst handleDragLeave = (e: DragEvent) => {\n if (props.disabled) return\n const currentTarget = e.currentTarget as HTMLElement\n const relatedTarget = e.relatedTarget as HTMLElement | null\n\n if (currentTarget.contains(relatedTarget)) return\n isDragover.value = false\n}\n\nconst handleDrop = (e: DragEvent) => {\n if (props.disabled) return\n isDragover.value = false\n const files = Array.from(e.dataTransfer?.files || [])\n processFiles(files)\n}\n\nfunction handleClickPicker() {\n if (props.disabled) return\n fileRef.value?.click()\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;EAiCA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,cAAa;EAE7B,MAAM,UAAU,YAA6B;EAC7C,MAAM,aAAa,IAAI,MAAK;EAE5B,MAAM,gBAAgB,UAAkB;GAEtC,KAAK,QADiB,MAAM,QAAQ,SAAS,YAAY,MAAM,MAAM,OAAO,CAClD,CAAA;;EAG5B,MAAM,gBAAgB,MAAa;GACjC,MAAM,SAAS,EAAE;GAEjB,aADc,MAAM,KAAK,OAAO,SAAS,EAAE,CACzB,CAAA;GAClB,OAAO,QAAQ;;EAGjB,MAAM,kBAAkB,MAAiB;GACvC,IAAI,MAAM,UAAU;GACpB,WAAW,QAAQ;;EAGrB,MAAM,mBAAmB,MAAiB;GACxC,IAAI,MAAM,UAAU;GACpB,MAAM,gBAAgB,EAAE;GACxB,MAAM,gBAAgB,EAAE;GAExB,IAAI,cAAc,SAAS,cAAa,EAAG;GAC3C,WAAW,QAAQ;;EAGrB,MAAM,cAAc,MAAiB;GACnC,IAAI,MAAM,UAAU;GACpB,WAAW,QAAQ;GAEnB,aADc,MAAM,KAAK,EAAE,cAAc,SAAS,EAAE,CAClC,CAAA;;EAGpB,SAAS,oBAAoB;GAC3B,IAAI,MAAM,UAAU;GACpB,QAAQ,OAAO,OAAM;;;uBA5ErB,YAoBY,wBAnBL,QAAA,IAAG,EAAA;IACP,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC;IACZ,SAAK,cAAO,mBAAiB,CAAA,OAAA,CAAA;IAC7B,YAAQ,cAAU,gBAAc,CAAA,UAAA,CAAA;IAChC,aAAW;IACX,QAAI,cAAU,YAAU,CAAA,UAAA,CAAA;;2BAYvB,CAVF,mBAUE,SAAA;KATC,UAAU,QAAA;KACV,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,SAAA,CAAA;KACb,MAAK;KACJ,QAAQ,QAAA;KACT,QAAA;KACA,aAAY;cACR;KAAJ,KAAI;KACH,UAAQ;KACT,SAAQ;8BAEV,WAAkC,KAAA,QAAA,WAAA,EAA3B,YAAa,WAAA,OAAU,CAAA,CAAA,CAAA"}
@@ -13,8 +13,8 @@ declare const __VLS_base: _$vue.DefineComponent<UploaderProps, {}, {}, {}, {}, _
13
13
  }, string, _$vue.PublicProps, Readonly<UploaderProps> & Readonly<{
14
14
  onPick?: ((files: File[]) => any) | undefined;
15
15
  }>, {
16
- multiple: boolean;
17
16
  tag: string;
17
+ multiple: boolean;
18
18
  }, {}, {}, {}, string, _$vue.ComponentProvideOptions, false, {}, any>;
19
19
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
20
20
  declare const _default: typeof __VLS_export;
@@ -1 +1 @@
1
- {"version":3,"file":"file-viewer.js","names":[],"sources":["../../../src/components/file-viewer/file-viewer.vue"],"sourcesContent":["<template>\n <Teleport to=\"body\" :disabled=\"!isModal\">\n <transition :name=\"isModal ? 'u-file-viewer-modal' : ''\">\n <div\n v-if=\"!isModal || openModel\"\n :class=\"[cls.b, bem.is('modal', isModal)]\"\n :tabindex=\"isModal ? -1 : undefined\"\n ref=\"rootRef\"\n @mousedown.self=\"handleBackdropMousedown\"\n >\n <div v-if=\"isModal\" :class=\"cls.e('backdrop')\" @mousedown.self=\"handleBackdropMousedown\" />\n <div :class=\"cls.e('inner')\">\n <aside v-if=\"showSidebar\" :class=\"cls.e('sidebar')\" :style=\"{ width: sidebarWidthCss }\">\n <header :class=\"cls.e('sidebar-head')\">\n <span :class=\"cls.e('sidebar-title')\">文件</span>\n <span :class=\"cls.e('sidebar-count')\">{{ normalizedFiles.length }}</span>\n </header>\n <u-scroll tag=\"ul\" :class=\"cls.e('list')\">\n <li\n v-for=\"f in normalizedFiles\"\n :key=\"f.id\"\n :class=\"[cls.e('item'), bem.is('active', f.id === activeId)]\"\n :title=\"f.name\"\n @click=\"activate(f.id)\"\n >\n <span :class=\"cls.e('item-meta')\">\n <span :class=\"cls.e('item-name')\" :title=\"f.name\">{{ f.name }}</span>\n <span :class=\"cls.e('item-size')\">{{ formatBytes(f.size) }}</span>\n </span>\n <span :class=\"cls.e('item-kind')\">{{ label(f.kind) }}</span>\n </li>\n <li v-if=\"!normalizedFiles.length\" :class=\"cls.e('list-empty')\">\n <u-empty text=\"暂无文件\" :size=\"32\" />\n </li>\n </u-scroll>\n </aside>\n\n <section :class=\"cls.e('stage')\">\n <header :class=\"cls.e('stage-head')\">\n <div :class=\"cls.e('stage-title')\">\n <span v-if=\"activeFile\" :class=\"[cls.e('badge'), cls.em('badge', activeFile.kind)]\">\n {{ label(activeFile.kind) }}\n </span>\n <span :class=\"cls.e('stage-copy')\">\n <span :class=\"cls.e('stage-name')\" :title=\"activeFile?.name\">\n {{ activeFile?.name ?? '—' }}\n </span>\n <span v-if=\"activeFile\" :class=\"cls.e('stage-sub')\">\n <span>{{ activeIndexLabel }}</span>\n <span v-if=\"activeFile.size\">{{ formatBytes(activeFile.size) }}</span>\n </span>\n </span>\n </div>\n <div :class=\"cls.e('stage-actions')\">\n <span :class=\"cls.e('action-group')\">\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"!hasPrev\"\n type=\"button\"\n aria-label=\"上一个\"\n title=\"上一个\"\n @click=\"prev\"\n >\n <u-icon :size=\"15\">\n <ArrowLeft />\n </u-icon>\n </button>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"!hasNext\"\n type=\"button\"\n aria-label=\"下一个\"\n title=\"下一个\"\n @click=\"next\"\n >\n <u-icon :size=\"15\">\n <ArrowRight />\n </u-icon>\n </button>\n </span>\n <span v-if=\"isZoomable\" :class=\"cls.e('action-group')\">\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"zoomOutDisabled\"\n type=\"button\"\n aria-label=\"缩小\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n <u-icon :size=\"15\">\n <ZoomOut />\n </u-icon>\n </button>\n <span :class=\"cls.e('zoom-value')\">{{ zoomPercent }}</span>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"zoomInDisabled\"\n type=\"button\"\n aria-label=\"放大\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n <u-icon :size=\"15\">\n <ZoomIn />\n </u-icon>\n </button>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"isTransformReset\"\n type=\"button\"\n aria-label=\"重置视图\"\n title=\"重置视图\"\n @click=\"resetTransform\"\n >\n <u-icon :size=\"15\">\n <Refresh />\n </u-icon>\n </button>\n </span>\n <button\n v-if=\"downloadable && activeFile\"\n :class=\"[cls.e('action'), cls.em('action', 'primary'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"下载\"\n title=\"下载\"\n @click=\"download\"\n >\n <u-icon :size=\"15\">\n <Download />\n </u-icon>\n </button>\n <button\n v-if=\"isModal\"\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"关闭预览\"\n title=\"关闭\"\n @click=\"handleClose\"\n >\n <u-icon :size=\"16\">\n <Close />\n </u-icon>\n </button>\n </div>\n </header>\n <div :class=\"cls.e('body')\">\n <transition name=\"u-file-viewer-fade\" mode=\"out-in\">\n <div\n v-if=\"activeFile\"\n :key=\"activeFile.id\"\n :class=\"[\n cls.e('viewport'),\n bem.is('transformable', isTransformable),\n bem.is('pannable', canPan),\n bem.is('dragging', isDragging)\n ]\"\n @pointerdown.capture=\"handleViewportPointerDown\"\n @pointermove.capture=\"handleViewportPointerMove\"\n @pointerup.capture=\"handleViewportPointerEnd\"\n @pointercancel.capture=\"handleViewportPointerEnd\"\n @wheel=\"handleViewportWheel\"\n @dblclick=\"handleViewportDblclick\"\n >\n <component\n :is=\"PreviewerMap[activeFile.kind]\"\n ref=\"previewerRef\"\n :file=\"activeFile\"\n :max-rows=\"sheetMaxRows\"\n :class=\"isTransformable ? cls.e('previewer') : undefined\"\n :style=\"previewerStyle\"\n @error=\"handleChildError\"\n @zoom-change=\"handlePdfZoomChange\"\n />\n </div>\n <div v-else :class=\"cls.e('empty')\">\n <u-empty text=\"暂无可预览文件\" />\n </div>\n </transition>\n </div>\n </section>\n </div>\n </div>\n </transition>\n </Teleport>\n</template>\n\n<script lang=\"ts\" setup>\nimport {\n ArrowLeft,\n ArrowRight,\n Close,\n Download,\n Refresh,\n ZoomIn,\n ZoomOut\n} from '@veltra/icons/normal'\nimport { bem, withUnit } from '@veltra/utils'\nimport {\n computed,\n defineAsyncComponent,\n nextTick,\n onBeforeUnmount,\n ref,\n shallowRef,\n watch\n} from 'vue'\nimport type { CSSProperties } from 'vue'\n\nimport type {\n _FileViewerExposed,\n FileViewerEmits,\n FileViewerItem,\n FileViewerKind,\n FileViewerProps\n} from '../../types/file-viewer'\nimport { UEmpty } from '../empty'\nimport { UIcon } from '../icon'\nimport { UScroll } from '../scroll'\nimport { FILE_VIEWER_KIND_LABEL, downloadFile, formatBytes, inferKind } from './helper'\n\ndefineOptions({\n name: 'FileViewer',\n inheritAttrs: false\n})\n\nconst props = withDefaults(defineProps<FileViewerProps>(), {\n modelValue: undefined,\n sidebarWidth: '280px',\n sheetMaxRows: 50_000,\n downloadable: true,\n open: undefined,\n closeOnClickBackdrop: true,\n closeOnEsc: true\n})\n\nconst emit = defineEmits<FileViewerEmits>()\n\nconst cls = bem('file-viewer')\n\nconst MIN_SCALE = 0.5\nconst MAX_SCALE = 3\n/** 每次缩放固定增减 10% */\nconst SCALE_STEP = 0.1\n/** 使用 CSS transform 缩放的类型(PDF 由 EmbedPDF zoom 插件处理) */\nconst TRANSFORMABLE_KINDS = new Set<FileViewerKind>(['image'])\n/** 工具栏显示缩放控件的类型 */\nconst ZOOMABLE_KINDS = new Set<FileViewerKind>(['image', 'pdf'])\n\nconst activeId = defineModel<string | undefined>('modelValue', { default: undefined })\nconst openModel = defineModel<boolean | undefined>('open', { default: undefined })\n\nconst rootRef = shallowRef<HTMLDivElement>()\nconst previewerRef = shallowRef<{\n zoomIn?: () => void\n zoomOut?: () => void\n resetZoom?: () => void\n}>()\nconst scale = ref(1)\nconst pdfZoomLevel = ref(1)\nconst offsetX = ref(0)\nconst offsetY = ref(0)\nconst isDragging = ref(false)\n\nlet dragState:\n | {\n pointerId: number\n startX: number\n startY: number\n originX: number\n originY: number\n }\n | undefined\n\nconst PreviewerMap: Record<FileViewerKind, ReturnType<typeof defineAsyncComponent>> = {\n image: defineAsyncComponent(() => import('./previewers/image-previewer.vue')),\n video: defineAsyncComponent(() => import('./previewers/video-previewer.vue')),\n pdf: defineAsyncComponent(() => import('./previewers/pdf-previewer.vue')),\n sheet: defineAsyncComponent(() => import('./previewers/sheet-previewer.vue')),\n docx: defineAsyncComponent(() => import('./previewers/docx-previewer.vue')),\n text: defineAsyncComponent(() => import('./previewers/text-previewer.vue'))\n}\n\ninterface NormalizedFile extends FileViewerItem {\n id: string\n kind: FileViewerKind\n}\n\nconst normalizedFiles = computed<NormalizedFile[]>(() =>\n props.files.map((f, i) => ({\n ...f,\n id: f.id ?? `file-${i}`,\n kind: inferKind(f.name, f.kind)\n }))\n)\n\nconst activeFile = computed<NormalizedFile | undefined>(() =>\n normalizedFiles.value.find((f) => f.id === activeId.value)\n)\n\nconst activeIndex = computed(() => normalizedFiles.value.findIndex((f) => f.id === activeId.value))\n\nconst hasPrev = computed(() => activeIndex.value > 0)\nconst hasNext = computed(\n () => activeIndex.value >= 0 && activeIndex.value < normalizedFiles.value.length - 1\n)\n\nconst showSidebar = computed(() => props.sidebarWidth !== false && props.sidebarWidth !== 0)\n\nconst sidebarWidthCss = computed(() => {\n const w = props.sidebarWidth\n if (w === false || w === 0) return undefined\n return withUnit(w ?? '280px', 'px')\n})\n\n/** 是否启用模态模式:只要父组件显式传入 open(含 v-model:open),即进入模态 */\nconst isModal = computed(() => openModel.value !== undefined)\n\nconst activeIndexLabel = computed(() =>\n activeIndex.value >= 0 ? `${activeIndex.value + 1} / ${normalizedFiles.value.length}` : ''\n)\n\nconst isTransformable = computed(\n () => !!activeFile.value && TRANSFORMABLE_KINDS.has(activeFile.value.kind)\n)\n\nconst isZoomable = computed(() => !!activeFile.value && ZOOMABLE_KINDS.has(activeFile.value.kind))\n\nconst isPdfActive = computed(() => activeFile.value?.kind === 'pdf')\n\nconst canPan = computed(() => isTransformable.value && scale.value > 1)\n\nconst displayZoomLevel = computed(() => (isPdfActive.value ? pdfZoomLevel.value : scale.value))\n\nconst zoomPercent = computed(() => `${Math.round(displayZoomLevel.value * 100)}%`)\n\nconst zoomInDisabled = computed(() => !isZoomable.value || displayZoomLevel.value >= MAX_SCALE)\n\nconst zoomOutDisabled = computed(() => !isZoomable.value || displayZoomLevel.value <= MIN_SCALE)\n\nconst isTransformReset = computed(() => {\n if (isPdfActive.value) {\n return Math.abs(pdfZoomLevel.value - 1) < 0.02\n }\n return scale.value === 1 && offsetX.value === 0 && offsetY.value === 0\n})\n\nconst previewerStyle = computed<CSSProperties | undefined>(() => {\n if (!isTransformable.value) return undefined\n return {\n transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value})`\n }\n})\n\nfunction label(kind: FileViewerKind): string {\n return FILE_VIEWER_KIND_LABEL[kind]\n}\n\nfunction activate(id: string) {\n if (activeId.value === id) return\n activeId.value = id\n const f = normalizedFiles.value.find((x) => x.id === id)\n if (f) emit('change', f)\n}\n\nfunction prev() {\n const i = activeIndex.value\n if (i <= 0) return\n const target = normalizedFiles.value[i - 1]\n if (target) activate(target.id)\n}\n\nfunction next() {\n const i = activeIndex.value\n if (i < 0 || i >= normalizedFiles.value.length - 1) return\n const target = normalizedFiles.value[i + 1]\n if (target) activate(target.id)\n}\n\nfunction normalizeScale(value: number): number {\n const clamped = Math.min(MAX_SCALE, Math.max(MIN_SCALE, value))\n return Math.round(clamped * 100) / 100\n}\n\nfunction setScale(value: number) {\n scale.value = normalizeScale(value)\n if (scale.value <= 1) {\n offsetX.value = 0\n offsetY.value = 0\n }\n}\n\nfunction zoomIn() {\n if (!isZoomable.value) return\n if (isPdfActive.value) {\n previewerRef.value?.zoomIn?.()\n return\n }\n setScale(scale.value + SCALE_STEP)\n}\n\nfunction zoomOut() {\n if (!isZoomable.value) return\n if (isPdfActive.value) {\n previewerRef.value?.zoomOut?.()\n return\n }\n setScale(scale.value - SCALE_STEP)\n}\n\nfunction resetTransform() {\n if (isPdfActive.value) {\n previewerRef.value?.resetZoom?.()\n pdfZoomLevel.value = 1\n return\n }\n scale.value = 1\n offsetX.value = 0\n offsetY.value = 0\n dragState = undefined\n isDragging.value = false\n}\n\nfunction handlePdfZoomChange(level: number) {\n pdfZoomLevel.value = level\n}\n\nfunction isZoomWheel(e: WheelEvent): boolean {\n return e.ctrlKey || e.metaKey\n}\n\nfunction handleViewportWheel(e: WheelEvent) {\n if (!activeFile.value || activeFile.value.kind !== 'image') return\n if (!isZoomWheel(e)) return\n if (isInteractiveTarget(e.target)) return\n e.preventDefault()\n const delta = e.deltaY > 0 ? -SCALE_STEP : SCALE_STEP\n setScale(scale.value + delta)\n}\n\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false\n return !!target.closest('button, a, input, textarea, select, video, [contenteditable=\"true\"]')\n}\n\nfunction handleViewportPointerDown(e: PointerEvent) {\n if (!canPan.value || e.button !== 0 || isInteractiveTarget(e.target)) return\n\n dragState = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n originX: offsetX.value,\n originY: offsetY.value\n }\n isDragging.value = true\n const el = e.currentTarget as HTMLElement\n el.setPointerCapture(e.pointerId)\n e.preventDefault()\n}\n\nfunction handleViewportPointerMove(e: PointerEvent) {\n if (!dragState || dragState.pointerId !== e.pointerId) return\n offsetX.value = dragState.originX + e.clientX - dragState.startX\n offsetY.value = dragState.originY + e.clientY - dragState.startY\n}\n\nfunction handleViewportPointerEnd(e: PointerEvent) {\n if (!dragState || dragState.pointerId !== e.pointerId) return\n const el = e.currentTarget as HTMLElement\n if (el.hasPointerCapture(e.pointerId)) {\n el.releasePointerCapture(e.pointerId)\n }\n dragState = undefined\n isDragging.value = false\n}\n\nfunction handleViewportDblclick() {\n if (isPdfActive.value) return\n if (!isTransformable.value) return\n if (scale.value === 1) {\n setScale(2)\n } else {\n resetTransform()\n }\n}\n\nasync function download() {\n if (!activeFile.value) return\n try {\n await downloadFile(activeFile.value)\n } catch (err) {\n emit('error', { file: activeFile.value, error: err })\n }\n}\n\nfunction handleChildError(err: unknown) {\n if (!activeFile.value) return\n emit('error', { file: activeFile.value, error: err })\n}\n\nfunction handleClose() {\n if (!isModal.value) return\n openModel.value = false\n}\n\nfunction handleWindowKeydown(e: KeyboardEvent) {\n if (e.key !== 'Escape') return\n if (!isModal.value || !openModel.value) return\n if (props.closeOnEsc === false) return\n e.stopPropagation()\n handleClose()\n}\n\nfunction handleBackdropMousedown() {\n if (!isModal.value) return\n if (props.closeOnClickBackdrop === false) return\n handleClose()\n}\n\nwatch(\n normalizedFiles,\n (files) => {\n if (!files.length) {\n activeId.value = undefined\n return\n }\n if (!activeId.value || !files.some((f) => f.id === activeId.value)) {\n activeId.value = files[0]!.id\n }\n },\n { immediate: true }\n)\n\nwatch(\n () => activeFile.value?.id,\n async () => {\n pdfZoomLevel.value = 1\n await nextTick()\n resetTransform()\n }\n)\n\n// 模态打开时:锁定 body 滚动 + 让容器获得焦点以便接收 ESC\nlet previousBodyOverflow = ''\nlet isBodyLocked = false\n\nfunction lockBody() {\n if (isBodyLocked || typeof document === 'undefined') return\n previousBodyOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n isBodyLocked = true\n}\n\nfunction unlockBody() {\n if (!isBodyLocked || typeof document === 'undefined') return\n document.body.style.overflow = previousBodyOverflow\n isBodyLocked = false\n}\n\nwatch(\n [isModal, openModel],\n ([modal, open]) => {\n if (modal && open) {\n lockBody()\n nextTick(() => {\n rootRef.value?.focus()\n })\n if (typeof window !== 'undefined') {\n window.addEventListener('keydown', handleWindowKeydown, true)\n }\n } else {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n }\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n})\n\ndefineExpose<_FileViewerExposed>({\n activeId,\n activate,\n next,\n prev\n})\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;AA+OA,MAAM,YAAY;AAClB,MAAM,YAAY;;AAElB,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAjBnB,MAAM,QAAQ;EAUd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,cAAa;EAO7B,MAAM,sBAAsB,IAAI,IAAoB,CAAC,QAAQ,CAAA;;EAE7D,MAAM,iBAAiB,IAAI,IAAoB,CAAC,SAAS,MAAM,CAAA;EAE/D,MAAM,WAAW,SAA+B,SAAC,aAAoC;EACrF,MAAM,YAAY,SAAgC,SAAC,OAA8B;EAEjF,MAAM,UAAU,YAA2B;EAC3C,MAAM,eAAe,YAIlB;EACH,MAAM,QAAQ,IAAI,EAAC;EACnB,MAAM,eAAe,IAAI,EAAC;EAC1B,MAAM,UAAU,IAAI,EAAC;EACrB,MAAM,UAAU,IAAI,EAAC;EACrB,MAAM,aAAa,IAAI,MAAK;EAE5B,IAAI;EAUJ,MAAM,eAAgF;GACpF,OAAO,2BAA2B,OAAO,mCAAmC;GAC5E,OAAO,2BAA2B,OAAO,mCAAmC;GAC5E,KAAK,2BAA2B,OAAO,iCAAiC;GACxE,OAAO,2BAA2B,OAAO,mCAAmC;GAC5E,MAAM,2BAA2B,OAAO,kCAAkC;GAC1E,MAAM,2BAA2B,OAAO,kCAAkC;GAC5E;EAOA,MAAM,kBAAkB,eACtB,MAAM,MAAM,KAAK,GAAG,OAAO;GACzB,GAAG;GACH,IAAI,EAAE,MAAM,QAAQ;GACpB,MAAM,UAAU,EAAE,MAAM,EAAE,KAAI;GAChC,EACF,CAAA;EAEA,MAAM,aAAa,eACjB,gBAAgB,MAAM,MAAM,MAAM,EAAE,OAAO,SAAS,MACtD,CAAA;EAEA,MAAM,cAAc,eAAe,gBAAgB,MAAM,WAAW,MAAM,EAAE,OAAO,SAAS,MAAM,CAAA;EAElG,MAAM,UAAU,eAAe,YAAY,QAAQ,EAAC;EACpD,MAAM,UAAU,eACR,YAAY,SAAS,KAAK,YAAY,QAAQ,gBAAgB,MAAM,SAAS,EACrF;EAEA,MAAM,cAAc,eAAe,MAAM,iBAAiB,SAAS,MAAM,iBAAiB,EAAC;EAE3F,MAAM,kBAAkB,eAAe;GACrC,MAAM,IAAI,MAAM;GAChB,IAAI,MAAM,SAAS,MAAM,GAAG,OAAO,KAAA;GACnC,OAAO,SAAS,KAAK,SAAS,KAAI;IACnC;;EAGD,MAAM,UAAU,eAAe,UAAU,UAAU,KAAA,EAAS;EAE5D,MAAM,mBAAmB,eACvB,YAAY,SAAS,IAAI,GAAG,YAAY,QAAQ,EAAE,KAAK,gBAAgB,MAAM,WAAW,GAC1F;EAEA,MAAM,kBAAkB,eAChB,CAAC,CAAC,WAAW,SAAS,oBAAoB,IAAI,WAAW,MAAM,KACvE,CAAA;EAEA,MAAM,aAAa,eAAe,CAAC,CAAC,WAAW,SAAS,eAAe,IAAI,WAAW,MAAM,KAAK,CAAA;EAEjG,MAAM,cAAc,eAAe,WAAW,OAAO,SAAS,MAAK;EAEnE,MAAM,SAAS,eAAe,gBAAgB,SAAS,MAAM,QAAQ,EAAC;EAEtE,MAAM,mBAAmB,eAAgB,YAAY,QAAQ,aAAa,QAAQ,MAAM,MAAM;EAE9F,MAAM,cAAc,eAAe,GAAG,KAAK,MAAM,iBAAiB,QAAQ,IAAG,CAAE,GAAE;EAEjF,MAAM,iBAAiB,eAAe,CAAC,WAAW,SAAS,iBAAiB,SAAS,UAAS;EAE9F,MAAM,kBAAkB,eAAe,CAAC,WAAW,SAAS,iBAAiB,SAAS,UAAS;EAE/F,MAAM,mBAAmB,eAAe;GACtC,IAAI,YAAY,OACd,OAAO,KAAK,IAAI,aAAa,QAAQ,EAAC,GAAI;GAE5C,OAAO,MAAM,UAAU,KAAK,QAAQ,UAAU,KAAK,QAAQ,UAAU;IACtE;EAED,MAAM,iBAAiB,eAA0C;GAC/D,IAAI,CAAC,gBAAgB,OAAO,OAAO,KAAA;GACnC,OAAO,EACL,WAAW,eAAe,QAAQ,MAAM,MAAM,QAAQ,MAAM,eAAe,MAAM,MAAM,IACzF;IACD;EAED,SAAS,MAAM,MAA8B;GAC3C,OAAO,uBAAuB;;EAGhC,SAAS,SAAS,IAAY;GAC5B,IAAI,SAAS,UAAU,IAAI;GAC3B,SAAS,QAAQ;GACjB,MAAM,IAAI,gBAAgB,MAAM,MAAM,MAAM,EAAE,OAAO,GAAE;GACvD,IAAI,GAAG,KAAK,UAAU,EAAC;;EAGzB,SAAS,OAAO;GACd,MAAM,IAAI,YAAY;GACtB,IAAI,KAAK,GAAG;GACZ,MAAM,SAAS,gBAAgB,MAAM,IAAI;GACzC,IAAI,QAAQ,SAAS,OAAO,GAAE;;EAGhC,SAAS,OAAO;GACd,MAAM,IAAI,YAAY;GACtB,IAAI,IAAI,KAAK,KAAK,gBAAgB,MAAM,SAAS,GAAG;GACpD,MAAM,SAAS,gBAAgB,MAAM,IAAI;GACzC,IAAI,QAAQ,SAAS,OAAO,GAAE;;EAGhC,SAAS,eAAe,OAAuB;GAE7C,OAAO,KAAK,MADI,KAAK,IAAI,WAAW,KAAK,IAAI,WAAW,MAAM,CAC5C,GAAU,IAAG,GAAI;;EAGrC,SAAS,SAAS,OAAe;GAC/B,MAAM,QAAQ,eAAe,MAAK;GAClC,IAAI,MAAM,SAAS,GAAG;IACpB,QAAQ,QAAQ;IAChB,QAAQ,QAAQ;;;EAIpB,SAAS,SAAS;GAChB,IAAI,CAAC,WAAW,OAAO;GACvB,IAAI,YAAY,OAAO;IACrB,aAAa,OAAO,UAAS;IAC7B;;GAEF,SAAS,MAAM,QAAQ,WAAU;;EAGnC,SAAS,UAAU;GACjB,IAAI,CAAC,WAAW,OAAO;GACvB,IAAI,YAAY,OAAO;IACrB,aAAa,OAAO,WAAU;IAC9B;;GAEF,SAAS,MAAM,QAAQ,WAAU;;EAGnC,SAAS,iBAAiB;GACxB,IAAI,YAAY,OAAO;IACrB,aAAa,OAAO,aAAY;IAChC,aAAa,QAAQ;IACrB;;GAEF,MAAM,QAAQ;GACd,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB,YAAY,KAAA;GACZ,WAAW,QAAQ;;EAGrB,SAAS,oBAAoB,OAAe;GAC1C,aAAa,QAAQ;;EAGvB,SAAS,YAAY,GAAwB;GAC3C,OAAO,EAAE,WAAW,EAAE;;EAGxB,SAAS,oBAAoB,GAAe;GAC1C,IAAI,CAAC,WAAW,SAAS,WAAW,MAAM,SAAS,SAAS;GAC5D,IAAI,CAAC,YAAY,EAAC,EAAG;GACrB,IAAI,oBAAoB,EAAE,OAAM,EAAG;GACnC,EAAE,gBAAe;GACjB,MAAM,QAAQ,EAAE,SAAS,IAAI,CAAC,aAAa;GAC3C,SAAS,MAAM,QAAQ,MAAK;;EAG9B,SAAS,oBAAoB,QAAqC;GAChE,IAAI,EAAE,kBAAkB,cAAc,OAAO;GAC7C,OAAO,CAAC,CAAC,OAAO,QAAQ,wEAAqE;;EAG/F,SAAS,0BAA0B,GAAiB;GAClD,IAAI,CAAC,OAAO,SAAS,EAAE,WAAW,KAAK,oBAAoB,EAAE,OAAM,EAAG;GAEtE,YAAY;IACV,WAAW,EAAE;IACb,QAAQ,EAAE;IACV,QAAQ,EAAE;IACV,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACnB;GACA,WAAW,QAAQ;GAEnB,EADa,cACV,kBAAkB,EAAE,UAAS;GAChC,EAAE,gBAAe;;EAGnB,SAAS,0BAA0B,GAAiB;GAClD,IAAI,CAAC,aAAa,UAAU,cAAc,EAAE,WAAW;GACvD,QAAQ,QAAQ,UAAU,UAAU,EAAE,UAAU,UAAU;GAC1D,QAAQ,QAAQ,UAAU,UAAU,EAAE,UAAU,UAAU;;EAG5D,SAAS,yBAAyB,GAAiB;GACjD,IAAI,CAAC,aAAa,UAAU,cAAc,EAAE,WAAW;GACvD,MAAM,KAAK,EAAE;GACb,IAAI,GAAG,kBAAkB,EAAE,UAAS,EAClC,GAAG,sBAAsB,EAAE,UAAS;GAEtC,YAAY,KAAA;GACZ,WAAW,QAAQ;;EAGrB,SAAS,yBAAyB;GAChC,IAAI,YAAY,OAAO;GACvB,IAAI,CAAC,gBAAgB,OAAO;GAC5B,IAAI,MAAM,UAAU,GAClB,SAAS,EAAC;QAEV,gBAAe;;EAInB,eAAe,WAAW;GACxB,IAAI,CAAC,WAAW,OAAO;GACvB,IAAI;IACF,MAAM,aAAa,WAAW,MAAK;YAC5B,KAAK;IACZ,KAAK,SAAS;KAAE,MAAM,WAAW;KAAO,OAAO;KAAK,CAAA;;;EAIxD,SAAS,iBAAiB,KAAc;GACtC,IAAI,CAAC,WAAW,OAAO;GACvB,KAAK,SAAS;IAAE,MAAM,WAAW;IAAO,OAAO;IAAK,CAAA;;EAGtD,SAAS,cAAc;GACrB,IAAI,CAAC,QAAQ,OAAO;GACpB,UAAU,QAAQ;;EAGpB,SAAS,oBAAoB,GAAkB;GAC7C,IAAI,EAAE,QAAQ,UAAU;GACxB,IAAI,CAAC,QAAQ,SAAS,CAAC,UAAU,OAAO;GACxC,IAAI,MAAM,eAAe,OAAO;GAChC,EAAE,iBAAgB;GAClB,aAAY;;EAGd,SAAS,0BAA0B;GACjC,IAAI,CAAC,QAAQ,OAAO;GACpB,IAAI,MAAM,yBAAyB,OAAO;GAC1C,aAAY;;EAGd,MACE,kBACC,UAAU;GACT,IAAI,CAAC,MAAM,QAAQ;IACjB,SAAS,QAAQ,KAAA;IACjB;;GAEF,IAAI,CAAC,SAAS,SAAS,CAAC,MAAM,MAAM,MAAM,EAAE,OAAO,SAAS,MAAK,EAC/D,SAAS,QAAQ,MAAM,GAAI;KAG/B,EAAE,WAAW,MACf,CAAA;EAEA,YACQ,WAAW,OAAO,IACxB,YAAY;GACV,aAAa,QAAQ;GACrB,MAAM,UAAS;GACf,gBAAe;IAEnB;EAGA,IAAI,uBAAuB;EAC3B,IAAI,eAAe;EAEnB,SAAS,WAAW;GAClB,IAAI,gBAAgB,OAAO,aAAa,aAAa;GACrD,uBAAuB,SAAS,KAAK,MAAM;GAC3C,SAAS,KAAK,MAAM,WAAW;GAC/B,eAAe;;EAGjB,SAAS,aAAa;GACpB,IAAI,CAAC,gBAAgB,OAAO,aAAa,aAAa;GACtD,SAAS,KAAK,MAAM,WAAW;GAC/B,eAAe;;EAGjB,MACE,CAAC,SAAS,UAAS,GAClB,CAAC,OAAO,UAAU;GACjB,IAAI,SAAS,MAAM;IACjB,UAAS;IACT,eAAe;KACb,QAAQ,OAAO,OAAM;MACtB;IACD,IAAI,OAAO,WAAW,aACpB,OAAO,iBAAiB,WAAW,qBAAqB,KAAI;UAEzD;IACL,YAAW;IACX,IAAI,OAAO,WAAW,aACpB,OAAO,oBAAoB,WAAW,qBAAqB,KAAI;;KAIrE,EAAE,WAAW,MACf,CAAA;EAEA,sBAAsB;GACpB,YAAW;GACX,IAAI,OAAO,WAAW,aACpB,OAAO,oBAAoB,WAAW,qBAAqB,KAAI;IAElE;EAED,SAAiC;GAC/B;GACA;GACA;GACA;GACD,CAAA;;uBA/kBC,YAsLW,UAAA;IAtLD,IAAG;IAAQ,UAAQ,CAAG,QAAA;OAC9B,YAoLa,YAAA,EApLA,MAAM,QAAA,QAAO,wBAAA,IAAA,EAAA;2BAmLlB,CAAA,CAjLG,QAAA,SAAW,UAAA,SAAA,WAAA,EADpB,mBAkLM,OAAA;;KAhLH,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,GAAG,MAAA,IAAA,CAAI,GAAE,SAAU,QAAA,MAAO,CAAA,CAAA;KACtC,UAAU,QAAA,QAAO,KAAQ,KAAA;cACtB;KAAJ,KAAI;KACH,aAAS,cAAO,yBAAuB,CAAA,OAAA,CAAA;QAE7B,QAAA,SAAA,WAAA,EAAX,mBAA2F,OAAA;;KAAtE,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,WAAA,CAAA;KAAe,aAAS,cAAO,yBAAuB,CAAA,OAAA,CAAA;sDACvF,mBAyKM,OAAA,EAzKA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,QAAA,CAAA,EAAA,EAAA,CACH,YAAA,SAAA,WAAA,EAAb,mBAuBQ,SAAA;;KAvBmB,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,UAAA,CAAA;KAAc,OAAK,eAAA,EAAA,OAAW,gBAAA,OAAe,CAAA;QAClF,mBAGS,UAAA,EAHA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,eAAA,CAAA,EAAA,EAAA,CACnB,mBAA+C,QAAA,EAAxC,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,gBAAA,CAAA,EAAA,EAAmB,MAAE,EAAA,EACxC,mBAAyE,QAAA,EAAlE,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,gBAAA,CAAA,EAAA,EAAA,gBAAsB,gBAAA,MAAgB,OAAM,EAAA,EAAA,CAAA,EAAA,EAAA,EAEjE,YAiBW,MAAA,YAAA,EAAA;KAjBD,KAAI;KAAM,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,OAAA,CAAA;;4BAEA,EAAA,UAAA,KAAA,EAD9B,mBAYK,UAAA,MAAA,WAXS,gBAAA,QAAL,MAAC;0BADV,mBAYK,MAAA;OAVF,KAAK,EAAE;OACP,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,OAAA,EAAU,MAAA,IAAA,CAAI,GAAE,UAAW,EAAE,OAAO,SAAA,MAAQ,CAAA,CAAA;OACzD,OAAO,EAAE;OACT,UAAK,WAAE,SAAS,EAAE,GAAE;UAErB,mBAGO,QAAA,EAHA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,YAAA,CAAA,EAAA,EAAA,CACjB,mBAAqE,QAAA;OAA9D,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,YAAA,CAAA;OAAgB,OAAO,EAAE;yBAAS,EAAE,KAAI,EAAA,IAAA,WAAA,EAC3D,mBAAkE,QAAA,EAA3D,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,YAAA,CAAA,EAAA,EAAA,gBAAkB,MAAA,YAAA,CAAY,EAAE,KAAI,CAAA,EAAA,EAAA,CAAA,EAAA,EAAA,EAEzD,mBAA4D,QAAA,EAArD,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,YAAA,CAAA,EAAA,EAAA,gBAAkB,MAAM,EAAE,KAAI,CAAA,EAAA,EAAA,CAAA,EAAA,IAAA,WAAA;iBAExC,gBAAA,MAAgB,UAAA,WAAA,EAA3B,mBAEK,MAAA;;MAF+B,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,aAAA,CAAA;SAC9C,YAAkC,MAAA,YAAA,EAAA;MAAzB,MAAK;MAAQ,MAAM;;;+DAKlC,mBA8IU,WAAA,EA9IA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,QAAA,CAAA,EAAA,EAAA,CACpB,mBA0GS,UAAA,EA1GA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,aAAA,CAAA,EAAA,EAAA,CACnB,mBAaM,OAAA,EAbA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,cAAA,CAAA,EAAA,EAAA,CACJ,WAAA,SAAA,WAAA,EAAZ,mBAEO,QAAA;;KAFkB,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,QAAA,EAAW,MAAA,IAAA,CAAI,GAAE,SAAU,WAAA,MAAW,KAAI,CAAA,CAAA;uBAC3E,MAAM,WAAA,MAAW,KAAI,CAAA,EAAA,EAAA,IAAA,mBAAA,QAAA,KAAA,EAE1B,mBAQO,QAAA,EARA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,aAAA,CAAA,EAAA,EAAA,CACjB,mBAEO,QAAA;KAFA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,aAAA,CAAA;KAAiB,OAAO,WAAA,OAAY;uBAClD,WAAA,OAAY,QAAI,IAAA,EAAA,IAAA,WAAA,EAET,WAAA,SAAA,WAAA,EAAZ,mBAGO,QAAA;;KAHkB,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,YAAA,CAAA;QACnC,mBAAmC,QAAA,MAAA,gBAA1B,iBAAA,MAAgB,EAAA,EAAA,EACb,WAAA,MAAW,QAAA,WAAA,EAAvB,mBAAsE,QAAA,YAAA,gBAAtC,MAAA,YAAA,CAAY,WAAA,MAAW,KAAI,CAAA,EAAA,EAAA,IAAA,mBAAA,QAAA,KAAA,CAAA,EAAA,EAAA,IAAA,mBAAA,QAAA,KAAA,CAAA,EAAA,EAAA,CAAA,EAAA,EAAA,EAIjE,mBA0FM,OAAA,EA1FA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,gBAAA,CAAA,EAAA,EAAA;KAChB,mBAyBO,QAAA,EAzBA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,eAAA,CAAA,EAAA,EAAA,CACjB,mBAWS,UAAA;MAVN,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,SAAA,EAAY,MAAA,IAAA,CAAI,GAAE,UAAA,OAAA,CAAA,CAAA;MAC/B,UAAQ,CAAG,QAAA;MACZ,MAAK;MACL,cAAW;MACX,OAAM;MACL,SAAO;SAER,YAES,MAAA,YAAA,EAAA,EAFA,MAAM,IAAE,EAAA;6BACF,CAAb,YAAa,MAAA,UAAA,CAAA,CAAA,CAAA;;2BAGjB,mBAWS,UAAA;MAVN,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,SAAA,EAAY,MAAA,IAAA,CAAI,GAAE,UAAA,OAAA,CAAA,CAAA;MAC/B,UAAQ,CAAG,QAAA;MACZ,MAAK;MACL,cAAW;MACX,OAAM;MACL,SAAO;SAER,YAES,MAAA,YAAA,EAAA,EAFA,MAAM,IAAE,EAAA;6BACD,CAAd,YAAc,MAAA,WAAA,CAAA,CAAA,CAAA;;;KAIR,WAAA,SAAA,WAAA,EAAZ,mBAsCO,QAAA;;MAtCkB,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,eAAA,CAAA;;MACnC,mBAWS,UAAA;OAVN,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,SAAA,EAAY,MAAA,IAAA,CAAI,GAAE,UAAA,OAAA,CAAA,CAAA;OAC/B,UAAU,gBAAA;OACX,MAAK;OACL,cAAW;OACX,OAAM;OACL,SAAO;UAER,YAES,MAAA,YAAA,EAAA,EAFA,MAAM,IAAE,EAAA;8BACJ,CAAX,YAAW,MAAA,QAAA,CAAA,CAAA,CAAA;;;MAGf,mBAA2D,QAAA,EAApD,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,aAAA,CAAA,EAAA,EAAA,gBAAmB,YAAA,MAAW,EAAA,EAAA;MACjD,mBAWS,UAAA;OAVN,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,SAAA,EAAY,MAAA,IAAA,CAAI,GAAE,UAAA,OAAA,CAAA,CAAA;OAC/B,UAAU,eAAA;OACX,MAAK;OACL,cAAW;OACX,OAAM;OACL,SAAO;UAER,YAES,MAAA,YAAA,EAAA,EAFA,MAAM,IAAE,EAAA;8BACL,CAAV,YAAU,MAAA,OAAA,CAAA,CAAA,CAAA;;;MAGd,mBAWS,UAAA;OAVN,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,SAAA,EAAY,MAAA,IAAA,CAAI,GAAE,UAAA,OAAA,CAAA,CAAA;OAC/B,UAAU,iBAAA;OACX,MAAK;OACL,cAAW;OACX,OAAM;OACL,SAAO;UAER,YAES,MAAA,YAAA,EAAA,EAFA,MAAM,IAAE,EAAA;8BACJ,CAAX,YAAW,MAAA,QAAA,CAAA,CAAA,CAAA;;;;KAKT,QAAA,gBAAgB,WAAA,SAAA,WAAA,EADxB,mBAWS,UAAA;;MATN,OAAK,eAAA;OAAG,MAAA,IAAA,CAAI,EAAC,SAAA;OAAY,MAAA,IAAA,CAAI,GAAE,UAAA,UAAA;OAAuB,MAAA,IAAA,CAAI,GAAE,UAAA,OAAA;OAAA,CAAA;MAC7D,MAAK;MACL,cAAW;MACX,OAAM;MACL,SAAO;SAER,YAES,MAAA,YAAA,EAAA,EAFA,MAAM,IAAE,EAAA;6BACH,CAAZ,YAAY,MAAA,SAAA,CAAA,CAAA,CAAA;;;KAIR,QAAA,SAAA,WAAA,EADR,mBAWS,UAAA;;MATN,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,SAAA,EAAY,MAAA,IAAA,CAAI,GAAE,UAAA,OAAA,CAAA,CAAA;MAChC,MAAK;MACL,cAAW;MACX,OAAM;MACL,SAAO;SAER,YAES,MAAA,YAAA,EAAA,EAFA,MAAM,IAAE,EAAA;6BACN,CAAT,YAAS,MAAA,MAAA,CAAA,CAAA,CAAA;;;gBAKjB,mBAiCM,OAAA,EAjCA,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,OAAA,CAAA,EAAA,EAAA,CAChB,YA+Ba,YAAA;KA/BD,MAAK;KAAqB,MAAK;;4BA2BnC,CAzBE,WAAA,SAAA,WAAA,EADR,mBA0BM,OAAA;MAxBH,KAAK,WAAA,MAAW;MAChB,OAAK,eAAA;OAAwB,MAAA,IAAA,CAAI,EAAC,WAAA;OAAkC,MAAA,IAAA,CAAI,GAAE,iBAAkB,gBAAA,MAAe;OAAuB,MAAA,IAAA,CAAI,GAAE,YAAa,OAAA,MAAM;OAAuB,MAAA,IAAA,CAAI,GAAE,YAAa,WAAA,MAAU;;4BAM1L;4BACA;0BACF;8BACI;MACvB,SAAO;MACP,YAAU;uBAEX,YASE,wBARK,aAAa,WAAA,MAAW,MAAI,EAAA;eAC7B;MAAJ,KAAI;MACH,MAAM,WAAA;MACN,YAAU,QAAA;MACV,OAAK,eAAE,gBAAA,QAAkB,MAAA,IAAA,CAAI,EAAC,YAAA,GAAgB,KAAA,EAAS;MACvD,OAAK,eAAE,eAAA,MAAc;MACrB,SAAO;MACP,cAAa;;;;;;gCAGlB,mBAEM,OAAA;;MAFO,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,QAAA,CAAA;SACvB,YAA0B,MAAA,YAAA,EAAA,EAAjB,MAAK,WAAS,CAAA,CAAA,EAAA,EAAA,EAAA,CAAA"}
1
+ {"version":3,"file":"file-viewer.js","names":[],"sources":["../../../src/components/file-viewer/file-viewer.vue"],"sourcesContent":["<template>\n <Teleport to=\"body\" :disabled=\"!isModal\">\n <transition :name=\"isModal ? 'u-file-viewer-modal' : ''\">\n <div\n v-if=\"!isModal || openModel\"\n :class=\"[cls.b, bem.is('modal', isModal)]\"\n :tabindex=\"isModal ? -1 : undefined\"\n ref=\"rootRef\"\n @mousedown.self=\"handleBackdropMousedown\"\n >\n <div v-if=\"isModal\" :class=\"cls.e('backdrop')\" @mousedown.self=\"handleBackdropMousedown\" />\n <div :class=\"cls.e('inner')\">\n <aside v-if=\"showSidebar\" :class=\"cls.e('sidebar')\" :style=\"{ width: sidebarWidthCss }\">\n <header :class=\"cls.e('sidebar-head')\">\n <span :class=\"cls.e('sidebar-title')\">文件</span>\n <span :class=\"cls.e('sidebar-count')\">{{ normalizedFiles.length }}</span>\n </header>\n <u-scroll tag=\"ul\" :class=\"cls.e('list')\">\n <li\n v-for=\"f in normalizedFiles\"\n :key=\"f.id\"\n :class=\"[cls.e('item'), bem.is('active', f.id === activeId)]\"\n :title=\"f.name\"\n @click=\"activate(f.id)\"\n >\n <span :class=\"cls.e('item-meta')\">\n <span :class=\"cls.e('item-name')\" :title=\"f.name\">{{ f.name }}</span>\n <span :class=\"cls.e('item-size')\">{{ formatBytes(f.size) }}</span>\n </span>\n <span :class=\"cls.e('item-kind')\">{{ label(f.kind) }}</span>\n </li>\n <li v-if=\"!normalizedFiles.length\" :class=\"cls.e('list-empty')\">\n <u-empty text=\"暂无文件\" :size=\"32\" />\n </li>\n </u-scroll>\n </aside>\n\n <section :class=\"cls.e('stage')\">\n <header :class=\"cls.e('stage-head')\">\n <div :class=\"cls.e('stage-title')\">\n <span v-if=\"activeFile\" :class=\"[cls.e('badge'), cls.em('badge', activeFile.kind)]\">\n {{ label(activeFile.kind) }}\n </span>\n <span :class=\"cls.e('stage-copy')\">\n <span :class=\"cls.e('stage-name')\" :title=\"activeFile?.name\">\n {{ activeFile?.name ?? '—' }}\n </span>\n <span v-if=\"activeFile\" :class=\"cls.e('stage-sub')\">\n <span>{{ activeIndexLabel }}</span>\n <span v-if=\"activeFile.size\">{{ formatBytes(activeFile.size) }}</span>\n </span>\n </span>\n </div>\n <div :class=\"cls.e('stage-actions')\">\n <span :class=\"cls.e('action-group')\">\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"!hasPrev\"\n type=\"button\"\n aria-label=\"上一个\"\n title=\"上一个\"\n @click=\"prev\"\n >\n <u-icon :size=\"15\">\n <ArrowLeft />\n </u-icon>\n </button>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"!hasNext\"\n type=\"button\"\n aria-label=\"下一个\"\n title=\"下一个\"\n @click=\"next\"\n >\n <u-icon :size=\"15\">\n <ArrowRight />\n </u-icon>\n </button>\n </span>\n <span v-if=\"isZoomable\" :class=\"cls.e('action-group')\">\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"zoomOutDisabled\"\n type=\"button\"\n aria-label=\"缩小\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n <u-icon :size=\"15\">\n <ZoomOut />\n </u-icon>\n </button>\n <span :class=\"cls.e('zoom-value')\">{{ zoomPercent }}</span>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"zoomInDisabled\"\n type=\"button\"\n aria-label=\"放大\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n <u-icon :size=\"15\">\n <ZoomIn />\n </u-icon>\n </button>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"isTransformReset\"\n type=\"button\"\n aria-label=\"重置视图\"\n title=\"重置视图\"\n @click=\"resetTransform\"\n >\n <u-icon :size=\"15\">\n <Refresh />\n </u-icon>\n </button>\n </span>\n <button\n v-if=\"downloadable && activeFile\"\n :class=\"[cls.e('action'), cls.em('action', 'primary'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"下载\"\n title=\"下载\"\n @click=\"download\"\n >\n <u-icon :size=\"15\">\n <Download />\n </u-icon>\n </button>\n <button\n v-if=\"isModal\"\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"关闭预览\"\n title=\"关闭\"\n @click=\"handleClose\"\n >\n <u-icon :size=\"16\">\n <Close />\n </u-icon>\n </button>\n </div>\n </header>\n <div :class=\"cls.e('body')\">\n <transition name=\"u-file-viewer-fade\" mode=\"out-in\">\n <div\n v-if=\"activeFile\"\n :key=\"activeFile.id\"\n :class=\"[\n cls.e('viewport'),\n bem.is('transformable', isTransformable),\n bem.is('pannable', canPan),\n bem.is('dragging', isDragging)\n ]\"\n @pointerdown.capture=\"handleViewportPointerDown\"\n @pointermove.capture=\"handleViewportPointerMove\"\n @pointerup.capture=\"handleViewportPointerEnd\"\n @pointercancel.capture=\"handleViewportPointerEnd\"\n @wheel=\"handleViewportWheel\"\n @dblclick=\"handleViewportDblclick\"\n >\n <component\n :is=\"PreviewerMap[activeFile.kind]\"\n ref=\"previewerRef\"\n :file=\"activeFile\"\n :max-rows=\"sheetMaxRows\"\n :class=\"isTransformable ? cls.e('previewer') : undefined\"\n :style=\"previewerStyle\"\n @error=\"handleChildError\"\n @zoom-change=\"handlePdfZoomChange\"\n />\n </div>\n <div v-else :class=\"cls.e('empty')\">\n <u-empty text=\"暂无可预览文件\" />\n </div>\n </transition>\n </div>\n </section>\n </div>\n </div>\n </transition>\n </Teleport>\n</template>\n\n<script lang=\"ts\" setup>\nimport {\n ArrowLeft,\n ArrowRight,\n Close,\n Download,\n Refresh,\n ZoomIn,\n ZoomOut\n} from '@veltra/icons/normal'\nimport { bem, withUnit } from '@veltra/utils'\nimport {\n computed,\n defineAsyncComponent,\n nextTick,\n onBeforeUnmount,\n ref,\n shallowRef,\n watch\n} from 'vue'\nimport type { CSSProperties } from 'vue'\n\nimport type {\n _FileViewerExposed,\n FileViewerEmits,\n FileViewerItem,\n FileViewerKind,\n FileViewerProps\n} from '../../types/file-viewer'\nimport { UEmpty } from '../empty'\nimport { UIcon } from '../icon'\nimport { UScroll } from '../scroll'\nimport { FILE_VIEWER_KIND_LABEL, downloadFile, formatBytes, inferKind } from './helper'\n\ndefineOptions({ name: 'FileViewer', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FileViewerProps>(), {\n modelValue: undefined,\n sidebarWidth: '280px',\n sheetMaxRows: 50_000,\n downloadable: true,\n open: undefined,\n closeOnClickBackdrop: true,\n closeOnEsc: true\n})\n\nconst emit = defineEmits<FileViewerEmits>()\n\nconst cls = bem('file-viewer')\n\nconst MIN_SCALE = 0.5\nconst MAX_SCALE = 3\n/** 每次缩放固定增减 10% */\nconst SCALE_STEP = 0.1\n/** 使用 CSS transform 缩放的类型(PDF 由 EmbedPDF zoom 插件处理) */\nconst TRANSFORMABLE_KINDS = new Set<FileViewerKind>(['image'])\n/** 工具栏显示缩放控件的类型 */\nconst ZOOMABLE_KINDS = new Set<FileViewerKind>(['image', 'pdf'])\n\nconst activeId = defineModel<string | undefined>('modelValue', { default: undefined })\nconst openModel = defineModel<boolean | undefined>('open', { default: undefined })\n\nconst rootRef = shallowRef<HTMLDivElement>()\nconst previewerRef = shallowRef<{\n zoomIn?: () => void\n zoomOut?: () => void\n resetZoom?: () => void\n}>()\nconst scale = ref(1)\nconst pdfZoomLevel = ref(1)\nconst offsetX = ref(0)\nconst offsetY = ref(0)\nconst isDragging = ref(false)\n\nlet dragState:\n | { pointerId: number; startX: number; startY: number; originX: number; originY: number }\n | undefined\n\nconst PreviewerMap: Record<FileViewerKind, ReturnType<typeof defineAsyncComponent>> = {\n image: defineAsyncComponent(() => import('./previewers/image-previewer.vue')),\n video: defineAsyncComponent(() => import('./previewers/video-previewer.vue')),\n pdf: defineAsyncComponent(() => import('./previewers/pdf-previewer.vue')),\n sheet: defineAsyncComponent(() => import('./previewers/sheet-previewer.vue')),\n docx: defineAsyncComponent(() => import('./previewers/docx-previewer.vue')),\n text: defineAsyncComponent(() => import('./previewers/text-previewer.vue'))\n}\n\ninterface NormalizedFile extends FileViewerItem {\n id: string\n kind: FileViewerKind\n}\n\nconst normalizedFiles = computed<NormalizedFile[]>(() =>\n props.files.map((f, i) => ({ ...f, id: f.id ?? `file-${i}`, kind: inferKind(f.name, f.kind) }))\n)\n\nconst activeFile = computed<NormalizedFile | undefined>(() =>\n normalizedFiles.value.find((f) => f.id === activeId.value)\n)\n\nconst activeIndex = computed(() => normalizedFiles.value.findIndex((f) => f.id === activeId.value))\n\nconst hasPrev = computed(() => activeIndex.value > 0)\nconst hasNext = computed(\n () => activeIndex.value >= 0 && activeIndex.value < normalizedFiles.value.length - 1\n)\n\nconst showSidebar = computed(() => props.sidebarWidth !== false && props.sidebarWidth !== 0)\n\nconst sidebarWidthCss = computed(() => {\n const w = props.sidebarWidth\n if (w === false || w === 0) return undefined\n return withUnit(w ?? '280px', 'px')\n})\n\n/** 是否启用模态模式:只要父组件显式传入 open(含 v-model:open),即进入模态 */\nconst isModal = computed(() => openModel.value !== undefined)\n\nconst activeIndexLabel = computed(() =>\n activeIndex.value >= 0 ? `${activeIndex.value + 1} / ${normalizedFiles.value.length}` : ''\n)\n\nconst isTransformable = computed(\n () => !!activeFile.value && TRANSFORMABLE_KINDS.has(activeFile.value.kind)\n)\n\nconst isZoomable = computed(() => !!activeFile.value && ZOOMABLE_KINDS.has(activeFile.value.kind))\n\nconst isPdfActive = computed(() => activeFile.value?.kind === 'pdf')\n\nconst canPan = computed(() => isTransformable.value && scale.value > 1)\n\nconst displayZoomLevel = computed(() => (isPdfActive.value ? pdfZoomLevel.value : scale.value))\n\nconst zoomPercent = computed(() => `${Math.round(displayZoomLevel.value * 100)}%`)\n\nconst zoomInDisabled = computed(() => !isZoomable.value || displayZoomLevel.value >= MAX_SCALE)\n\nconst zoomOutDisabled = computed(() => !isZoomable.value || displayZoomLevel.value <= MIN_SCALE)\n\nconst isTransformReset = computed(() => {\n if (isPdfActive.value) {\n return Math.abs(pdfZoomLevel.value - 1) < 0.02\n }\n return scale.value === 1 && offsetX.value === 0 && offsetY.value === 0\n})\n\nconst previewerStyle = computed<CSSProperties | undefined>(() => {\n if (!isTransformable.value) return undefined\n return {\n transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value})`\n }\n})\n\nfunction label(kind: FileViewerKind): string {\n return FILE_VIEWER_KIND_LABEL[kind]\n}\n\nfunction activate(id: string) {\n if (activeId.value === id) return\n activeId.value = id\n const f = normalizedFiles.value.find((x) => x.id === id)\n if (f) emit('change', f)\n}\n\nfunction prev() {\n const i = activeIndex.value\n if (i <= 0) return\n const target = normalizedFiles.value[i - 1]\n if (target) activate(target.id)\n}\n\nfunction next() {\n const i = activeIndex.value\n if (i < 0 || i >= normalizedFiles.value.length - 1) return\n const target = normalizedFiles.value[i + 1]\n if (target) activate(target.id)\n}\n\nfunction normalizeScale(value: number): number {\n const clamped = Math.min(MAX_SCALE, Math.max(MIN_SCALE, value))\n return Math.round(clamped * 100) / 100\n}\n\nfunction setScale(value: number) {\n scale.value = normalizeScale(value)\n if (scale.value <= 1) {\n offsetX.value = 0\n offsetY.value = 0\n }\n}\n\nfunction zoomIn() {\n if (!isZoomable.value) return\n if (isPdfActive.value) {\n previewerRef.value?.zoomIn?.()\n return\n }\n setScale(scale.value + SCALE_STEP)\n}\n\nfunction zoomOut() {\n if (!isZoomable.value) return\n if (isPdfActive.value) {\n previewerRef.value?.zoomOut?.()\n return\n }\n setScale(scale.value - SCALE_STEP)\n}\n\nfunction resetTransform() {\n if (isPdfActive.value) {\n previewerRef.value?.resetZoom?.()\n pdfZoomLevel.value = 1\n return\n }\n scale.value = 1\n offsetX.value = 0\n offsetY.value = 0\n dragState = undefined\n isDragging.value = false\n}\n\nfunction handlePdfZoomChange(level: number) {\n pdfZoomLevel.value = level\n}\n\nfunction isZoomWheel(e: WheelEvent): boolean {\n return e.ctrlKey || e.metaKey\n}\n\nfunction handleViewportWheel(e: WheelEvent) {\n if (!activeFile.value || activeFile.value.kind !== 'image') return\n if (!isZoomWheel(e)) return\n if (isInteractiveTarget(e.target)) return\n e.preventDefault()\n const delta = e.deltaY > 0 ? -SCALE_STEP : SCALE_STEP\n setScale(scale.value + delta)\n}\n\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false\n return !!target.closest('button, a, input, textarea, select, video, [contenteditable=\"true\"]')\n}\n\nfunction handleViewportPointerDown(e: PointerEvent) {\n if (!canPan.value || e.button !== 0 || isInteractiveTarget(e.target)) return\n\n dragState = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n originX: offsetX.value,\n originY: offsetY.value\n }\n isDragging.value = true\n const el = e.currentTarget as HTMLElement\n el.setPointerCapture(e.pointerId)\n e.preventDefault()\n}\n\nfunction handleViewportPointerMove(e: PointerEvent) {\n if (!dragState || dragState.pointerId !== e.pointerId) return\n offsetX.value = dragState.originX + e.clientX - dragState.startX\n offsetY.value = dragState.originY + e.clientY - dragState.startY\n}\n\nfunction handleViewportPointerEnd(e: PointerEvent) {\n if (!dragState || dragState.pointerId !== e.pointerId) return\n const el = e.currentTarget as HTMLElement\n if (el.hasPointerCapture(e.pointerId)) {\n el.releasePointerCapture(e.pointerId)\n }\n dragState = undefined\n isDragging.value = false\n}\n\nfunction handleViewportDblclick() {\n if (isPdfActive.value) return\n if (!isTransformable.value) return\n if (scale.value === 1) {\n setScale(2)\n } else {\n resetTransform()\n }\n}\n\nasync function download() {\n if (!activeFile.value) return\n try {\n await downloadFile(activeFile.value)\n } catch (err) {\n emit('error', { file: activeFile.value, error: err })\n }\n}\n\nfunction handleChildError(err: unknown) {\n if (!activeFile.value) return\n emit('error', { file: activeFile.value, error: err })\n}\n\nfunction handleClose() {\n if (!isModal.value) return\n openModel.value = false\n}\n\nfunction handleWindowKeydown(e: KeyboardEvent) {\n if (e.key !== 'Escape') return\n if (!isModal.value || !openModel.value) return\n if (props.closeOnEsc === false) return\n e.stopPropagation()\n handleClose()\n}\n\nfunction handleBackdropMousedown() {\n if (!isModal.value) return\n if (props.closeOnClickBackdrop === false) return\n handleClose()\n}\n\nwatch(\n normalizedFiles,\n (files) => {\n if (!files.length) {\n activeId.value = undefined\n return\n }\n if (!activeId.value || !files.some((f) => f.id === activeId.value)) {\n activeId.value = files[0]!.id\n }\n },\n { immediate: true }\n)\n\nwatch(\n () => activeFile.value?.id,\n async () => {\n pdfZoomLevel.value = 1\n await nextTick()\n resetTransform()\n }\n)\n\n// 模态打开时:锁定 body 滚动 + 让容器获得焦点以便接收 ESC\nlet previousBodyOverflow = ''\nlet isBodyLocked = false\n\nfunction lockBody() {\n if (isBodyLocked || typeof document === 'undefined') return\n previousBodyOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n isBodyLocked = true\n}\n\nfunction unlockBody() {\n if (!isBodyLocked || typeof document === 'undefined') return\n document.body.style.overflow = previousBodyOverflow\n isBodyLocked = false\n}\n\nwatch(\n [isModal, openModel],\n ([modal, open]) => {\n if (modal && open) {\n lockBody()\n nextTick(() => {\n rootRef.value?.focus()\n })\n if (typeof window !== 'undefined') {\n window.addEventListener('keydown', handleWindowKeydown, true)\n }\n } else {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n }\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n})\n\ndefineExpose<_FileViewerExposed>({ activeId, activate, next, prev })\n</script>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pdf-previewer.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/pdf-previewer.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('pdf')\" v-bind=\"attrs\">\n <div v-if=\"!engine || isLoading\" :class=\"cls.e('loading')\">正在加载 PDF 引擎…</div>\n <EmbedPDF v-else-if=\"pdfUrl\" :engine=\"engine\" :plugins=\"plugins\" v-slot=\"{ activeDocumentId }\">\n <PdfZoomBridge\n v-if=\"activeDocumentId\"\n :document-id=\"activeDocumentId\"\n @zoom-change=\"onZoomChange\"\n />\n <DocumentContent\n v-if=\"activeDocumentId\"\n :document-id=\"activeDocumentId\"\n v-slot=\"{ isLoaded }\"\n >\n <Viewport v-if=\"isLoaded\" :document-id=\"activeDocumentId\" :class=\"cls.e('pdf-viewport')\">\n <PdfViewportScroll>\n <ZoomGestureWrapper :document-id=\"activeDocumentId\" :enable-wheel=\"true\">\n <Scroller :document-id=\"activeDocumentId\">\n <template #default=\"{ page }\">\n <div\n :class=\"cls.e('pdf-page')\"\n :style=\"{ width: page.width + 'px', height: page.height + 'px' }\"\n >\n <RenderLayer :document-id=\"activeDocumentId\" :page-index=\"page.pageIndex\" />\n </div>\n </template>\n </Scroller>\n </ZoomGestureWrapper>\n </PdfViewportScroll>\n </Viewport>\n </DocumentContent>\n </EmbedPDF>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { createPluginRegistration } from '@embedpdf/core'\nimport { EmbedPDF } from '@embedpdf/core/vue'\nimport { usePdfiumEngine } from '@embedpdf/engines/vue'\nimport {\n DocumentContent,\n DocumentManagerPluginPackage\n} from '@embedpdf/plugin-document-manager/vue'\nimport { RenderLayer, RenderPluginPackage } from '@embedpdf/plugin-render/vue'\nimport { ScrollPluginPackage, Scroller } from '@embedpdf/plugin-scroll/vue'\nimport { ViewportPluginPackage, Viewport } from '@embedpdf/plugin-viewport/vue'\nimport {\n ZoomGestureWrapper,\n ZoomMode,\n ZoomPluginPackage,\n type ZoomScope\n} from '@embedpdf/plugin-zoom/vue'\nimport { bem } from '@veltra/utils'\nimport { computed, onBeforeUnmount, shallowRef, useAttrs, watch } from 'vue'\n\nimport type { FileViewerItem } from '../../../types/file-viewer'\nimport { toBlobUrl } from '../helper'\nimport PdfViewportScroll from './pdf-viewport-scroll.vue'\nimport PdfZoomBridge from './pdf-zoom-bridge.vue'\n\ndefineOptions({ name: 'FileViewerPdfPreviewer', inheritAttrs: false })\n\nconst props = defineProps<{ file: FileViewerItem }>()\n\nconst emit = defineEmits<{\n (e: 'error', err: unknown): void\n (e: 'zoom-change', level: number): void\n}>()\n\nconst cls = bem('file-viewer')\nconst attrs = useAttrs()\n\nconst { engine, isLoading, error } = usePdfiumEngine()\n\nconst pdfUrl = shallowRef<string>('')\nlet revoke: (() => void) | undefined\n\n/** 当前文档的 zoom API(由 PdfZoomBridge 注入) */\nlet zoomScope: ZoomScope | null = null\n\nfunction load() {\n revoke?.()\n const r = toBlobUrl(props.file.src, props.file.mime ?? 'application/pdf')\n pdfUrl.value = r.url\n revoke = r.revoke\n}\n\nconst plugins = computed(() => {\n if (!pdfUrl.value) return []\n return [\n createPluginRegistration(DocumentManagerPluginPackage, {\n initialDocuments: [{ url: pdfUrl.value }]\n }),\n createPluginRegistration(ViewportPluginPackage, { viewportGap: 0 }),\n createPluginRegistration(ScrollPluginPackage, { defaultBufferSize: 2 }),\n createPluginRegistration(RenderPluginPackage),\n createPluginRegistration(ZoomPluginPackage, {\n defaultZoomLevel: ZoomMode.FitPage,\n minZoom: 0.5,\n maxZoom: 3,\n zoomStep: 0.1\n })\n ]\n})\n\nfunction onZoomChange(payload: { level: number; scope: ZoomScope | null }) {\n zoomScope = payload.scope\n emit('zoom-change', payload.level)\n}\n\nfunction zoomIn() {\n zoomScope?.zoomIn()\n}\n\nfunction zoomOut() {\n zoomScope?.zoomOut()\n}\n\nfunction resetZoom() {\n zoomScope?.requestZoom(ZoomMode.FitPage)\n}\n\nwatch(\n () => props.file,\n () => load(),\n { immediate: true }\n)\n\nwatch(error, (err) => {\n if (err) emit('error', err)\n})\n\nonBeforeUnmount(() => {\n revoke?.()\n pdfUrl.value = ''\n zoomScope = null\n})\n\ndefineExpose({\n zoomIn,\n zoomOut,\n resetZoom\n})\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EA8DA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAKb,MAAM,MAAM,IAAI,cAAa;EAC7B,MAAM,QAAQ,UAAS;EAEvB,MAAM,EAAE,QAAQ,WAAW,UAAU,iBAAgB;EAErD,MAAM,SAAS,WAAmB,GAAE;EACpC,IAAI;;EAGJ,IAAI,YAA8B;EAElC,SAAS,OAAO;GACd,UAAS;GACT,MAAM,IAAI,UAAU,MAAM,KAAK,KAAK,MAAM,KAAK,QAAQ,kBAAiB;GACxE,OAAO,QAAQ,EAAE;GACjB,SAAS,EAAE;;EAGb,MAAM,UAAU,eAAe;GAC7B,IAAI,CAAC,OAAO,OAAO,OAAO,EAAC;GAC3B,OAAO;IACL,yBAAyB,8BAA8B,EACrD,kBAAkB,CAAC,EAAE,KAAK,OAAO,OAAO,CAAA,EACzC,CAAA;IACD,yBAAyB,uBAAuB,EAAE,aAAa,GAAG,CAAA;IAClE,yBAAyB,qBAAqB,EAAE,mBAAmB,GAAG,CAAA;IACtE,yBAAyB,oBAAmB;IAC5C,yBAAyB,mBAAmB;KAC1C,kBAAkB,SAAS;KAC3B,SAAS;KACT,SAAS;KACT,UAAU;KACX,CAAA;IACH;IACD;EAED,SAAS,aAAa,SAAqD;GACzE,YAAY,QAAQ;GACpB,KAAK,eAAe,QAAQ,MAAK;;EAGnC,SAAS,SAAS;GAChB,WAAW,QAAO;;EAGpB,SAAS,UAAU;GACjB,WAAW,SAAQ;;EAGrB,SAAS,YAAY;GACnB,WAAW,YAAY,SAAS,QAAO;;EAGzC,YACQ,MAAM,YACN,MAAK,EACX,EAAE,WAAW,MACf,CAAA;EAEA,MAAM,QAAQ,QAAQ;GACpB,IAAI,KAAK,KAAK,SAAS,IAAG;IAC3B;EAED,sBAAsB;GACpB,UAAS;GACT,OAAO,QAAQ;GACf,YAAY;IACb;EAED,SAAa;GACX;GACA;GACA;GACD,CAAA;;uBA7IC,mBA+BM,OA/BN,WA+BM,EA/BA,OAAO,MAAA,IAAA,CAAI,EAAC,MAAA,EAAA,EAAiB,MAAA,MAAK,CAAA,EAAA,CAAA,CAC1B,MAAA,OAAA,IAAU,MAAA,UAAA,IAAA,WAAA,EAAtB,mBAA6E,OAAA;;IAA3C,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,UAAA,CAAA;MAAa,gBAAY,EAAA,IAClD,OAAA,SAAA,WAAA,EAArB,YA4BW,MAAA,SAAA,EAAA;;IA5BmB,QAAQ,MAAA,OAAA;IAAS,SAAS,QAAA;;sBAKpD,EALuE,uBAAgB,CAEjF,oBAAA,WAAA,EADR,YAIE,aAAA;;KAFC,eAAa;KACA;sEAGR,oBAAA,WAAA,EADR,YAqBkB,MAAA,gBAAA,EAAA;;KAnBf,eAAa;;uBAkBH,EAjBD,eAAQ,CAEF,YAAA,WAAA,EAAhB,YAeW,MAAA,SAAA,EAAA;;MAfgB,eAAa;MAAmB,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,eAAA,CAAA;;6BAcjD,CAbpB,YAaoB,aAAA,MAAA;8BADG,CAXrB,YAWqB,MAAA,mBAAA,EAAA;QAXA,eAAa;QAAmB,gBAAc;;+BAUtD,CATX,YASW,MAAA,SAAA,EAAA,EATA,eAAa,kBAAgB,EAAA;SAC3B,SAAO,SAMV,EANc,WAAI,CACxB,mBAKM,OAAA;UAJH,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,WAAA,CAAA;UACZ,OAAK,eAAA;WAAA,OAAW,KAAK,QAAK;WAAA,QAAiB,KAAK,SAAM;WAAA,CAAA;aAEvD,YAA4E,MAAA,YAAA,EAAA;UAA9D,eAAa;UAAmB,cAAY,KAAK"}
1
+ {"version":3,"file":"pdf-previewer.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/pdf-previewer.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('pdf')\" v-bind=\"attrs\">\n <div v-if=\"!engine || isLoading\" :class=\"cls.e('loading')\">正在加载 PDF 引擎…</div>\n <EmbedPDF v-else-if=\"pdfUrl\" :engine=\"engine\" :plugins=\"plugins\" v-slot=\"{ activeDocumentId }\">\n <PdfZoomBridge\n v-if=\"activeDocumentId\"\n :document-id=\"activeDocumentId\"\n @zoom-change=\"onZoomChange\"\n />\n <DocumentContent\n v-if=\"activeDocumentId\"\n :document-id=\"activeDocumentId\"\n v-slot=\"{ isLoaded }\"\n >\n <Viewport v-if=\"isLoaded\" :document-id=\"activeDocumentId\" :class=\"cls.e('pdf-viewport')\">\n <PdfViewportScroll>\n <ZoomGestureWrapper :document-id=\"activeDocumentId\" :enable-wheel=\"true\">\n <Scroller :document-id=\"activeDocumentId\">\n <template #default=\"{ page }\">\n <div\n :class=\"cls.e('pdf-page')\"\n :style=\"{ width: page.width + 'px', height: page.height + 'px' }\"\n >\n <RenderLayer :document-id=\"activeDocumentId\" :page-index=\"page.pageIndex\" />\n </div>\n </template>\n </Scroller>\n </ZoomGestureWrapper>\n </PdfViewportScroll>\n </Viewport>\n </DocumentContent>\n </EmbedPDF>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { createPluginRegistration } from '@embedpdf/core'\nimport { EmbedPDF } from '@embedpdf/core/vue'\nimport { usePdfiumEngine } from '@embedpdf/engines/vue'\nimport {\n DocumentContent,\n DocumentManagerPluginPackage\n} from '@embedpdf/plugin-document-manager/vue'\nimport { RenderLayer, RenderPluginPackage } from '@embedpdf/plugin-render/vue'\nimport { ScrollPluginPackage, Scroller } from '@embedpdf/plugin-scroll/vue'\nimport { ViewportPluginPackage, Viewport } from '@embedpdf/plugin-viewport/vue'\nimport {\n ZoomGestureWrapper,\n ZoomMode,\n ZoomPluginPackage,\n type ZoomScope\n} from '@embedpdf/plugin-zoom/vue'\nimport { bem } from '@veltra/utils'\nimport { computed, onBeforeUnmount, shallowRef, useAttrs, watch } from 'vue'\n\nimport type { FileViewerItem } from '../../../types/file-viewer'\nimport { toBlobUrl } from '../helper'\nimport PdfViewportScroll from './pdf-viewport-scroll.vue'\nimport PdfZoomBridge from './pdf-zoom-bridge.vue'\n\ndefineOptions({ name: 'FileViewerPdfPreviewer', inheritAttrs: false })\n\nconst props = defineProps<{ file: FileViewerItem }>()\n\nconst emit = defineEmits<{\n (e: 'error', err: unknown): void\n (e: 'zoom-change', level: number): void\n}>()\n\nconst cls = bem('file-viewer')\nconst attrs = useAttrs()\n\nconst { engine, isLoading, error } = usePdfiumEngine()\n\nconst pdfUrl = shallowRef<string>('')\nlet revoke: (() => void) | undefined\n\n/** 当前文档的 zoom API(由 PdfZoomBridge 注入) */\nlet zoomScope: ZoomScope | null = null\n\nfunction load() {\n revoke?.()\n const r = toBlobUrl(props.file.src, props.file.mime ?? 'application/pdf')\n pdfUrl.value = r.url\n revoke = r.revoke\n}\n\nconst plugins = computed(() => {\n if (!pdfUrl.value) return []\n return [\n createPluginRegistration(DocumentManagerPluginPackage, {\n initialDocuments: [{ url: pdfUrl.value }]\n }),\n createPluginRegistration(ViewportPluginPackage, { viewportGap: 0 }),\n createPluginRegistration(ScrollPluginPackage, { defaultBufferSize: 2 }),\n createPluginRegistration(RenderPluginPackage),\n createPluginRegistration(ZoomPluginPackage, {\n defaultZoomLevel: ZoomMode.FitPage,\n minZoom: 0.5,\n maxZoom: 3,\n zoomStep: 0.1\n })\n ]\n})\n\nfunction onZoomChange(payload: { level: number; scope: ZoomScope | null }) {\n zoomScope = payload.scope\n emit('zoom-change', payload.level)\n}\n\nfunction zoomIn() {\n zoomScope?.zoomIn()\n}\n\nfunction zoomOut() {\n zoomScope?.zoomOut()\n}\n\nfunction resetZoom() {\n zoomScope?.requestZoom(ZoomMode.FitPage)\n}\n\nwatch(\n () => props.file,\n () => load(),\n { immediate: true }\n)\n\nwatch(error, (err) => {\n if (err) emit('error', err)\n})\n\nonBeforeUnmount(() => {\n revoke?.()\n pdfUrl.value = ''\n zoomScope = null\n})\n\ndefineExpose({ zoomIn, zoomOut, resetZoom })\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EA8DA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAKb,MAAM,MAAM,IAAI,cAAa;EAC7B,MAAM,QAAQ,UAAS;EAEvB,MAAM,EAAE,QAAQ,WAAW,UAAU,iBAAgB;EAErD,MAAM,SAAS,WAAmB,GAAE;EACpC,IAAI;;EAGJ,IAAI,YAA8B;EAElC,SAAS,OAAO;GACd,UAAS;GACT,MAAM,IAAI,UAAU,MAAM,KAAK,KAAK,MAAM,KAAK,QAAQ,kBAAiB;GACxE,OAAO,QAAQ,EAAE;GACjB,SAAS,EAAE;;EAGb,MAAM,UAAU,eAAe;GAC7B,IAAI,CAAC,OAAO,OAAO,OAAO,EAAC;GAC3B,OAAO;IACL,yBAAyB,8BAA8B,EACrD,kBAAkB,CAAC,EAAE,KAAK,OAAO,OAAO,CAAA,EACzC,CAAA;IACD,yBAAyB,uBAAuB,EAAE,aAAa,GAAG,CAAA;IAClE,yBAAyB,qBAAqB,EAAE,mBAAmB,GAAG,CAAA;IACtE,yBAAyB,oBAAmB;IAC5C,yBAAyB,mBAAmB;KAC1C,kBAAkB,SAAS;KAC3B,SAAS;KACT,SAAS;KACT,UAAU;KACX,CAAA;IACH;IACD;EAED,SAAS,aAAa,SAAqD;GACzE,YAAY,QAAQ;GACpB,KAAK,eAAe,QAAQ,MAAK;;EAGnC,SAAS,SAAS;GAChB,WAAW,QAAO;;EAGpB,SAAS,UAAU;GACjB,WAAW,SAAQ;;EAGrB,SAAS,YAAY;GACnB,WAAW,YAAY,SAAS,QAAO;;EAGzC,YACQ,MAAM,YACN,MAAK,EACX,EAAE,WAAW,MACf,CAAA;EAEA,MAAM,QAAQ,QAAQ;GACpB,IAAI,KAAK,KAAK,SAAS,IAAG;IAC3B;EAED,sBAAsB;GACpB,UAAS;GACT,OAAO,QAAQ;GACf,YAAY;IACb;EAED,SAAa;GAAE;GAAQ;GAAS;GAAW,CAAA;;uBAzIzC,mBA+BM,OA/BN,WA+BM,EA/BA,OAAO,MAAA,IAAA,CAAI,EAAC,MAAA,EAAA,EAAiB,MAAA,MAAK,CAAA,EAAA,CAAA,CAC1B,MAAA,OAAA,IAAU,MAAA,UAAA,IAAA,WAAA,EAAtB,mBAA6E,OAAA;;IAA3C,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,UAAA,CAAA;MAAa,gBAAY,EAAA,IAClD,OAAA,SAAA,WAAA,EAArB,YA4BW,MAAA,SAAA,EAAA;;IA5BmB,QAAQ,MAAA,OAAA;IAAS,SAAS,QAAA;;sBAKpD,EALuE,uBAAgB,CAEjF,oBAAA,WAAA,EADR,YAIE,aAAA;;KAFC,eAAa;KACA;sEAGR,oBAAA,WAAA,EADR,YAqBkB,MAAA,gBAAA,EAAA;;KAnBf,eAAa;;uBAkBH,EAjBD,eAAQ,CAEF,YAAA,WAAA,EAAhB,YAeW,MAAA,SAAA,EAAA;;MAfgB,eAAa;MAAmB,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,eAAA,CAAA;;6BAcjD,CAbpB,YAaoB,aAAA,MAAA;8BADG,CAXrB,YAWqB,MAAA,mBAAA,EAAA;QAXA,eAAa;QAAmB,gBAAc;;+BAUtD,CATX,YASW,MAAA,SAAA,EAAA,EATA,eAAa,kBAAgB,EAAA;SAC3B,SAAO,SAMV,EANc,WAAI,CACxB,mBAKM,OAAA;UAJH,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC,WAAA,CAAA;UACZ,OAAK,eAAA;WAAA,OAAW,KAAK,QAAK;WAAA,QAAiB,KAAK,SAAM;WAAA,CAAA;aAEvD,YAA4E,MAAA,YAAA,EAAA;UAA9D,eAAa;UAAmB,cAAY,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"pdf-viewport-scroll.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/pdf-viewport-scroll.vue"],"sourcesContent":["<template>\n <slot />\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed, inject, onBeforeUnmount, type Ref, watch } from 'vue'\n\ndefineOptions({ name: 'FileViewerPdfViewportScroll' })\n\n/** EmbedPDF Viewport 向子树注入的滚动容器 ref */\nconst VIEWPORT_ELEMENT_KEY = 'viewport-element'\n\nconst viewportRef = inject<Ref<HTMLDivElement | null>>(VIEWPORT_ELEMENT_KEY)\nconst viewportEl = computed(() => viewportRef?.value ?? null)\n\nlet panState:\n | {\n pointerId: number\n startX: number\n startY: number\n scrollLeft: number\n scrollTop: number\n }\n | undefined\n\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false\n return !!target.closest(\n 'button, a, input, textarea, select, video, [contenteditable=\"true\"], .u-scroll__bar-x, .u-scroll__bar-y'\n )\n}\n\nfunction handlePointerDown(e: PointerEvent) {\n if (e.button !== 0 || isInteractiveTarget(e.target)) return\n\n const el = viewportEl.value\n if (!el) return\n\n panState = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n scrollLeft: el.scrollLeft,\n scrollTop: el.scrollTop\n }\n el.classList.add('is-panning')\n el.setPointerCapture(e.pointerId)\n e.preventDefault()\n}\n\nfunction handlePointerMove(e: PointerEvent) {\n if (!panState || panState.pointerId !== e.pointerId) return\n\n const el = viewportEl.value\n if (!el) return\n\n el.scrollLeft = panState.scrollLeft - (e.clientX - panState.startX)\n el.scrollTop = panState.scrollTop - (e.clientY - panState.startY)\n}\n\nfunction endPan(e: PointerEvent) {\n if (!panState || panState.pointerId !== e.pointerId) return\n\n const el = viewportEl.value\n if (el?.hasPointerCapture(e.pointerId)) {\n el.releasePointerCapture(e.pointerId)\n }\n el?.classList.remove('is-panning')\n panState = undefined\n}\n\nlet detachPan: (() => void) | undefined\n\nwatch(\n viewportEl,\n (el, _, onCleanup) => {\n detachPan?.()\n detachPan = undefined\n if (!el) return\n\n el.addEventListener('pointerdown', handlePointerDown, { capture: true })\n el.addEventListener('pointermove', handlePointerMove, { capture: true })\n el.addEventListener('pointerup', endPan, { capture: true })\n el.addEventListener('pointercancel', endPan, { capture: true })\n\n detachPan = () => {\n el.removeEventListener('pointerdown', handlePointerDown, { capture: true })\n el.removeEventListener('pointermove', handlePointerMove, { capture: true })\n el.removeEventListener('pointerup', endPan, { capture: true })\n el.removeEventListener('pointercancel', endPan, { capture: true })\n el.classList.remove('is-panning')\n panState = undefined\n }\n\n onCleanup(() => {\n detachPan?.()\n detachPan = undefined\n })\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n detachPan?.()\n detachPan = undefined\n})\n</script>\n"],"mappings":";;AAUA,MAAM,uBAAuB;;;;;;EAE7B,MAAM,cAAc,OAAmC,qBAAoB;EAC3E,MAAM,aAAa,eAAe,aAAa,SAAS,KAAI;EAE5D,IAAI;EAUJ,SAAS,oBAAoB,QAAqC;GAChE,IAAI,EAAE,kBAAkB,cAAc,OAAO;GAC7C,OAAO,CAAC,CAAC,OAAO,QACd,4GACF;;EAGF,SAAS,kBAAkB,GAAiB;GAC1C,IAAI,EAAE,WAAW,KAAK,oBAAoB,EAAE,OAAM,EAAG;GAErD,MAAM,KAAK,WAAW;GACtB,IAAI,CAAC,IAAI;GAET,WAAW;IACT,WAAW,EAAE;IACb,QAAQ,EAAE;IACV,QAAQ,EAAE;IACV,YAAY,GAAG;IACf,WAAW,GAAG;IAChB;GACA,GAAG,UAAU,IAAI,aAAY;GAC7B,GAAG,kBAAkB,EAAE,UAAS;GAChC,EAAE,gBAAe;;EAGnB,SAAS,kBAAkB,GAAiB;GAC1C,IAAI,CAAC,YAAY,SAAS,cAAc,EAAE,WAAW;GAErD,MAAM,KAAK,WAAW;GACtB,IAAI,CAAC,IAAI;GAET,GAAG,aAAa,SAAS,cAAc,EAAE,UAAU,SAAS;GAC5D,GAAG,YAAY,SAAS,aAAa,EAAE,UAAU,SAAS;;EAG5D,SAAS,OAAO,GAAiB;GAC/B,IAAI,CAAC,YAAY,SAAS,cAAc,EAAE,WAAW;GAErD,MAAM,KAAK,WAAW;GACtB,IAAI,IAAI,kBAAkB,EAAE,UAAS,EACnC,GAAG,sBAAsB,EAAE,UAAS;GAEtC,IAAI,UAAU,OAAO,aAAY;GACjC,WAAW,KAAA;;EAGb,IAAI;EAEJ,MACE,aACC,IAAI,GAAG,cAAc;GACpB,aAAY;GACZ,YAAY,KAAA;GACZ,IAAI,CAAC,IAAI;GAET,GAAG,iBAAiB,eAAe,mBAAmB,EAAE,SAAS,MAAM,CAAA;GACvE,GAAG,iBAAiB,eAAe,mBAAmB,EAAE,SAAS,MAAM,CAAA;GACvE,GAAG,iBAAiB,aAAa,QAAQ,EAAE,SAAS,MAAM,CAAA;GAC1D,GAAG,iBAAiB,iBAAiB,QAAQ,EAAE,SAAS,MAAM,CAAA;GAE9D,kBAAkB;IAChB,GAAG,oBAAoB,eAAe,mBAAmB,EAAE,SAAS,MAAM,CAAA;IAC1E,GAAG,oBAAoB,eAAe,mBAAmB,EAAE,SAAS,MAAM,CAAA;IAC1E,GAAG,oBAAoB,aAAa,QAAQ,EAAE,SAAS,MAAM,CAAA;IAC7D,GAAG,oBAAoB,iBAAiB,QAAQ,EAAE,SAAS,MAAM,CAAA;IACjE,GAAG,UAAU,OAAO,aAAY;IAChC,WAAW,KAAA;;GAGb,gBAAgB;IACd,aAAY;IACZ,YAAY,KAAA;KACb;KAEH,EAAE,WAAW,MACf,CAAA;EAEA,sBAAsB;GACpB,aAAY;GACZ,YAAY,KAAA;IACb;;UAxGC,WAAQ,KAAA,QAAA,UAAA"}
1
+ {"version":3,"file":"pdf-viewport-scroll.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/pdf-viewport-scroll.vue"],"sourcesContent":["<template>\n <slot />\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed, inject, onBeforeUnmount, type Ref, watch } from 'vue'\n\ndefineOptions({ name: 'FileViewerPdfViewportScroll' })\n\n/** EmbedPDF Viewport 向子树注入的滚动容器 ref */\nconst VIEWPORT_ELEMENT_KEY = 'viewport-element'\n\nconst viewportRef = inject<Ref<HTMLDivElement | null>>(VIEWPORT_ELEMENT_KEY)\nconst viewportEl = computed(() => viewportRef?.value ?? null)\n\nlet panState:\n | { pointerId: number; startX: number; startY: number; scrollLeft: number; scrollTop: number }\n | undefined\n\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false\n return !!target.closest(\n 'button, a, input, textarea, select, video, [contenteditable=\"true\"], .u-scroll__bar-x, .u-scroll__bar-y'\n )\n}\n\nfunction handlePointerDown(e: PointerEvent) {\n if (e.button !== 0 || isInteractiveTarget(e.target)) return\n\n const el = viewportEl.value\n if (!el) return\n\n panState = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n scrollLeft: el.scrollLeft,\n scrollTop: el.scrollTop\n }\n el.classList.add('is-panning')\n el.setPointerCapture(e.pointerId)\n e.preventDefault()\n}\n\nfunction handlePointerMove(e: PointerEvent) {\n if (!panState || panState.pointerId !== e.pointerId) return\n\n const el = viewportEl.value\n if (!el) return\n\n el.scrollLeft = panState.scrollLeft - (e.clientX - panState.startX)\n el.scrollTop = panState.scrollTop - (e.clientY - panState.startY)\n}\n\nfunction endPan(e: PointerEvent) {\n if (!panState || panState.pointerId !== e.pointerId) return\n\n const el = viewportEl.value\n if (el?.hasPointerCapture(e.pointerId)) {\n el.releasePointerCapture(e.pointerId)\n }\n el?.classList.remove('is-panning')\n panState = undefined\n}\n\nlet detachPan: (() => void) | undefined\n\nwatch(\n viewportEl,\n (el, _, onCleanup) => {\n detachPan?.()\n detachPan = undefined\n if (!el) return\n\n el.addEventListener('pointerdown', handlePointerDown, { capture: true })\n el.addEventListener('pointermove', handlePointerMove, { capture: true })\n el.addEventListener('pointerup', endPan, { capture: true })\n el.addEventListener('pointercancel', endPan, { capture: true })\n\n detachPan = () => {\n el.removeEventListener('pointerdown', handlePointerDown, { capture: true })\n el.removeEventListener('pointermove', handlePointerMove, { capture: true })\n el.removeEventListener('pointerup', endPan, { capture: true })\n el.removeEventListener('pointercancel', endPan, { capture: true })\n el.classList.remove('is-panning')\n panState = undefined\n }\n\n onCleanup(() => {\n detachPan?.()\n detachPan = undefined\n })\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n detachPan?.()\n detachPan = undefined\n})\n</script>\n"],"mappings":";;AAUA,MAAM,uBAAuB;;;;;;EAE7B,MAAM,cAAc,OAAmC,qBAAoB;EAC3E,MAAM,aAAa,eAAe,aAAa,SAAS,KAAI;EAE5D,IAAI;EAIJ,SAAS,oBAAoB,QAAqC;GAChE,IAAI,EAAE,kBAAkB,cAAc,OAAO;GAC7C,OAAO,CAAC,CAAC,OAAO,QACd,4GACF;;EAGF,SAAS,kBAAkB,GAAiB;GAC1C,IAAI,EAAE,WAAW,KAAK,oBAAoB,EAAE,OAAM,EAAG;GAErD,MAAM,KAAK,WAAW;GACtB,IAAI,CAAC,IAAI;GAET,WAAW;IACT,WAAW,EAAE;IACb,QAAQ,EAAE;IACV,QAAQ,EAAE;IACV,YAAY,GAAG;IACf,WAAW,GAAG;IAChB;GACA,GAAG,UAAU,IAAI,aAAY;GAC7B,GAAG,kBAAkB,EAAE,UAAS;GAChC,EAAE,gBAAe;;EAGnB,SAAS,kBAAkB,GAAiB;GAC1C,IAAI,CAAC,YAAY,SAAS,cAAc,EAAE,WAAW;GAErD,MAAM,KAAK,WAAW;GACtB,IAAI,CAAC,IAAI;GAET,GAAG,aAAa,SAAS,cAAc,EAAE,UAAU,SAAS;GAC5D,GAAG,YAAY,SAAS,aAAa,EAAE,UAAU,SAAS;;EAG5D,SAAS,OAAO,GAAiB;GAC/B,IAAI,CAAC,YAAY,SAAS,cAAc,EAAE,WAAW;GAErD,MAAM,KAAK,WAAW;GACtB,IAAI,IAAI,kBAAkB,EAAE,UAAS,EACnC,GAAG,sBAAsB,EAAE,UAAS;GAEtC,IAAI,UAAU,OAAO,aAAY;GACjC,WAAW,KAAA;;EAGb,IAAI;EAEJ,MACE,aACC,IAAI,GAAG,cAAc;GACpB,aAAY;GACZ,YAAY,KAAA;GACZ,IAAI,CAAC,IAAI;GAET,GAAG,iBAAiB,eAAe,mBAAmB,EAAE,SAAS,MAAM,CAAA;GACvE,GAAG,iBAAiB,eAAe,mBAAmB,EAAE,SAAS,MAAM,CAAA;GACvE,GAAG,iBAAiB,aAAa,QAAQ,EAAE,SAAS,MAAM,CAAA;GAC1D,GAAG,iBAAiB,iBAAiB,QAAQ,EAAE,SAAS,MAAM,CAAA;GAE9D,kBAAkB;IAChB,GAAG,oBAAoB,eAAe,mBAAmB,EAAE,SAAS,MAAM,CAAA;IAC1E,GAAG,oBAAoB,eAAe,mBAAmB,EAAE,SAAS,MAAM,CAAA;IAC1E,GAAG,oBAAoB,aAAa,QAAQ,EAAE,SAAS,MAAM,CAAA;IAC7D,GAAG,oBAAoB,iBAAiB,QAAQ,EAAE,SAAS,MAAM,CAAA;IACjE,GAAG,UAAU,OAAO,aAAY;IAChC,WAAW,KAAA;;GAGb,gBAAgB;IACd,aAAY;IACZ,YAAY,KAAA;KACb;KAEH,EAAE,WAAW,MACf,CAAA;EAEA,sBAAsB;GACpB,aAAY;GACZ,YAAY,KAAA;IACb;;UAlGC,WAAQ,KAAA,QAAA,UAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"pdf-zoom-bridge.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/pdf-zoom-bridge.vue"],"sourcesContent":["<template>\n <span hidden aria-hidden=\"true\" />\n</template>\n\n<script lang=\"ts\" setup>\nimport { useZoom, ZoomMode, type ZoomScope } from '@embedpdf/plugin-zoom/vue'\nimport { watch } from 'vue'\n\ndefineOptions({ name: 'FileViewerPdfZoomBridge' })\n\nconst props = defineProps<{ documentId: string }>()\n\nconst emit = defineEmits<{\n (e: 'zoom-change', payload: { level: number; scope: ZoomScope | null }): void\n}>()\n\nconst { provides: zoom, state } = useZoom(() => props.documentId)\n\nwatch(\n [zoom, () => state.value.currentZoomLevel],\n () => {\n emit('zoom-change', {\n level: state.value.currentZoomLevel,\n scope: zoom.value\n })\n },\n { immediate: true }\n)\n\ndefineExpose({\n resetZoom: () => zoom.value?.requestZoom(ZoomMode.FitPage)\n})\n</script>\n"],"mappings":";;;;;;;;;;;;;EAUA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAIb,MAAM,EAAE,UAAU,MAAM,UAAU,cAAc,MAAM,WAAU;EAEhE,MACE,CAAC,YAAY,MAAM,MAAM,iBAAgB,QACnC;GACJ,KAAK,eAAe;IAClB,OAAO,MAAM,MAAM;IACnB,OAAO,KAAK;IACb,CAAA;KAEH,EAAE,WAAW,MACf,CAAA;EAEA,SAAa,EACX,iBAAiB,KAAK,OAAO,YAAY,SAAS,QAAO,EAC1D,CAAA;;uBA9BC,mBAAkC,QAAlC,WAAkC"}
1
+ {"version":3,"file":"pdf-zoom-bridge.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/pdf-zoom-bridge.vue"],"sourcesContent":["<template>\n <span hidden aria-hidden=\"true\" />\n</template>\n\n<script lang=\"ts\" setup>\nimport { useZoom, ZoomMode, type ZoomScope } from '@embedpdf/plugin-zoom/vue'\nimport { watch } from 'vue'\n\ndefineOptions({ name: 'FileViewerPdfZoomBridge' })\n\nconst props = defineProps<{ documentId: string }>()\n\nconst emit = defineEmits<{\n (e: 'zoom-change', payload: { level: number; scope: ZoomScope | null }): void\n}>()\n\nconst { provides: zoom, state } = useZoom(() => props.documentId)\n\nwatch(\n [zoom, () => state.value.currentZoomLevel],\n () => {\n emit('zoom-change', { level: state.value.currentZoomLevel, scope: zoom.value })\n },\n { immediate: true }\n)\n\ndefineExpose({ resetZoom: () => zoom.value?.requestZoom(ZoomMode.FitPage) })\n</script>\n"],"mappings":";;;;;;;;;;;;;EAUA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAIb,MAAM,EAAE,UAAU,MAAM,UAAU,cAAc,MAAM,WAAU;EAEhE,MACE,CAAC,YAAY,MAAM,MAAM,iBAAgB,QACnC;GACJ,KAAK,eAAe;IAAE,OAAO,MAAM,MAAM;IAAkB,OAAO,KAAK;IAAO,CAAA;KAEhF,EAAE,WAAW,MACf,CAAA;EAEA,SAAa,EAAE,iBAAiB,KAAK,OAAO,YAAY,SAAS,QAAO,EAAG,CAAA;;uBAzBzE,mBAAkC,QAAlC,WAAkC"}
@@ -1 +1 @@
1
- {"version":3,"file":"sheet-previewer.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/sheet-previewer.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('sheet')\">\n <div v-if=\"truncated\" :class=\"cls.e('sheet-note')\">\n 仅展示前 {{ renderedRows.toLocaleString() }} 行(共 {{ totalRows.toLocaleString() }} 行)\n </div>\n <div v-if=\"sheets.length > 1\" :class=\"cls.e('sheet-tabs')\">\n <button\n v-for=\"(s, i) in sheets\"\n :key=\"s.name\"\n :class=\"[cls.e('sheet-tab'), bem.is('active', i === activeSheetIndex)]\"\n @click=\"activeSheetIndex = i\"\n >\n {{ s.name }}\n </button>\n </div>\n <div ref=\"container\" :class=\"cls.e('sheet-stage')\" />\n <div v-if=\"loading\" :class=\"cls.e('loading')\">加载中…</div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { onBeforeUnmount, ref, shallowRef, useTemplateRef, watch } from 'vue'\n\nimport type { FileViewerItem } from '../../../types/file-viewer'\n\ndefineOptions({ name: 'FileViewerSheetPreviewer' })\n\nconst props = withDefaults(\n defineProps<{\n file: FileViewerItem\n maxRows?: number\n }>(),\n { maxRows: 50_000 }\n)\n\nconst emit = defineEmits<{ (e: 'error', err: unknown): void }>()\n\nconst cls = bem('file-viewer')\n\nconst container = useTemplateRef<HTMLDivElement>('container')\nconst loading = ref(true)\nconst truncated = ref(false)\nconst totalRows = ref(0)\nconst renderedRows = ref(0)\n\ninterface SheetData {\n name: string\n headers: string[]\n rows: string[][]\n totalCount: number\n}\n\nconst sheets = shallowRef<SheetData[]>([])\nconst activeSheetIndex = ref(0)\n\nlet controller: AbortController | undefined\nlet instance: { release?: () => void; resize?: () => void } | undefined\nlet resizeObserver: ResizeObserver | undefined\n\nasync function load() {\n controller?.abort()\n controller = new AbortController()\n const signal = controller.signal\n loading.value = true\n sheets.value = []\n activeSheetIndex.value = 0\n\n try {\n const ext = props.file.name.slice(props.file.name.lastIndexOf('.') + 1).toLowerCase()\n const { toArrayBuffer, parseCsv } = await import('../helper')\n const buf = await toArrayBuffer(props.file.src, signal)\n if (signal.aborted) return\n\n if (ext === 'csv') {\n const text = new TextDecoder('utf-8', { fatal: false }).decode(buf)\n const parsed = parseCsv(text).filter((row) => row.some((c) => c.length > 0))\n const headers = parsed[0] ?? []\n const rows = parsed.slice(1)\n sheets.value = [\n {\n name: props.file.name,\n headers: headers.map((h, i) => String(h) || `Column ${i + 1}`),\n rows,\n totalCount: rows.length\n }\n ]\n } else {\n const { readWorkbook } = await import('@cat-kit/excel')\n const workbook = await readWorkbook(new Uint8Array(buf))\n if (signal.aborted) return\n sheets.value = workbook.worksheets.map((ws) => {\n const wsRows = ws.getRows()\n const firstRow = wsRows[0]\n const headers = firstRow ? firstRow.toValues().map((v) => cellToString(v)) : []\n const rows = wsRows.slice(1).map((r) => r.toValues().map(cellToString))\n return {\n name: ws.name,\n headers: headers.map((h, i) => h || `Column ${i + 1}`),\n rows,\n totalCount: rows.length\n }\n })\n }\n\n await renderActive()\n } catch (err) {\n if ((err as { name?: string })?.name === 'AbortError') return\n emit('error', err)\n } finally {\n loading.value = false\n }\n}\n\nfunction cellToString(v: unknown): string {\n if (v === null || v === undefined) return ''\n if (typeof v === 'string') return v\n if (typeof v === 'number' || typeof v === 'boolean') return String(v)\n if (v instanceof Date) return v.toLocaleString()\n if (typeof v === 'object' && v !== null && 'formula' in v) {\n const f = v as { formula: string; result?: unknown }\n if (f.result !== undefined && f.result !== null) return cellToString(f.result)\n return `=${f.formula}`\n }\n return String(v)\n}\n\nasync function renderActive() {\n const sheet = sheets.value[activeSheetIndex.value]\n if (!sheet || !container.value) return\n\n releaseInstance()\n\n const limit = props.maxRows > 0 ? Math.min(props.maxRows, sheet.rows.length) : sheet.rows.length\n totalRows.value = sheet.totalCount\n renderedRows.value = limit\n truncated.value = props.maxRows > 0 && sheet.rows.length > props.maxRows\n\n const columns = sheet.headers.map((h, i) => ({\n field: 'c' + i,\n title: h,\n width: 'auto' as const\n }))\n\n const records: Record<string, string>[] = []\n for (let i = 0; i < limit; i++) {\n const row = sheet.rows[i]\n if (!row) continue\n const record: Record<string, string> = {}\n for (let j = 0; j < columns.length; j++) {\n record['c' + j] = row[j] ?? ''\n }\n records.push(record)\n }\n\n const VTable = await import('@visactor/vtable')\n if (!container.value) return\n\n instance = new VTable.ListTable(container.value, {\n records,\n columns,\n widthMode: 'standard',\n heightMode: 'standard',\n defaultRowHeight: 32,\n defaultHeaderRowHeight: 36,\n autoFillWidth: true,\n frozenColCount: 0,\n theme: (VTable.themes.ARCO ?? VTable.themes.DEFAULT).extends({\n defaultStyle: {\n borderLineWidth: 1\n }\n })\n })\n}\n\nfunction releaseInstance() {\n if (instance && typeof instance.release === 'function') {\n try {\n instance.release()\n } catch {\n /* noop */\n }\n }\n instance = undefined\n}\n\nwatch(\n () => props.file,\n () => load(),\n { immediate: true }\n)\n\nwatch(activeSheetIndex, () => renderActive())\n\nwatch(container, (el) => {\n resizeObserver?.disconnect()\n if (!el) return\n resizeObserver = new ResizeObserver(() => {\n instance?.resize?.()\n })\n resizeObserver.observe(el)\n})\n\nonBeforeUnmount(() => {\n controller?.abort()\n resizeObserver?.disconnect()\n releaseInstance()\n sheets.value = []\n})\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"sheet-previewer.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/sheet-previewer.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('sheet')\">\n <div v-if=\"truncated\" :class=\"cls.e('sheet-note')\">\n 仅展示前 {{ renderedRows.toLocaleString() }} 行(共 {{ totalRows.toLocaleString() }} 行)\n </div>\n <div v-if=\"sheets.length > 1\" :class=\"cls.e('sheet-tabs')\">\n <button\n v-for=\"(s, i) in sheets\"\n :key=\"s.name\"\n :class=\"[cls.e('sheet-tab'), bem.is('active', i === activeSheetIndex)]\"\n @click=\"activeSheetIndex = i\"\n >\n {{ s.name }}\n </button>\n </div>\n <div ref=\"container\" :class=\"cls.e('sheet-stage')\" />\n <div v-if=\"loading\" :class=\"cls.e('loading')\">加载中…</div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { onBeforeUnmount, ref, shallowRef, useTemplateRef, watch } from 'vue'\n\nimport type { FileViewerItem } from '../../../types/file-viewer'\n\ndefineOptions({ name: 'FileViewerSheetPreviewer' })\n\nconst props = withDefaults(defineProps<{ file: FileViewerItem; maxRows?: number }>(), {\n maxRows: 50_000\n})\n\nconst emit = defineEmits<{ (e: 'error', err: unknown): void }>()\n\nconst cls = bem('file-viewer')\n\nconst container = useTemplateRef<HTMLDivElement>('container')\nconst loading = ref(true)\nconst truncated = ref(false)\nconst totalRows = ref(0)\nconst renderedRows = ref(0)\n\ninterface SheetData {\n name: string\n headers: string[]\n rows: string[][]\n totalCount: number\n}\n\nconst sheets = shallowRef<SheetData[]>([])\nconst activeSheetIndex = ref(0)\n\nlet controller: AbortController | undefined\nlet instance: { release?: () => void; resize?: () => void } | undefined\nlet resizeObserver: ResizeObserver | undefined\n\nasync function load() {\n controller?.abort()\n controller = new AbortController()\n const signal = controller.signal\n loading.value = true\n sheets.value = []\n activeSheetIndex.value = 0\n\n try {\n const ext = props.file.name.slice(props.file.name.lastIndexOf('.') + 1).toLowerCase()\n const { toArrayBuffer, parseCsv } = await import('../helper')\n const buf = await toArrayBuffer(props.file.src, signal)\n if (signal.aborted) return\n\n if (ext === 'csv') {\n const text = new TextDecoder('utf-8', { fatal: false }).decode(buf)\n const parsed = parseCsv(text).filter((row) => row.some((c) => c.length > 0))\n const headers = parsed[0] ?? []\n const rows = parsed.slice(1)\n sheets.value = [\n {\n name: props.file.name,\n headers: headers.map((h, i) => String(h) || `Column ${i + 1}`),\n rows,\n totalCount: rows.length\n }\n ]\n } else {\n const { readWorkbook } = await import('@cat-kit/excel')\n const workbook = await readWorkbook(new Uint8Array(buf))\n if (signal.aborted) return\n sheets.value = workbook.worksheets.map((ws) => {\n const wsRows = ws.getRows()\n const firstRow = wsRows[0]\n const headers = firstRow ? firstRow.toValues().map((v) => cellToString(v)) : []\n const rows = wsRows.slice(1).map((r) => r.toValues().map(cellToString))\n return {\n name: ws.name,\n headers: headers.map((h, i) => h || `Column ${i + 1}`),\n rows,\n totalCount: rows.length\n }\n })\n }\n\n await renderActive()\n } catch (err) {\n if ((err as { name?: string })?.name === 'AbortError') return\n emit('error', err)\n } finally {\n loading.value = false\n }\n}\n\nfunction cellToString(v: unknown): string {\n if (v === null || v === undefined) return ''\n if (typeof v === 'string') return v\n if (typeof v === 'number' || typeof v === 'boolean') return String(v)\n if (v instanceof Date) return v.toLocaleString()\n if (typeof v === 'object' && v !== null && 'formula' in v) {\n const f = v as { formula: string; result?: unknown }\n if (f.result !== undefined && f.result !== null) return cellToString(f.result)\n return `=${f.formula}`\n }\n return String(v)\n}\n\nasync function renderActive() {\n const sheet = sheets.value[activeSheetIndex.value]\n if (!sheet || !container.value) return\n\n releaseInstance()\n\n const limit = props.maxRows > 0 ? Math.min(props.maxRows, sheet.rows.length) : sheet.rows.length\n totalRows.value = sheet.totalCount\n renderedRows.value = limit\n truncated.value = props.maxRows > 0 && sheet.rows.length > props.maxRows\n\n const columns = sheet.headers.map((h, i) => ({\n field: 'c' + i,\n title: h,\n width: 'auto' as const\n }))\n\n const records: Record<string, string>[] = []\n for (let i = 0; i < limit; i++) {\n const row = sheet.rows[i]\n if (!row) continue\n const record: Record<string, string> = {}\n for (let j = 0; j < columns.length; j++) {\n record['c' + j] = row[j] ?? ''\n }\n records.push(record)\n }\n\n const VTable = await import('@visactor/vtable')\n if (!container.value) return\n\n instance = new VTable.ListTable(container.value, {\n records,\n columns,\n widthMode: 'standard',\n heightMode: 'standard',\n defaultRowHeight: 32,\n defaultHeaderRowHeight: 36,\n autoFillWidth: true,\n frozenColCount: 0,\n theme: (VTable.themes.ARCO ?? VTable.themes.DEFAULT).extends({\n defaultStyle: { borderLineWidth: 1 }\n })\n })\n}\n\nfunction releaseInstance() {\n if (instance && typeof instance.release === 'function') {\n try {\n instance.release()\n } catch {\n /* noop */\n }\n }\n instance = undefined\n}\n\nwatch(\n () => props.file,\n () => load(),\n { immediate: true }\n)\n\nwatch(activeSheetIndex, () => renderActive())\n\nwatch(container, (el) => {\n resizeObserver?.disconnect()\n if (!el) return\n resizeObserver = new ResizeObserver(() => {\n instance?.resize?.()\n })\n resizeObserver.observe(el)\n})\n\nonBeforeUnmount(() => {\n controller?.abort()\n resizeObserver?.disconnect()\n releaseInstance()\n sheets.value = []\n})\n</script>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"float-button.js","names":[],"sources":["../../../src/components/float-button/float-button.vue"],"sourcesContent":["<template>\n <Teleport to=\"body\">\n <div\n :class=\"cls.b\"\n @mouseenter=\"handleMouseEnter\"\n @mouseleave=\"handleMouseLeave\"\n ref=\"floatButtonRef\"\n >\n <u-button\n v-for=\"(item, index) of items\"\n :key=\"item.key\"\n :class=\"[cls.e('item'), bem.is('first', index === 0)]\"\n circle\n :size=\"size\"\n :type=\"item.type ?? 'primary'\"\n ref=\"itemsRef\"\n :style=\"{ transitionDelay: index * 0.1 + 's' }\"\n @transitionend=\"handleTransitionEnd(index, $event)\"\n @click=\"emit('click', item.key)\"\n :title=\"item.name ?? item.key\"\n >\n <u-icon v-if=\"item.icon\"> <component :is=\"item.icon\" /> </u-icon>\n <span v-else>{{ item.name?.[0] ?? item.key[0] }}</span>\n </u-button>\n </div>\n </Teleport>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem, removeStyles, setStyles } from '@veltra/utils'\nimport { shallowRef } from 'vue'\n\nimport type { FloatButtonProps, FloatButtonEmits, ButtonExposed } from '../../types'\nimport { UButton } from '../button'\nimport { UIcon } from '../icon'\n\ndefineOptions({\n name: 'FloatButton'\n})\n\ndefineProps<FloatButtonProps>()\n\nconst emit = defineEmits<FloatButtonEmits>()\n\nconst cls = bem('float-button')\nconst hoveredCls = bem.is('hovered')\n\nconst floatButtonRef = shallowRef<HTMLElement>()\nconst itemsRef = shallowRef<ButtonExposed[]>()\n\nconst hovered = shallowRef(false)\n\nconst handleMouseEnter = () => {\n hovered.value = true\n\n itemsRef.value?.forEach((item) => {\n setStyles(item.el!, { display: 'flex' })\n })\n\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n itemsRef.value?.forEach((item) => {\n item.el!.classList.add(hoveredCls)\n })\n })\n })\n}\nconst handleMouseLeave = () => {\n hovered.value = false\n itemsRef.value?.forEach((item) => {\n item.el!.classList.remove(hoveredCls)\n })\n}\n\n/**\n * 动画结束回调\n * @param index 发生的元素索引\n * @param e 事件\n */\nconst handleTransitionEnd = (index: number, e: TransitionEvent) => {\n if (index !== 1 || hovered.value) return\n\n itemsRef.value?.forEach((item) => {\n removeStyles(item.el!, ['display'])\n })\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;EA0CA,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,eAAc;EAC9B,MAAM,aAAa,IAAI,GAAG,UAAS;EAEnC,MAAM,iBAAiB,YAAwB;EAC/C,MAAM,WAAW,YAA4B;EAE7C,MAAM,UAAU,WAAW,MAAK;EAEhC,MAAM,yBAAyB;GAC7B,QAAQ,QAAQ;GAEhB,SAAS,OAAO,SAAS,SAAS;IAChC,UAAU,KAAK,IAAK,EAAE,SAAS,QAAQ,CAAA;KACxC;GAED,4BAA4B;IAC1B,4BAA4B;KAC1B,SAAS,OAAO,SAAS,SAAS;MAChC,KAAK,GAAI,UAAU,IAAI,WAAU;OAClC;MACF;KACF;;EAEH,MAAM,yBAAyB;GAC7B,QAAQ,QAAQ;GAChB,SAAS,OAAO,SAAS,SAAS;IAChC,KAAK,GAAI,UAAU,OAAO,WAAU;KACrC;;;;;;;EAQH,MAAM,uBAAuB,OAAe,MAAuB;GACjE,IAAI,UAAU,KAAK,QAAQ,OAAO;GAElC,SAAS,OAAO,SAAS,SAAS;IAChC,aAAa,KAAK,IAAK,CAAC,UAAU,CAAA;KACnC;;;uBAnFD,YAwBW,UAAA,EAxBD,IAAG,QAAM,EAAA,CACjB,mBAsBM,OAAA;IArBH,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC;IACZ,cAAY;IACZ,cAAY;aACT;IAAJ,KAAI;yBAEJ,mBAeW,UAAA,MAAA,WAde,QAAA,QAAhB,MAAM,UAAK;wBADrB,YAeW,MAAA,YAAA,EAAA;KAbR,KAAK,KAAK;KACV,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,OAAA,EAAU,MAAA,IAAA,CAAI,GAAE,SAAU,UAAK,EAAA,CAAA,CAAA;KAC7C,QAAA;KACC,MAAM,QAAA;KACN,MAAM,KAAK,QAAI;;cACZ;KAAJ,KAAI;KACH,OAAK,eAAA,EAAA,iBAAqB,QAAK,KAAA,KAAA,CAAA;KAC/B,kBAAa,WAAE,oBAAoB,OAAO,OAAM;KAChD,UAAK,WAAE,KAAI,SAAU,KAAK,IAAG;KAC7B,OAAO,KAAK,QAAQ,KAAK;;4BAEuC,CAAnD,KAAK,QAAA,WAAA,EAAnB,YAAiE,MAAA,YAAA,EAAA,EAAA,KAAA,GAAA,EAAA;6BAAV,EAAA,WAAA,EAA7B,YAA6B,wBAAb,KAAK,KAAI,CAAA,EAAA,CAAA;;+BACnD,mBAAuD,QAAA,YAAA,gBAAvC,KAAK,OAAI,MAAS,KAAK,IAAG,GAAA,EAAA,EAAA,EAAA,CAAA"}
1
+ {"version":3,"file":"float-button.js","names":[],"sources":["../../../src/components/float-button/float-button.vue"],"sourcesContent":["<template>\n <Teleport to=\"body\">\n <div\n :class=\"cls.b\"\n @mouseenter=\"handleMouseEnter\"\n @mouseleave=\"handleMouseLeave\"\n ref=\"floatButtonRef\"\n >\n <u-button\n v-for=\"(item, index) of items\"\n :key=\"item.key\"\n :class=\"[cls.e('item'), bem.is('first', index === 0)]\"\n circle\n :size=\"size\"\n :type=\"item.type ?? 'primary'\"\n ref=\"itemsRef\"\n :style=\"{ transitionDelay: index * 0.1 + 's' }\"\n @transitionend=\"handleTransitionEnd(index, $event)\"\n @click=\"emit('click', item.key)\"\n :title=\"item.name ?? item.key\"\n >\n <u-icon v-if=\"item.icon\"> <component :is=\"item.icon\" /> </u-icon>\n <span v-else>{{ item.name?.[0] ?? item.key[0] }}</span>\n </u-button>\n </div>\n </Teleport>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem, removeStyles, setStyles } from '@veltra/utils'\nimport { shallowRef } from 'vue'\n\nimport type { FloatButtonProps, FloatButtonEmits, ButtonExposed } from '../../types'\nimport { UButton } from '../button'\nimport { UIcon } from '../icon'\n\ndefineOptions({ name: 'FloatButton' })\n\ndefineProps<FloatButtonProps>()\n\nconst emit = defineEmits<FloatButtonEmits>()\n\nconst cls = bem('float-button')\nconst hoveredCls = bem.is('hovered')\n\nconst floatButtonRef = shallowRef<HTMLElement>()\nconst itemsRef = shallowRef<ButtonExposed[]>()\n\nconst hovered = shallowRef(false)\n\nconst handleMouseEnter = () => {\n hovered.value = true\n\n itemsRef.value?.forEach((item) => {\n setStyles(item.el!, { display: 'flex' })\n })\n\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n itemsRef.value?.forEach((item) => {\n item.el!.classList.add(hoveredCls)\n })\n })\n })\n}\nconst handleMouseLeave = () => {\n hovered.value = false\n itemsRef.value?.forEach((item) => {\n item.el!.classList.remove(hoveredCls)\n })\n}\n\n/**\n * 动画结束回调\n * @param index 发生的元素索引\n * @param e 事件\n */\nconst handleTransitionEnd = (index: number, e: TransitionEvent) => {\n if (index !== 1 || hovered.value) return\n\n itemsRef.value?.forEach((item) => {\n removeStyles(item.el!, ['display'])\n })\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;EAwCA,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,eAAc;EAC9B,MAAM,aAAa,IAAI,GAAG,UAAS;EAEnC,MAAM,iBAAiB,YAAwB;EAC/C,MAAM,WAAW,YAA4B;EAE7C,MAAM,UAAU,WAAW,MAAK;EAEhC,MAAM,yBAAyB;GAC7B,QAAQ,QAAQ;GAEhB,SAAS,OAAO,SAAS,SAAS;IAChC,UAAU,KAAK,IAAK,EAAE,SAAS,QAAQ,CAAA;KACxC;GAED,4BAA4B;IAC1B,4BAA4B;KAC1B,SAAS,OAAO,SAAS,SAAS;MAChC,KAAK,GAAI,UAAU,IAAI,WAAU;OAClC;MACF;KACF;;EAEH,MAAM,yBAAyB;GAC7B,QAAQ,QAAQ;GAChB,SAAS,OAAO,SAAS,SAAS;IAChC,KAAK,GAAI,UAAU,OAAO,WAAU;KACrC;;;;;;;EAQH,MAAM,uBAAuB,OAAe,MAAuB;GACjE,IAAI,UAAU,KAAK,QAAQ,OAAO;GAElC,SAAS,OAAO,SAAS,SAAS;IAChC,aAAa,KAAK,IAAK,CAAC,UAAU,CAAA;KACnC;;;uBAjFD,YAwBW,UAAA,EAxBD,IAAG,QAAM,EAAA,CACjB,mBAsBM,OAAA;IArBH,OAAK,eAAE,MAAA,IAAA,CAAI,EAAC;IACZ,cAAY;IACZ,cAAY;aACT;IAAJ,KAAI;yBAEJ,mBAeW,UAAA,MAAA,WAde,QAAA,QAAhB,MAAM,UAAK;wBADrB,YAeW,MAAA,YAAA,EAAA;KAbR,KAAK,KAAK;KACV,OAAK,eAAA,CAAG,MAAA,IAAA,CAAI,EAAC,OAAA,EAAU,MAAA,IAAA,CAAI,GAAE,SAAU,UAAK,EAAA,CAAA,CAAA;KAC7C,QAAA;KACC,MAAM,QAAA;KACN,MAAM,KAAK,QAAI;;cACZ;KAAJ,KAAI;KACH,OAAK,eAAA,EAAA,iBAAqB,QAAK,KAAA,KAAA,CAAA;KAC/B,kBAAa,WAAE,oBAAoB,OAAO,OAAM;KAChD,UAAK,WAAE,KAAI,SAAU,KAAK,IAAG;KAC7B,OAAO,KAAK,QAAQ,KAAK;;4BAEuC,CAAnD,KAAK,QAAA,WAAA,EAAnB,YAAiE,MAAA,YAAA,EAAA,EAAA,KAAA,GAAA,EAAA;6BAAV,EAAA,WAAA,EAA7B,YAA6B,wBAAb,KAAK,KAAI,CAAA,EAAA,CAAA;;+BACnD,mBAAuD,QAAA,YAAA,gBAAvC,KAAK,OAAI,MAAS,KAAK,IAAG,GAAA,EAAA,EAAA,EAAA,CAAA"}
@@ -1,11 +1,11 @@
1
- import { AllKeys, DataSettingConfig, IFormModel, ModelData } from "../../types/form.js";
1
+ import { AllKeys, DataSettingConfig, FormModelField, IFormModel, ModelData } from "../../types/form.js";
2
2
  import { Reactive } from "vue";
3
3
 
4
4
  //#region src/components/form/form-model.d.ts
5
5
  /**
6
6
  * 表单模型
7
7
  */
8
- declare class FormModel<Fields extends Record<string, any> = Record<string, any>> implements IFormModel<Fields> {
8
+ declare class FormModel<Fields extends Record<string, FormModelField> = Record<string, FormModelField>> implements IFormModel<Fields> {
9
9
  /** 表单数据 */
10
10
  data: ModelData<Fields>;
11
11
  /** 表单规则 */
@@ -1 +1 @@
1
- {"version":3,"file":"form-model.js","names":[],"sources":["../../../src/components/form/form-model.ts"],"sourcesContent":["import { o } from '@cat-kit/core'\nimport { middleProxy, Validator } from '@veltra/utils'\nimport { nextTick, reactive, shallowReactive, watch, type Reactive } from 'vue'\n\nimport type { ModelData, DataSettingConfig, IFormModel, AllKeys, FormModelItem } from '../../types'\n\n/**\n * 递归展平字段逻辑\n */\nfunction flattenFields(fields: Record<string, any>, prefix = ''): Record<string, FormModelItem> {\n const result: Record<string, FormModelItem> = {}\n for (const key in fields) {\n const item = fields[key]\n const fullPath = prefix ? `${prefix}.${key}` : key\n if (item && typeof item === 'object' && '__isNested' in item && item.__isNested) {\n Object.assign(result, flattenFields((item as any).fields, fullPath))\n } else {\n result[fullPath] = item\n }\n }\n return result\n}\n\n/**\n * 表单模型\n */\nexport class FormModel<\n Fields extends Record<string, any> = Record<string, any>\n> implements IFormModel<Fields> {\n /** 表单数据 */\n data!: ModelData<Fields>\n\n /** 表单规则 */\n readonly fields: Fields\n\n /** 所有的键 */\n readonly allKeys: string[]\n\n /**\n * 不同表单所需要校验的字段\n * @description\n * 这个值会在表单组件渲染时由表单设置,因为只有真正渲染的组件才应该被校验\n */\n formKeys: Map<number, AllKeys<Fields>[]> = new Map()\n\n /** 初始数据 */\n readonly initialData: ModelData<Fields>\n\n readonly errors: Map<AllKeys<Fields>, string[] | undefined> = shallowReactive(new Map())\n\n private validator: Validator<Record<string, FormModelItem>>\n\n /**\n * 是否在表单值更新时校验\n */\n private validateOnFieldChange = true\n\n private modelChangeCallback: Set<(fields: string, val: any) => void> = new Set()\n\n constructor(fields: Fields) {\n this.fields = fields\n const flatFields = flattenFields(fields)\n const rawData = {} as ModelData<Fields>\n const allKeys: string[] = []\n\n for (const key in flatFields) {\n const fieldItem = flatFields[key]!\n allKeys.push(key)\n const { value } = fieldItem\n let v = value\n\n if (typeof value === 'function') {\n watch(value, (v) => {\n o(this.initialData).set(key, v)\n })\n v = value()\n }\n\n o(rawData).set(key, v)\n }\n\n this.allKeys = allKeys\n this.initialData = JSON.parse(JSON.stringify(rawData))\n\n this.setProxyData(reactive(rawData))\n\n this.validator = new Validator(flatFields)\n\n return shallowReactive(this)\n }\n\n /**\n * 设置响应式值, 替换掉原有的数据\n * @description 设置响应式值时,会自动监听值的变化,并进行校验\n * @param proxyData 响应式的值\n */\n setProxyData(proxyData: ModelData<Fields> | Reactive<ModelData<Fields>>): void {\n const data = middleProxy(proxyData, {\n set: (field, val) => {\n this.modelChangeCallback.forEach((cb) => cb(field, val))\n },\n\n changed: (fields) => {\n if (!this.validateOnFieldChange) {\n this.validateOnFieldChange = true\n return\n }\n this.validate(fields as any)\n }\n })\n\n this.data = data as ModelData<Fields>\n }\n\n private getValidateFields(fields?: AllKeys<Fields> | AllKeys<Fields>[]) {\n if (!fields) {\n if (this.formKeys.size) {\n let _fields: AllKeys<Fields>[] = []\n this.formKeys.forEach((fields) => {\n _fields = _fields.concat(fields)\n })\n return _fields\n } else {\n return this.allKeys as AllKeys<Fields>[]\n }\n }\n\n if (!Array.isArray(fields)) {\n return [fields]\n }\n return fields\n }\n\n /**\n * 模型校验\n * @param fields 需要校验的字段, 不传则校验所有字段\n * @returns\n */\n async validate(fields?: AllKeys<Fields> | AllKeys<Fields>[]): Promise<boolean> {\n const { errors, validator, data } = this\n\n const results = await validator.validate(data, this.getValidateFields(fields) as any)\n\n // 全量校验\n if (!fields) {\n errors.clear()\n\n for (const field in results) {\n errors.set(field as any, results[field])\n }\n }\n // 局部校验\n else {\n ~(Array.isArray(fields) ? fields : [fields]).forEach((field) => {\n const errs = results[field as string]\n if (errs?.length) {\n errors.set(field, errs)\n } else {\n errors.delete(field)\n }\n })\n }\n\n if (errors.size > 0) {\n if (!fields) {\n nextTick(() => {\n document.querySelector('.u-form-item.is-error')?.scrollIntoView({ block: 'nearest' })\n })\n }\n return Promise.reject(false)\n }\n\n return true\n }\n\n /**\n * 重置数据\n * @param fields 需要重置的字段\n */\n resetData(keys?: AllKeys<Fields> | AllKeys<Fields>[]): void {\n if (typeof keys === 'string') {\n keys = [keys]\n } else if (Array.isArray(keys)) {\n } else {\n keys = this.allKeys as AllKeys<Fields>[]\n }\n\n this.clearValidate()\n\n this.validateOnFieldChange = false\n\n keys.forEach((field) => {\n o(this.data).set(field as string, o(this.initialData).get(field as string))\n })\n }\n\n /**\n * 设置值\n * @param formData 表单值\n * @param options 配置\n */\n setData(\n formData: Partial<ModelData<Fields> & Record<string, any>>,\n config?: DataSettingConfig\n ): FormModel<Fields> {\n const { validate = true } = config || {}\n\n if (!validate) {\n this.validateOnFieldChange = false\n }\n\n this.allKeys.forEach((key) => {\n const value = o(formData).get(key)\n if (value !== undefined) {\n o(this.data).set(key, value)\n }\n })\n\n return this\n }\n\n /**\n * 设置初始值\n * @description 初始值在重置数据和查看原始数据时会用到\n * @param data 初始值\n */\n setInitialData(data: Partial<ModelData<Fields>>): FormModel<Fields> {\n this.allKeys.forEach((key) => {\n o(this.initialData).set(key, o(data).get(key))\n })\n\n return this\n }\n\n /** 清除校验 */\n clearValidate(): void {\n this.errors.clear()\n }\n\n /**\n * 监听值变更\n * @param cb 回调\n */\n onChange(cb: (field: AllKeys<Fields>, val: any) => void): void {\n this.modelChangeCallback.add(cb as any)\n }\n\n /** 关闭监听值变更 */\n offChange(cb: (field: AllKeys<Fields>, val: any) => void): void {\n this.modelChangeCallback.delete(cb as any)\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"form-model.js","names":[],"sources":["../../../src/components/form/form-model.ts"],"sourcesContent":["import { o } from '@cat-kit/core'\nimport { middleProxy, Validator } from '@veltra/utils'\nimport { nextTick, reactive, shallowReactive, watch, type Reactive } from 'vue'\n\nimport type {\n ModelData,\n DataSettingConfig,\n IFormModel,\n AllKeys,\n FormModelItem,\n FormModelField\n} from '../../types'\n\n/**\n * 递归展平字段逻辑\n */\nfunction flattenFields(fields: Record<string, any>, prefix = ''): Record<string, FormModelItem> {\n const result: Record<string, FormModelItem> = {}\n for (const key in fields) {\n const item = fields[key]\n const fullPath = prefix ? `${prefix}.${key}` : key\n if (item && typeof item === 'object' && '__isNested' in item && item.__isNested) {\n Object.assign(result, flattenFields((item as any).fields, fullPath))\n } else {\n result[fullPath] = item\n }\n }\n return result\n}\n\n/**\n * 表单模型\n */\nexport class FormModel<\n Fields extends Record<string, FormModelField> = Record<string, FormModelField>\n> implements IFormModel<Fields> {\n /** 表单数据 */\n data!: ModelData<Fields>\n\n /** 表单规则 */\n readonly fields: Fields\n\n /** 所有的键 */\n readonly allKeys: string[]\n\n /**\n * 不同表单所需要校验的字段\n * @description\n * 这个值会在表单组件渲染时由表单设置,因为只有真正渲染的组件才应该被校验\n */\n formKeys: Map<number, AllKeys<Fields>[]> = new Map()\n\n /** 初始数据 */\n readonly initialData: ModelData<Fields>\n\n readonly errors: Map<AllKeys<Fields>, string[] | undefined> = shallowReactive(new Map())\n\n private validator: Validator<Record<string, FormModelItem>>\n\n /**\n * 是否在表单值更新时校验\n */\n private validateOnFieldChange = true\n\n private modelChangeCallback: Set<(fields: string, val: any) => void> = new Set()\n\n constructor(fields: Fields) {\n this.fields = fields\n const flatFields = flattenFields(fields)\n const rawData = {} as ModelData<Fields>\n const allKeys: string[] = []\n\n for (const key in flatFields) {\n const fieldItem = flatFields[key]!\n allKeys.push(key)\n const { value } = fieldItem\n let v = value\n\n if (typeof value === 'function') {\n watch(value, (v) => {\n o(this.initialData).set(key, v)\n })\n v = value()\n }\n\n o(rawData).set(key, v)\n }\n\n this.allKeys = allKeys\n this.initialData = JSON.parse(JSON.stringify(rawData))\n\n this.setProxyData(reactive(rawData))\n\n this.validator = new Validator(flatFields)\n\n return shallowReactive(this)\n }\n\n /**\n * 设置响应式值, 替换掉原有的数据\n * @description 设置响应式值时,会自动监听值的变化,并进行校验\n * @param proxyData 响应式的值\n */\n setProxyData(proxyData: ModelData<Fields> | Reactive<ModelData<Fields>>): void {\n const data = middleProxy(proxyData, {\n set: (field, val) => {\n this.modelChangeCallback.forEach((cb) => cb(field, val))\n },\n\n changed: (fields) => {\n if (!this.validateOnFieldChange) {\n this.validateOnFieldChange = true\n return\n }\n this.validate(fields as any)\n }\n })\n\n this.data = data as ModelData<Fields>\n }\n\n private getValidateFields(fields?: AllKeys<Fields> | AllKeys<Fields>[]) {\n if (!fields) {\n if (this.formKeys.size) {\n let _fields: AllKeys<Fields>[] = []\n this.formKeys.forEach((fields) => {\n _fields = _fields.concat(fields)\n })\n return _fields\n } else {\n return this.allKeys as AllKeys<Fields>[]\n }\n }\n\n if (!Array.isArray(fields)) {\n return [fields]\n }\n return fields\n }\n\n /**\n * 模型校验\n * @param fields 需要校验的字段, 不传则校验所有字段\n * @returns\n */\n async validate(fields?: AllKeys<Fields> | AllKeys<Fields>[]): Promise<boolean> {\n const { errors, validator, data } = this\n\n const results = await validator.validate(data, this.getValidateFields(fields) as any)\n\n // 全量校验\n if (!fields) {\n errors.clear()\n\n for (const field in results) {\n errors.set(field as any, results[field])\n }\n }\n // 局部校验\n else {\n ~(Array.isArray(fields) ? fields : [fields]).forEach((field) => {\n const errs = results[field as string]\n if (errs?.length) {\n errors.set(field, errs)\n } else {\n errors.delete(field)\n }\n })\n }\n\n if (errors.size > 0) {\n if (!fields) {\n nextTick(() => {\n document.querySelector('.u-form-item.is-error')?.scrollIntoView({ block: 'nearest' })\n })\n }\n return Promise.reject(false)\n }\n\n return true\n }\n\n /**\n * 重置数据\n * @param fields 需要重置的字段\n */\n resetData(keys?: AllKeys<Fields> | AllKeys<Fields>[]): void {\n if (typeof keys === 'string') {\n keys = [keys]\n } else if (Array.isArray(keys)) {\n } else {\n keys = this.allKeys as AllKeys<Fields>[]\n }\n\n this.clearValidate()\n\n this.validateOnFieldChange = false\n\n keys.forEach((field) => {\n o(this.data).set(field as string, o(this.initialData).get(field as string))\n })\n }\n\n /**\n * 设置值\n * @param formData 表单值\n * @param options 配置\n */\n setData(\n formData: Partial<ModelData<Fields> & Record<string, any>>,\n config?: DataSettingConfig\n ): FormModel<Fields> {\n const { validate = true } = config || {}\n\n if (!validate) {\n this.validateOnFieldChange = false\n }\n\n this.allKeys.forEach((key) => {\n const value = o(formData).get(key)\n if (value !== undefined) {\n o(this.data).set(key, value)\n }\n })\n\n return this\n }\n\n /**\n * 设置初始值\n * @description 初始值在重置数据和查看原始数据时会用到\n * @param data 初始值\n */\n setInitialData(data: Partial<ModelData<Fields>>): FormModel<Fields> {\n this.allKeys.forEach((key) => {\n o(this.initialData).set(key, o(data).get(key))\n })\n\n return this\n }\n\n /** 清除校验 */\n clearValidate(): void {\n this.errors.clear()\n }\n\n /**\n * 监听值变更\n * @param cb 回调\n */\n onChange(cb: (field: AllKeys<Fields>, val: any) => void): void {\n this.modelChangeCallback.add(cb as any)\n }\n\n /** 关闭监听值变更 */\n offChange(cb: (field: AllKeys<Fields>, val: any) => void): void {\n this.modelChangeCallback.delete(cb as any)\n }\n}\n"],"mappings":"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"}