@class-kit/vue 0.1.3 → 0.1.4

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 (239) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/components/affix.cjs.map +1 -1
  3. package/dist/components/affix.js.map +1 -1
  4. package/dist/components/backtop.cjs +61 -0
  5. package/dist/components/backtop.cjs.map +1 -1
  6. package/dist/components/backtop.js +61 -0
  7. package/dist/components/backtop.js.map +1 -1
  8. package/dist/components/badge.cjs.map +1 -1
  9. package/dist/components/badge.js.map +1 -1
  10. package/dist/components/barcode.cjs.map +1 -1
  11. package/dist/components/barcode.js.map +1 -1
  12. package/dist/components/breadcrumb.cjs.map +1 -1
  13. package/dist/components/breadcrumb.js.map +1 -1
  14. package/dist/components/button.cjs.map +1 -1
  15. package/dist/components/button.js.map +1 -1
  16. package/dist/components/calendar.cjs +61 -0
  17. package/dist/components/calendar.cjs.map +1 -1
  18. package/dist/components/calendar.js +61 -0
  19. package/dist/components/calendar.js.map +1 -1
  20. package/dist/components/canvas-editor.cjs.map +1 -1
  21. package/dist/components/canvas-editor.js.map +1 -1
  22. package/dist/components/canvas-image.cjs.map +1 -1
  23. package/dist/components/canvas-image.js.map +1 -1
  24. package/dist/components/chat-textarea.cjs +61 -0
  25. package/dist/components/chat-textarea.cjs.map +1 -1
  26. package/dist/components/chat-textarea.js +61 -0
  27. package/dist/components/chat-textarea.js.map +1 -1
  28. package/dist/components/chat-virtual-list.cjs.map +1 -1
  29. package/dist/components/chat-virtual-list.js.map +1 -1
  30. package/dist/components/checkbox.cjs.map +1 -1
  31. package/dist/components/checkbox.js.map +1 -1
  32. package/dist/components/checked.cjs.map +1 -1
  33. package/dist/components/checked.js.map +1 -1
  34. package/dist/components/code-preview.cjs.map +1 -1
  35. package/dist/components/code-preview.js.map +1 -1
  36. package/dist/components/color-picker.cjs.map +1 -1
  37. package/dist/components/color-picker.js.map +1 -1
  38. package/dist/components/comic-reader.cjs.map +1 -1
  39. package/dist/components/comic-reader.js.map +1 -1
  40. package/dist/components/config-provider.cjs.map +1 -1
  41. package/dist/components/config-provider.js.map +1 -1
  42. package/dist/components/config-table.cjs +61 -0
  43. package/dist/components/config-table.cjs.map +1 -1
  44. package/dist/components/config-table.js +61 -0
  45. package/dist/components/config-table.js.map +1 -1
  46. package/dist/components/countdown.cjs.map +1 -1
  47. package/dist/components/countdown.js.map +1 -1
  48. package/dist/components/danmaku.cjs.map +1 -1
  49. package/dist/components/danmaku.js.map +1 -1
  50. package/dist/components/date-picker.cjs +61 -0
  51. package/dist/components/date-picker.cjs.map +1 -1
  52. package/dist/components/date-picker.js +61 -0
  53. package/dist/components/date-picker.js.map +1 -1
  54. package/dist/components/date-range-picker.cjs +61 -0
  55. package/dist/components/date-range-picker.cjs.map +1 -1
  56. package/dist/components/date-range-picker.js +61 -0
  57. package/dist/components/date-range-picker.js.map +1 -1
  58. package/dist/components/design-effect.cjs.map +1 -1
  59. package/dist/components/design-effect.js.map +1 -1
  60. package/dist/components/drag-drop-board.cjs.map +1 -1
  61. package/dist/components/drag-drop-board.js.map +1 -1
  62. package/dist/components/draggable.cjs.map +1 -1
  63. package/dist/components/draggable.js.map +1 -1
  64. package/dist/components/ellipsis-text.cjs.map +1 -1
  65. package/dist/components/ellipsis-text.js.map +1 -1
  66. package/dist/components/empty.cjs.map +1 -1
  67. package/dist/components/empty.js.map +1 -1
  68. package/dist/components/field.cjs +61 -0
  69. package/dist/components/field.cjs.map +1 -1
  70. package/dist/components/field.js +61 -0
  71. package/dist/components/field.js.map +1 -1
  72. package/dist/components/file-preview.cjs.map +1 -1
  73. package/dist/components/file-preview.js.map +1 -1
  74. package/dist/components/floating-ball.cjs.map +1 -1
  75. package/dist/components/floating-ball.js.map +1 -1
  76. package/dist/components/form.cjs +5 -1
  77. package/dist/components/form.cjs.map +1 -1
  78. package/dist/components/form.js +5 -1
  79. package/dist/components/form.js.map +1 -1
  80. package/dist/components/gradient-text.cjs.map +1 -1
  81. package/dist/components/gradient-text.js.map +1 -1
  82. package/dist/components/height-transition.cjs.map +1 -1
  83. package/dist/components/height-transition.js.map +1 -1
  84. package/dist/components/input.cjs +61 -0
  85. package/dist/components/input.cjs.map +1 -1
  86. package/dist/components/input.js +61 -0
  87. package/dist/components/input.js.map +1 -1
  88. package/dist/components/lazy-image.cjs.map +1 -1
  89. package/dist/components/lazy-image.js.map +1 -1
  90. package/dist/components/live-room.cjs.map +1 -1
  91. package/dist/components/live-room.js.map +1 -1
  92. package/dist/components/loading.cjs.map +1 -1
  93. package/dist/components/loading.js.map +1 -1
  94. package/dist/components/marquee.cjs.map +1 -1
  95. package/dist/components/marquee.js.map +1 -1
  96. package/dist/components/masonry-virtual-list.cjs.map +1 -1
  97. package/dist/components/masonry-virtual-list.js.map +1 -1
  98. package/dist/components/menu.cjs +61 -0
  99. package/dist/components/menu.cjs.map +1 -1
  100. package/dist/components/menu.js +61 -0
  101. package/dist/components/menu.js.map +1 -1
  102. package/dist/components/modal.cjs +61 -0
  103. package/dist/components/modal.cjs.map +1 -1
  104. package/dist/components/modal.js +61 -0
  105. package/dist/components/modal.js.map +1 -1
  106. package/dist/components/multi-column-picker.cjs.map +1 -1
  107. package/dist/components/multi-column-picker.js.map +1 -1
  108. package/dist/components/novel-reader.cjs.map +1 -1
  109. package/dist/components/novel-reader.js.map +1 -1
  110. package/dist/components/number-input.cjs +61 -0
  111. package/dist/components/number-input.cjs.map +1 -1
  112. package/dist/components/number-input.js +61 -0
  113. package/dist/components/number-input.js.map +1 -1
  114. package/dist/components/orbital-sphere.cjs.map +1 -1
  115. package/dist/components/orbital-sphere.js.map +1 -1
  116. package/dist/components/pagination.cjs +61 -0
  117. package/dist/components/pagination.cjs.map +1 -1
  118. package/dist/components/pagination.js +61 -0
  119. package/dist/components/pagination.js.map +1 -1
  120. package/dist/components/password-input.cjs +67 -12
  121. package/dist/components/password-input.cjs.map +1 -1
  122. package/dist/components/password-input.js +67 -12
  123. package/dist/components/password-input.js.map +1 -1
  124. package/dist/components/popconfirm.cjs.map +1 -1
  125. package/dist/components/popconfirm.js.map +1 -1
  126. package/dist/components/popup.cjs +61 -0
  127. package/dist/components/popup.cjs.map +1 -1
  128. package/dist/components/popup.js +61 -0
  129. package/dist/components/popup.js.map +1 -1
  130. package/dist/components/progress-bar.cjs.map +1 -1
  131. package/dist/components/progress-bar.js.map +1 -1
  132. package/dist/components/qr-code.cjs.map +1 -1
  133. package/dist/components/qr-code.js.map +1 -1
  134. package/dist/components/radio-group.cjs.map +1 -1
  135. package/dist/components/radio-group.js.map +1 -1
  136. package/dist/components/rating.cjs +61 -0
  137. package/dist/components/rating.cjs.map +1 -1
  138. package/dist/components/rating.js +61 -0
  139. package/dist/components/rating.js.map +1 -1
  140. package/dist/components/rich-editor.cjs +1341 -0
  141. package/dist/components/rich-editor.cjs.map +1 -0
  142. package/dist/components/rich-editor.d.ts +2 -0
  143. package/dist/components/rich-editor.d.ts.map +1 -0
  144. package/dist/components/rich-editor.js +1339 -0
  145. package/dist/components/rich-editor.js.map +1 -0
  146. package/dist/components/rolling-number.cjs.map +1 -1
  147. package/dist/components/rolling-number.js.map +1 -1
  148. package/dist/components/select.cjs +61 -0
  149. package/dist/components/select.cjs.map +1 -1
  150. package/dist/components/select.js +61 -0
  151. package/dist/components/select.js.map +1 -1
  152. package/dist/components/signature.cjs.map +1 -1
  153. package/dist/components/signature.js.map +1 -1
  154. package/dist/components/skeleton.cjs.map +1 -1
  155. package/dist/components/skeleton.js.map +1 -1
  156. package/dist/components/slide-captcha.cjs +61 -0
  157. package/dist/components/slide-captcha.cjs.map +1 -1
  158. package/dist/components/slide-captcha.js +61 -0
  159. package/dist/components/slide-captcha.js.map +1 -1
  160. package/dist/components/swiper.cjs +61 -0
  161. package/dist/components/swiper.cjs.map +1 -1
  162. package/dist/components/swiper.js +61 -0
  163. package/dist/components/swiper.js.map +1 -1
  164. package/dist/components/switch.cjs.map +1 -1
  165. package/dist/components/switch.js.map +1 -1
  166. package/dist/components/table.cjs +61 -0
  167. package/dist/components/table.cjs.map +1 -1
  168. package/dist/components/table.js +61 -0
  169. package/dist/components/table.js.map +1 -1
  170. package/dist/components/tabs.cjs.map +1 -1
  171. package/dist/components/tabs.js.map +1 -1
  172. package/dist/components/tag.cjs +61 -0
  173. package/dist/components/tag.cjs.map +1 -1
  174. package/dist/components/tag.js +61 -0
  175. package/dist/components/tag.js.map +1 -1
  176. package/dist/components/textarea.cjs +61 -0
  177. package/dist/components/textarea.cjs.map +1 -1
  178. package/dist/components/textarea.js +61 -0
  179. package/dist/components/textarea.js.map +1 -1
  180. package/dist/components/theme-box.cjs.map +1 -1
  181. package/dist/components/theme-box.js.map +1 -1
  182. package/dist/components/tilt-card.cjs.map +1 -1
  183. package/dist/components/tilt-card.js.map +1 -1
  184. package/dist/components/timeline.cjs.map +1 -1
  185. package/dist/components/timeline.js.map +1 -1
  186. package/dist/components/toast.cjs +61 -0
  187. package/dist/components/toast.cjs.map +1 -1
  188. package/dist/components/toast.js +61 -0
  189. package/dist/components/toast.js.map +1 -1
  190. package/dist/components/tooltip.cjs.map +1 -1
  191. package/dist/components/tooltip.js.map +1 -1
  192. package/dist/components/typewriter-text.cjs.map +1 -1
  193. package/dist/components/typewriter-text.js.map +1 -1
  194. package/dist/components/upload.cjs +61 -0
  195. package/dist/components/upload.cjs.map +1 -1
  196. package/dist/components/upload.js +61 -0
  197. package/dist/components/upload.js.map +1 -1
  198. package/dist/components/verification-code.cjs.map +1 -1
  199. package/dist/components/verification-code.js.map +1 -1
  200. package/dist/components/video-detail-transition.cjs +61 -0
  201. package/dist/components/video-detail-transition.cjs.map +1 -1
  202. package/dist/components/video-detail-transition.js +61 -0
  203. package/dist/components/video-detail-transition.js.map +1 -1
  204. package/dist/components/video-player.cjs.map +1 -1
  205. package/dist/components/video-player.js.map +1 -1
  206. package/dist/components/virtual-list.cjs.map +1 -1
  207. package/dist/components/virtual-list.js.map +1 -1
  208. package/dist/components/virtual-select.cjs +61 -0
  209. package/dist/components/virtual-select.cjs.map +1 -1
  210. package/dist/components/virtual-select.js +61 -0
  211. package/dist/components/virtual-select.js.map +1 -1
  212. package/dist/components/virtual-table.cjs +61 -0
  213. package/dist/components/virtual-table.cjs.map +1 -1
  214. package/dist/components/virtual-table.js +61 -0
  215. package/dist/components/virtual-table.js.map +1 -1
  216. package/dist/components/width-transition.cjs.map +1 -1
  217. package/dist/components/width-transition.js.map +1 -1
  218. package/dist/import-transform-BJDUXanp.js +153 -0
  219. package/dist/import-transform-BJDUXanp.js.map +1 -0
  220. package/dist/import-transform-yUes6fHV.js +151 -0
  221. package/dist/import-transform-yUes6fHV.js.map +1 -0
  222. package/dist/import-transform.d.ts.map +1 -1
  223. package/dist/index.cjs +817 -13
  224. package/dist/index.cjs.map +1 -1
  225. package/dist/index.d.ts +80 -26
  226. package/dist/index.d.ts.map +1 -1
  227. package/dist/index.js +816 -17
  228. package/dist/index.js.map +1 -1
  229. package/dist/styles/components/password-input.css +4 -4
  230. package/dist/styles/components/rich-editor.css +511 -0
  231. package/dist/styles/components/tooltip.css +24 -0
  232. package/dist/styles/components.css +513 -4
  233. package/dist/styles/themes/dark-tech.css +34 -0
  234. package/dist/styles.css +513 -4
  235. package/dist/vite.cjs +1 -1
  236. package/dist/vite.js +1 -1
  237. package/dist/webpack-loader.cjs +1 -1
  238. package/dist/webpack-loader.js +1 -1
  239. package/package.json +11 -3
@@ -0,0 +1,1339 @@
1
+ import { defineComponent, ref, watch, onBeforeUnmount, h, shallowRef, nextTick, onMounted, Teleport } from 'vue';
2
+ import { RichEditorController, ToastManager, getClassComponentsLocale, configureClassComponents, TooltipController, getSafeTooltipPlacement } from '@class-kit/core';
3
+
4
+ let tooltipIdSeed = 0;
5
+ const defaultToastManager = /*#__PURE__*/ new ToastManager();
6
+ const classIconPaths = {
7
+ alignCenter: ["M6 6h12", "M4 12h16", "M7 18h10"],
8
+ alignLeft: ["M4 6h16", "M4 12h12", "M4 18h16"],
9
+ alignRight: ["M4 6h16", "M8 12h12", "M4 18h16"],
10
+ bold: ["M7 5h6a3.5 3.5 0 0 1 0 7H7z", "M7 12h7a3.5 3.5 0 0 1 0 7H7z"],
11
+ chevronDown: ["M6 9l6 6 6-6"],
12
+ chevronLeft: ["M15 18l-6-6 6-6"],
13
+ chevronRight: ["M9 18l6-6-6-6"],
14
+ chevronUp: ["M18 15l-6-6-6 6"],
15
+ check: ["M20 6 9 17l-5-5"],
16
+ code: ["M9 18 3 12l6-6", "M15 6l6 6-6 6"],
17
+ eraser: ["M7 21h10", "M17 3 4 16l5 5 13-13z", "M14 6l4 4"],
18
+ fileCode: [
19
+ "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z",
20
+ "M14 2v6h6",
21
+ "M10 13l-2 2 2 2",
22
+ "M14 17l2-2-2-2",
23
+ ],
24
+ heading: ["M6 5v14", "M18 5v14", "M6 12h12"],
25
+ image: ["M5 5h14v14H5z", "M8 15l3-3 2 2 3-4 3 5", "M9 9h.01"],
26
+ italic: ["M10 5h8", "M6 19h8", "M14 5l-4 14"],
27
+ link: [
28
+ "M10 13a5 5 0 0 0 7.07 0l2-2a5 5 0 0 0-7.07-7.07l-1.1 1.1",
29
+ "M14 11a5 5 0 0 0-7.07 0l-2 2A5 5 0 0 0 12 20.07l1.1-1.1",
30
+ ],
31
+ list: [
32
+ "M8 6h13",
33
+ "M8 12h13",
34
+ "M8 18h13",
35
+ "M3 6h.01",
36
+ "M3 12h.01",
37
+ "M3 18h.01",
38
+ ],
39
+ listOrdered: [
40
+ "M10 6h11",
41
+ "M10 12h11",
42
+ "M10 18h11",
43
+ "M4 6h1v4",
44
+ "M4 10h2",
45
+ "M4 14a2 2 0 0 1 2 2c0 1-2 2-2 4h3",
46
+ ],
47
+ palette: [
48
+ "M12 3a9 9 0 0 0 0 18h1.5a1.8 1.8 0 0 0 1.2-3.1 1.8 1.8 0 0 1 1.2-3.1H18a6 6 0 0 0 0-12z",
49
+ "M7.5 10h.01",
50
+ "M10 6.5h.01",
51
+ "M14 6.5h.01",
52
+ "M16.5 10h.01",
53
+ ],
54
+ paragraph: ["M13 5v14", "M17 5v14", "M7 5h8a4 4 0 0 1 0 8H7z"],
55
+ quote: ["M8 11H5a3 3 0 0 1 3-3v8", "M19 11h-3a3 3 0 0 1 3-3v8"],
56
+ redo: ["M21 7v6h-6", "M21 13a8 8 0 1 1-2.34-5.66"],
57
+ settings: [
58
+ "M12 15.5A3.5 3.5 0 1 0 12 8a3.5 3.5 0 0 0 0 7.5Z",
59
+ "M19.4 15a1.8 1.8 0 0 0 .36 1.98l.04.04a2.18 2.18 0 0 1-3.08 3.08l-.04-.04a1.8 1.8 0 0 0-1.98-.36 1.8 1.8 0 0 0-1 1.62V21a2.2 2.2 0 0 1-4.4 0v-.06a1.8 1.8 0 0 0-1-1.62 1.8 1.8 0 0 0-1.98.36l-.04.04A2.18 2.18 0 0 1 3.2 16.64l.04-.04A1.8 1.8 0 0 0 3.6 14.6a1.8 1.8 0 0 0-1.62-1H2a2.2 2.2 0 0 1 0-4.4h.06a1.8 1.8 0 0 0 1.62-1 1.8 1.8 0 0 0-.36-1.98l-.04-.04A2.18 2.18 0 0 1 6.36 3.1l.04.04a1.8 1.8 0 0 0 1.98.36h.08A1.8 1.8 0 0 0 9.4 1.88V1.8a2.2 2.2 0 0 1 4.4 0v.06a1.8 1.8 0 0 0 1 1.62 1.8 1.8 0 0 0 1.98-.36l.04-.04A2.18 2.18 0 0 1 19.9 6.16l-.04.04a1.8 1.8 0 0 0-.36 1.98v.08a1.8 1.8 0 0 0 1.62.94h.08a2.2 2.2 0 0 1 0 4.4h-.06A1.8 1.8 0 0 0 19.4 15Z",
60
+ ],
61
+ star: [
62
+ "M12 2l3.09 6.26 6.91 1-5 4.87 1.18 6.87L12 17.77 5.82 21 7 14.13l-5-4.87 6.91-1L12 2Z",
63
+ ],
64
+ strikethrough: [
65
+ "M5 12h14",
66
+ "M16 6.5A4 4 0 0 0 12.5 5H11a3 3 0 0 0-.7 5.9",
67
+ "M8 17.5A4.2 4.2 0 0 0 11.5 19H13a3 3 0 0 0 .7-5.9",
68
+ ],
69
+ table: ["M4 5h16v14H4z", "M4 11h16", "M10 5v14"],
70
+ trash: ["M3 6h18", "M8 6V4h8v2", "M6 6l1 15h10l1-15", "M10 11v6", "M14 11v6"],
71
+ type: ["M4 7V5h16v2", "M12 5v14", "M8 19h8"],
72
+ underline: ["M7 5v6a5 5 0 0 0 10 0V5", "M5 21h14"],
73
+ undo: ["M3 7v6h6", "M3 13a8 8 0 1 0 2.34-5.66"],
74
+ uploadCloud: [
75
+ "M16 16l-4-4-4 4",
76
+ "M12 12v9",
77
+ "M20 16.6A5 5 0 0 0 18 7h-1.26A8 8 0 1 0 4 15.25",
78
+ ],
79
+ video: ["M4 6h11v12H4z", "M15 10l5-3v10l-5-3z"],
80
+ x: ["M18 6 6 18", "M6 6l12 12"],
81
+ };
82
+ function classIcon(name, className = "cc-icon") {
83
+ return h("svg", {
84
+ "aria-hidden": "true",
85
+ class: className,
86
+ fill: name === "star" ? "currentColor" : "none",
87
+ focusable: "false",
88
+ viewBox: "0 0 24 24",
89
+ }, classIconPaths[name].map((d) => h("path", {
90
+ d,
91
+ "stroke-linecap": "round",
92
+ "stroke-linejoin": "round",
93
+ "stroke-width": name === "star" ? 0 : 2,
94
+ stroke: "currentColor",
95
+ })));
96
+ }
97
+ function resolveClassKitThemeName(theme) {
98
+ var _a;
99
+ if (typeof theme === "string")
100
+ return theme;
101
+ return (_a = theme === null || theme === void 0 ? void 0 : theme.name) !== null && _a !== void 0 ? _a : "minimal";
102
+ }
103
+ function applyDocumentTheme(themeName) {
104
+ if (typeof document === "undefined")
105
+ return undefined;
106
+ const root = document.documentElement;
107
+ const previousTheme = root.getAttribute("data-cc-theme");
108
+ const previousPage = root.getAttribute("data-cc-theme-page");
109
+ root.setAttribute("data-cc-theme", themeName);
110
+ root.setAttribute("data-cc-theme-page", "true");
111
+ return () => {
112
+ if (previousTheme === null)
113
+ root.removeAttribute("data-cc-theme");
114
+ else
115
+ root.setAttribute("data-cc-theme", previousTheme);
116
+ if (previousPage === null)
117
+ root.removeAttribute("data-cc-theme-page");
118
+ else
119
+ root.setAttribute("data-cc-theme-page", previousPage);
120
+ };
121
+ }
122
+ defineComponent({
123
+ name: "ClassConfigProvider",
124
+ props: {
125
+ applyGlobalTheme: {
126
+ type: Boolean,
127
+ default: true,
128
+ },
129
+ class: {
130
+ type: String,
131
+ default: "",
132
+ },
133
+ locale: {
134
+ type: Object,
135
+ default: undefined,
136
+ },
137
+ style: {
138
+ type: [String, Object, Array],
139
+ default: undefined,
140
+ },
141
+ theme: {
142
+ type: [String, Object],
143
+ default: "minimal",
144
+ },
145
+ },
146
+ setup(props, { slots }) {
147
+ const version = ref(0);
148
+ let restoreDocumentTheme;
149
+ const applyConfig = () => {
150
+ configureClassComponents({
151
+ locale: props.locale,
152
+ theme: props.theme,
153
+ });
154
+ version.value += 1;
155
+ };
156
+ const applyGlobalTheme = () => {
157
+ restoreDocumentTheme === null || restoreDocumentTheme === void 0 ? void 0 : restoreDocumentTheme();
158
+ restoreDocumentTheme = props.applyGlobalTheme
159
+ ? applyDocumentTheme(resolveClassKitThemeName(props.theme))
160
+ : undefined;
161
+ };
162
+ watch(() => [props.locale, props.theme], applyConfig, {
163
+ deep: true,
164
+ immediate: true,
165
+ });
166
+ watch(() => [props.applyGlobalTheme, props.theme], applyGlobalTheme, {
167
+ deep: true,
168
+ immediate: true,
169
+ });
170
+ onBeforeUnmount(() => {
171
+ restoreDocumentTheme === null || restoreDocumentTheme === void 0 ? void 0 : restoreDocumentTheme();
172
+ });
173
+ return () => {
174
+ var _a;
175
+ return h("div", {
176
+ class: ["cc-config-provider", props.class].filter(Boolean),
177
+ "data-cc-theme": resolveClassKitThemeName(props.theme),
178
+ style: props.style,
179
+ }, [
180
+ h("div", { key: version.value, class: "cc-config-provider__content" }, (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)),
181
+ ]);
182
+ };
183
+ },
184
+ });
185
+ function resolveAnimation(animation, fallbackName) {
186
+ var _a, _b, _c, _d;
187
+ if (animation === false) {
188
+ return {
189
+ duration: 0,
190
+ easing: "ease",
191
+ enabled: false,
192
+ name: "none",
193
+ };
194
+ }
195
+ return {
196
+ duration: (_a = animation === null || animation === void 0 ? void 0 : animation.duration) !== null && _a !== void 0 ? _a : 180,
197
+ easing: (_b = animation === null || animation === void 0 ? void 0 : animation.easing) !== null && _b !== void 0 ? _b : "cubic-bezier(0.22, 0.8, 0.28, 1)",
198
+ enabled: (_c = animation === null || animation === void 0 ? void 0 : animation.enabled) !== null && _c !== void 0 ? _c : true,
199
+ name: (_d = animation === null || animation === void 0 ? void 0 : animation.name) !== null && _d !== void 0 ? _d : fallbackName,
200
+ };
201
+ }
202
+ function animationStyle(animation) {
203
+ return {
204
+ "--cc-animation-duration": `${animation.enabled ? animation.duration : 0}ms`,
205
+ "--cc-animation-easing": animation.easing,
206
+ };
207
+ }
208
+ function normalizeToastMaxVisible(maxVisible) {
209
+ if (typeof maxVisible !== "number" || !Number.isFinite(maxVisible))
210
+ return 3;
211
+ return Math.max(1, Math.min(6, Math.floor(maxVisible)));
212
+ }
213
+ function isToastTopPosition(position) {
214
+ return (position === "top" || position === "top-left" || position === "top-right");
215
+ }
216
+ const dynamicImportModule = (name) => new Function("name", "return import(name)")(name);
217
+ function normalizeRichEditorUrl(value) {
218
+ var _a;
219
+ const url = (_a = value === null || value === void 0 ? void 0 : value.trim()) !== null && _a !== void 0 ? _a : "";
220
+ if (!url)
221
+ return "";
222
+ try {
223
+ const parsed = new URL(url);
224
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:")
225
+ return "";
226
+ return parsed.toString();
227
+ }
228
+ catch (_b) {
229
+ return "";
230
+ }
231
+ }
232
+ function createRichEditorTableHtml() {
233
+ return [
234
+ '<table style="width: 100%; border-collapse: collapse;">',
235
+ "<tbody>",
236
+ "<tr><td>标题</td><td>内容</td></tr>",
237
+ "<tr><td>示例</td><td>可继续编辑</td></tr>",
238
+ "</tbody>",
239
+ "</table><p><br></p>",
240
+ ].join("");
241
+ }
242
+ function getRichEditorImageFiles(files) {
243
+ return Array.from(files !== null && files !== void 0 ? files : []).filter((file) => file.type.startsWith("image/"));
244
+ }
245
+ function resolveRichEditorUploadUrl(payload) {
246
+ var _a, _b, _c, _d, _e, _f, _g, _h;
247
+ if (typeof payload === "string")
248
+ return payload;
249
+ if (!payload || typeof payload !== "object")
250
+ return "";
251
+ const record = payload;
252
+ const data = record.data;
253
+ return String((_h = (_g = (_f = (_e = (_d = (_c = (_b = (_a = record.url) !== null && _a !== void 0 ? _a : record.href) !== null && _b !== void 0 ? _b : record.src) !== null && _c !== void 0 ? _c : record.path) !== null && _d !== void 0 ? _d : data === null || data === void 0 ? void 0 : data.url) !== null && _e !== void 0 ? _e : data === null || data === void 0 ? void 0 : data.href) !== null && _f !== void 0 ? _f : data === null || data === void 0 ? void 0 : data.src) !== null && _g !== void 0 ? _g : data === null || data === void 0 ? void 0 : data.path) !== null && _h !== void 0 ? _h : "");
254
+ }
255
+ async function postRichEditorImage(file, uploadUrl, uploadHeaders) {
256
+ const formData = new FormData();
257
+ formData.append("file", file);
258
+ const response = await fetch(uploadUrl, {
259
+ body: formData,
260
+ credentials: "include",
261
+ headers: uploadHeaders,
262
+ method: "POST",
263
+ });
264
+ if (!response.ok) {
265
+ throw new Error("图片上传失败,请重试");
266
+ }
267
+ const payload = await response.json().catch(() => undefined);
268
+ const url = resolveRichEditorUploadUrl(payload);
269
+ if (!url) {
270
+ throw new Error("图片上传失败,请重试");
271
+ }
272
+ return { url };
273
+ }
274
+ const ClassRichEditor = /*#__PURE__*/ defineComponent({
275
+ name: "ClassRichEditor",
276
+ props: {
277
+ className: String,
278
+ disabled: Boolean,
279
+ height: {
280
+ type: Number,
281
+ default: 400,
282
+ },
283
+ onError: Function,
284
+ placeholder: {
285
+ type: String,
286
+ default: "请输入内容",
287
+ },
288
+ readOnly: Boolean,
289
+ uploadHeaders: Object,
290
+ uploadImage: Function,
291
+ uploadUrl: String,
292
+ value: {
293
+ type: String,
294
+ default: "",
295
+ },
296
+ },
297
+ emits: ["update:value", "change", "error"],
298
+ setup(props, { emit }) {
299
+ const controller = new RichEditorController({ html: props.value });
300
+ const html = ref(controller.getState().html);
301
+ const sourceMode = ref(false);
302
+ const uploading = ref(false);
303
+ const notice = ref(null);
304
+ const wang = shallowRef(null);
305
+ const editor = shallowRef(null);
306
+ const fallbackEditor = ref(null);
307
+ const fileInput = ref(null);
308
+ const urlDialogInput = ref(null);
309
+ const fallbackSelection = shallowRef(null);
310
+ const urlDialog = ref(null);
311
+ const toastManager = new ToastManager();
312
+ const syncFallbackEditor = () => {
313
+ var _a;
314
+ const element = fallbackEditor.value;
315
+ if (!element || sourceMode.value || ((_a = wang.value) === null || _a === void 0 ? void 0 : _a.Editor))
316
+ return;
317
+ if (document.activeElement === element)
318
+ return;
319
+ if (element.innerHTML !== html.value)
320
+ element.innerHTML = html.value;
321
+ };
322
+ const emitError = (message) => {
323
+ var _a;
324
+ toastManager.show({ message, tone: "danger" });
325
+ (_a = props.onError) === null || _a === void 0 ? void 0 : _a.call(props, message);
326
+ emit("error", message);
327
+ };
328
+ const commitHtml = (nextHtml) => {
329
+ const state = controller.setHtml(nextHtml);
330
+ html.value = state.html;
331
+ emit("update:value", state.html);
332
+ emit("change", state.html);
333
+ return state.html;
334
+ };
335
+ const uploadHandler = async (file) => {
336
+ if (props.uploadImage)
337
+ return props.uploadImage(file);
338
+ if (props.uploadUrl) {
339
+ return postRichEditorImage(file, props.uploadUrl, props.uploadHeaders);
340
+ }
341
+ throw new Error("请配置图片上传接口");
342
+ };
343
+ const saveFallbackSelection = () => {
344
+ const element = fallbackEditor.value;
345
+ const selection = window.getSelection();
346
+ if (!element || !selection || selection.rangeCount === 0)
347
+ return;
348
+ const range = selection.getRangeAt(0);
349
+ if (!element.contains(range.commonAncestorContainer))
350
+ return;
351
+ fallbackSelection.value = range.cloneRange();
352
+ };
353
+ const restoreFallbackSelection = () => {
354
+ if (!fallbackSelection.value)
355
+ return;
356
+ const selection = window.getSelection();
357
+ selection === null || selection === void 0 ? void 0 : selection.removeAllRanges();
358
+ selection === null || selection === void 0 ? void 0 : selection.addRange(fallbackSelection.value);
359
+ };
360
+ const insertFallbackHtml = (nextHtml) => {
361
+ var _a;
362
+ (_a = fallbackEditor.value) === null || _a === void 0 ? void 0 : _a.focus();
363
+ restoreFallbackSelection();
364
+ document.execCommand("insertHTML", false, nextHtml);
365
+ if (fallbackEditor.value)
366
+ commitHtml(fallbackEditor.value.innerHTML);
367
+ };
368
+ const runFallbackCommand = (command, value) => {
369
+ var _a;
370
+ (_a = fallbackEditor.value) === null || _a === void 0 ? void 0 : _a.focus();
371
+ restoreFallbackSelection();
372
+ document.execCommand(command, false, value);
373
+ if (fallbackEditor.value)
374
+ commitHtml(fallbackEditor.value.innerHTML);
375
+ };
376
+ const deleteSelectedContent = () => {
377
+ var _a, _b, _c;
378
+ if (props.disabled)
379
+ return;
380
+ const currentEditor = editor.value;
381
+ if (currentEditor === null || currentEditor === void 0 ? void 0 : currentEditor.deleteFragment) {
382
+ (_a = currentEditor.focus) === null || _a === void 0 ? void 0 : _a.call(currentEditor);
383
+ currentEditor.deleteFragment();
384
+ const nextHtml = (_b = currentEditor.getHtml) === null || _b === void 0 ? void 0 : _b.call(currentEditor);
385
+ if (typeof nextHtml === "string")
386
+ commitHtml(nextHtml);
387
+ return;
388
+ }
389
+ (_c = fallbackEditor.value) === null || _c === void 0 ? void 0 : _c.focus();
390
+ restoreFallbackSelection();
391
+ document.execCommand("delete");
392
+ if (fallbackEditor.value)
393
+ commitHtml(fallbackEditor.value.innerHTML);
394
+ };
395
+ const handleFallbackUpload = async (files) => {
396
+ const images = getRichEditorImageFiles(files);
397
+ if (images.length === 0)
398
+ return;
399
+ uploading.value = true;
400
+ notice.value = { text: "图片上传中...", type: "loading" };
401
+ try {
402
+ for (const file of images) {
403
+ const result = await controller.uploadImage(file, uploadHandler);
404
+ insertFallbackHtml(`<p><img src="${result.url}" alt="${file.name}" /></p>`);
405
+ }
406
+ notice.value = { text: "图片上传完成", type: "success" };
407
+ }
408
+ catch (error) {
409
+ emitError(error instanceof Error ? error.message : "图片上传失败,请重试");
410
+ }
411
+ finally {
412
+ uploading.value = false;
413
+ if (fileInput.value)
414
+ fileInput.value.value = "";
415
+ }
416
+ };
417
+ const openFallbackUrlDialog = (kind) => {
418
+ saveFallbackSelection();
419
+ const locale = getClassComponentsLocale();
420
+ const dialogMap = {
421
+ image: {
422
+ icon: "image",
423
+ placeholder: locale.richEditorInsertImagePlaceholder,
424
+ title: locale.richEditorInsertImageTitle,
425
+ },
426
+ link: {
427
+ icon: "link",
428
+ placeholder: locale.richEditorInsertLinkPlaceholder,
429
+ title: locale.richEditorInsertLinkTitle,
430
+ },
431
+ video: {
432
+ icon: "video",
433
+ placeholder: locale.richEditorInsertVideoPlaceholder,
434
+ title: locale.richEditorInsertVideoTitle,
435
+ },
436
+ };
437
+ urlDialog.value = { ...dialogMap[kind], kind, value: "" };
438
+ void nextTick(() => { var _a; return (_a = urlDialogInput.value) === null || _a === void 0 ? void 0 : _a.focus(); });
439
+ };
440
+ const closeFallbackUrlDialog = () => {
441
+ urlDialog.value = null;
442
+ };
443
+ const submitFallbackUrlDialog = () => {
444
+ var _a;
445
+ if (!urlDialog.value)
446
+ return;
447
+ const dialog = urlDialog.value;
448
+ const url = normalizeRichEditorUrl(dialog.value);
449
+ if (!url) {
450
+ emitError(getClassComponentsLocale().richEditorInvalidUrlText);
451
+ return;
452
+ }
453
+ if (dialog.kind === "image") {
454
+ insertFallbackHtml(`<p><img src="${url}" alt="" /></p>`);
455
+ }
456
+ else if (dialog.kind === "video") {
457
+ insertFallbackHtml(`<p><video controls src="${url}"></video></p>`);
458
+ }
459
+ else {
460
+ restoreFallbackSelection();
461
+ const text = ((_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.toString()) || url;
462
+ insertFallbackHtml(`<a href="${url}" target="_blank" rel="noopener noreferrer">${text}</a>`);
463
+ }
464
+ urlDialog.value = null;
465
+ };
466
+ watch(() => props.value, (nextValue) => {
467
+ const nextHtml = controller.setHtml(nextValue !== null && nextValue !== void 0 ? nextValue : "").html;
468
+ if (html.value !== nextHtml)
469
+ html.value = nextHtml;
470
+ });
471
+ watch(html, () => void nextTick(syncFallbackEditor), { flush: "post" });
472
+ watch(() => { var _a; return [sourceMode.value, (_a = wang.value) === null || _a === void 0 ? void 0 : _a.Editor]; }, () => void nextTick(syncFallbackEditor), { flush: "post" });
473
+ watch(() => [props.disabled, props.readOnly], () => {
474
+ var _a, _b, _c, _d;
475
+ if (props.disabled || props.readOnly)
476
+ (_b = (_a = editor.value) === null || _a === void 0 ? void 0 : _a.disable) === null || _b === void 0 ? void 0 : _b.call(_a);
477
+ else
478
+ (_d = (_c = editor.value) === null || _c === void 0 ? void 0 : _c.enable) === null || _d === void 0 ? void 0 : _d.call(_c);
479
+ });
480
+ onMounted(() => {
481
+ syncFallbackEditor();
482
+ dynamicImportModule("@wangeditor/editor-for-vue")
483
+ .then((module) => {
484
+ wang.value = module;
485
+ })
486
+ .catch(() => {
487
+ wang.value = null;
488
+ });
489
+ });
490
+ onBeforeUnmount(() => {
491
+ var _a, _b;
492
+ (_b = (_a = editor.value) === null || _a === void 0 ? void 0 : _a.destroy) === null || _b === void 0 ? void 0 : _b.call(_a);
493
+ editor.value = null;
494
+ });
495
+ const toolbarConfig = {
496
+ toolbarKeys: [
497
+ "bold",
498
+ "italic",
499
+ "underline",
500
+ "through",
501
+ "color",
502
+ "bgColor",
503
+ "fontSize",
504
+ "justifyLeft",
505
+ "justifyCenter",
506
+ "justifyRight",
507
+ "justifyJustify",
508
+ "numberedList",
509
+ "bulletedList",
510
+ "lineHeight",
511
+ "indent",
512
+ "delIndent",
513
+ "blockquote",
514
+ "codeBlock",
515
+ "uploadImage",
516
+ "insertImage",
517
+ "insertVideo",
518
+ "insertTable",
519
+ "insertLink",
520
+ "unLink",
521
+ "undo",
522
+ "redo",
523
+ "clearStyle",
524
+ ],
525
+ };
526
+ const editorConfig = {
527
+ MENU_CONF: {
528
+ uploadImage: {
529
+ allowedFileTypes: [
530
+ "image/jpeg",
531
+ "image/jpg",
532
+ "image/png",
533
+ "image/gif",
534
+ "image/webp",
535
+ ],
536
+ customUpload: async (file, insertFn) => {
537
+ uploading.value = true;
538
+ notice.value = { text: "图片上传中...", type: "loading" };
539
+ try {
540
+ const result = await controller.uploadImage(file, uploadHandler);
541
+ insertFn(result.url, file.name, result.url);
542
+ notice.value = { text: "图片上传完成", type: "success" };
543
+ }
544
+ catch (error) {
545
+ emitError(error instanceof Error ? error.message : "图片上传失败,请重试");
546
+ }
547
+ finally {
548
+ uploading.value = false;
549
+ }
550
+ },
551
+ },
552
+ },
553
+ autoFocus: false,
554
+ placeholder: props.placeholder,
555
+ readOnly: props.disabled,
556
+ customPaste: (_editor, event) => {
557
+ var _a;
558
+ const pastedHtml = (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.getData("text/html");
559
+ if (!pastedHtml)
560
+ return true;
561
+ event.preventDefault();
562
+ _editor.dangerouslyInsertHtml(controller.sanitize(pastedHtml));
563
+ return false;
564
+ },
565
+ };
566
+ const toolTip = (content, child) => h(ClassTooltip, { content, placement: "bottom" }, { default: () => child });
567
+ const toolIcon = (icon) => h("span", { class: "cc-rich-editor__summary-icon" }, [
568
+ classIcon(icon),
569
+ classIcon("chevronDown", "cc-rich-editor__chevron"),
570
+ ]);
571
+ const toolGroup = (label, icon, children) => h("div", {
572
+ class: "cc-rich-editor__tool-group",
573
+ "data-disabled": props.disabled ? "true" : "false",
574
+ }, [
575
+ toolTip(label, h("button", {
576
+ "aria-haspopup": "menu",
577
+ "aria-label": label,
578
+ class: "cc-rich-editor__tool-trigger",
579
+ disabled: props.disabled,
580
+ type: "button",
581
+ }, [toolIcon(icon)])),
582
+ h("div", { class: "cc-rich-editor__tool-menu", role: "menu" }, children),
583
+ ]);
584
+ return () => {
585
+ var _a, _b, _c;
586
+ const locale = getClassComponentsLocale();
587
+ const rootClass = [
588
+ "cc-rich-editor",
589
+ props.readOnly ? "cc-rich-editor--readonly" : "",
590
+ props.disabled ? "cc-rich-editor--disabled" : "",
591
+ (_a = props.className) !== null && _a !== void 0 ? _a : "",
592
+ ]
593
+ .filter(Boolean)
594
+ .join(" ");
595
+ if (props.readOnly) {
596
+ return h("div", { class: rootClass }, [
597
+ h("div", {
598
+ class: "cc-rich-editor__preview",
599
+ innerHTML: html.value,
600
+ style: { minHeight: `${props.height}px` },
601
+ }),
602
+ ]);
603
+ }
604
+ const toolbar = ((_b = wang.value) === null || _b === void 0 ? void 0 : _b.Toolbar) && editor.value
605
+ ? h(wang.value.Toolbar, {
606
+ defaultConfig: toolbarConfig,
607
+ editor: editor.value,
608
+ mode: "default",
609
+ })
610
+ : h("div", { class: "cc-rich-editor__fallback-toolbar" }, [
611
+ toolTip("加粗", h("button", {
612
+ "aria-label": "加粗",
613
+ class: "cc-rich-editor__tool",
614
+ disabled: props.disabled,
615
+ type: "button",
616
+ onClick: () => runFallbackCommand("bold"),
617
+ }, [classIcon("bold")])),
618
+ toolTip("斜体", h("button", {
619
+ "aria-label": "斜体",
620
+ class: "cc-rich-editor__tool",
621
+ disabled: props.disabled,
622
+ type: "button",
623
+ onClick: () => runFallbackCommand("italic"),
624
+ }, [classIcon("italic")])),
625
+ toolTip("下划线", h("button", {
626
+ "aria-label": "下划线",
627
+ class: "cc-rich-editor__tool",
628
+ disabled: props.disabled,
629
+ type: "button",
630
+ onClick: () => runFallbackCommand("underline"),
631
+ }, [classIcon("underline")])),
632
+ toolTip("删除线", h("button", {
633
+ "aria-label": "删除线",
634
+ class: "cc-rich-editor__tool",
635
+ disabled: props.disabled,
636
+ type: "button",
637
+ onClick: () => runFallbackCommand("strikeThrough"),
638
+ }, [classIcon("strikethrough")])),
639
+ toolTip("文字色", h("label", {
640
+ "aria-label": "文字色",
641
+ class: "cc-rich-editor__color-tool",
642
+ "data-disabled": props.disabled ? "true" : "false",
643
+ }, [
644
+ classIcon("type"),
645
+ h("input", {
646
+ disabled: props.disabled,
647
+ type: "color",
648
+ onChange: (event) => runFallbackCommand("foreColor", event.currentTarget.value),
649
+ }),
650
+ ])),
651
+ toolTip("背景色", h("label", {
652
+ "aria-label": "背景色",
653
+ class: "cc-rich-editor__color-tool cc-rich-editor__color-tool--background",
654
+ "data-disabled": props.disabled ? "true" : "false",
655
+ }, [
656
+ classIcon("palette"),
657
+ h("input", {
658
+ disabled: props.disabled,
659
+ type: "color",
660
+ onChange: (event) => runFallbackCommand("hiliteColor", event.currentTarget.value),
661
+ }),
662
+ ])),
663
+ toolGroup("段落和字号", "type", [
664
+ h("button", {
665
+ disabled: props.disabled,
666
+ type: "button",
667
+ onClick: () => runFallbackCommand("formatBlock", "p"),
668
+ }, [classIcon("paragraph"), h("span", "正文")]),
669
+ h("button", {
670
+ disabled: props.disabled,
671
+ type: "button",
672
+ onClick: () => runFallbackCommand("formatBlock", "h2"),
673
+ }, [classIcon("heading"), h("span", "标题")]),
674
+ h("button", {
675
+ disabled: props.disabled,
676
+ type: "button",
677
+ onClick: () => runFallbackCommand("fontSize", "2"),
678
+ }, [classIcon("type"), h("span", "小字")]),
679
+ h("button", {
680
+ disabled: props.disabled,
681
+ type: "button",
682
+ onClick: () => runFallbackCommand("fontSize", "4"),
683
+ }, [classIcon("type"), h("span", "大字")]),
684
+ ]),
685
+ toolGroup("对齐", "alignLeft", [
686
+ h("button", {
687
+ disabled: props.disabled,
688
+ type: "button",
689
+ onClick: () => runFallbackCommand("justifyLeft"),
690
+ }, [classIcon("alignLeft"), h("span", "左对齐")]),
691
+ h("button", {
692
+ disabled: props.disabled,
693
+ type: "button",
694
+ onClick: () => runFallbackCommand("justifyCenter"),
695
+ }, [classIcon("alignCenter"), h("span", "居中")]),
696
+ h("button", {
697
+ disabled: props.disabled,
698
+ type: "button",
699
+ onClick: () => runFallbackCommand("justifyRight"),
700
+ }, [classIcon("alignRight"), h("span", "右对齐")]),
701
+ ]),
702
+ toolGroup("段落功能", "list", [
703
+ h("button", {
704
+ disabled: props.disabled,
705
+ type: "button",
706
+ onClick: () => runFallbackCommand("insertOrderedList"),
707
+ }, [classIcon("listOrdered"), h("span", "有序列表")]),
708
+ h("button", {
709
+ disabled: props.disabled,
710
+ type: "button",
711
+ onClick: () => runFallbackCommand("insertUnorderedList"),
712
+ }, [classIcon("list"), h("span", "无序列表")]),
713
+ h("button", {
714
+ disabled: props.disabled,
715
+ type: "button",
716
+ onClick: () => runFallbackCommand("formatBlock", "blockquote"),
717
+ }, [classIcon("quote"), h("span", "引用")]),
718
+ h("button", {
719
+ disabled: props.disabled,
720
+ type: "button",
721
+ onClick: () => runFallbackCommand("formatBlock", "pre"),
722
+ }, [classIcon("code"), h("span", "代码块")]),
723
+ ]),
724
+ toolGroup("插入", "image", [
725
+ h("button", {
726
+ disabled: props.disabled || uploading.value,
727
+ type: "button",
728
+ onClick: () => { var _a; return (_a = fileInput.value) === null || _a === void 0 ? void 0 : _a.click(); },
729
+ }, [
730
+ classIcon("uploadCloud"),
731
+ h("span", uploading.value ? "上传中" : "本地图片"),
732
+ ]),
733
+ h("button", {
734
+ disabled: props.disabled,
735
+ type: "button",
736
+ onClick: () => openFallbackUrlDialog("image"),
737
+ }, [classIcon("image"), h("span", "网络图片")]),
738
+ h("button", {
739
+ disabled: props.disabled,
740
+ type: "button",
741
+ onClick: () => openFallbackUrlDialog("video"),
742
+ }, [classIcon("video"), h("span", "视频链接")]),
743
+ h("button", {
744
+ disabled: props.disabled,
745
+ type: "button",
746
+ onClick: () => insertFallbackHtml(createRichEditorTableHtml()),
747
+ }, [classIcon("table"), h("span", "表格")]),
748
+ h("button", {
749
+ disabled: props.disabled,
750
+ type: "button",
751
+ onClick: () => openFallbackUrlDialog("link"),
752
+ }, [classIcon("link"), h("span", "链接")]),
753
+ ]),
754
+ toolTip("清除格式", h("button", {
755
+ "aria-label": "清除格式",
756
+ class: "cc-rich-editor__tool",
757
+ disabled: props.disabled,
758
+ type: "button",
759
+ onClick: () => runFallbackCommand("removeFormat"),
760
+ }, [classIcon("eraser")])),
761
+ toolTip("撤销", h("button", {
762
+ "aria-label": "撤销",
763
+ class: "cc-rich-editor__tool",
764
+ disabled: props.disabled,
765
+ type: "button",
766
+ onClick: () => runFallbackCommand("undo"),
767
+ }, [classIcon("undo")])),
768
+ toolTip("恢复撤销", h("button", {
769
+ "aria-label": "恢复撤销",
770
+ class: "cc-rich-editor__tool",
771
+ disabled: props.disabled,
772
+ type: "button",
773
+ onClick: () => runFallbackCommand("redo"),
774
+ }, [classIcon("redo")])),
775
+ h("input", {
776
+ accept: "image/jpeg,image/jpg,image/png,image/gif,image/webp",
777
+ hidden: true,
778
+ multiple: true,
779
+ ref: fileInput,
780
+ type: "file",
781
+ onChange: (event) => void handleFallbackUpload(event.currentTarget.files),
782
+ }),
783
+ ]);
784
+ return h("div", { class: rootClass }, [
785
+ h("div", { class: "cc-rich-editor__toolbar-row" }, [
786
+ toolbar,
787
+ h("div", { class: "cc-rich-editor__toolbar-actions" }, [
788
+ toolTip("删除选中", h("button", {
789
+ "aria-label": "删除选中",
790
+ class: "cc-rich-editor__source-toggle",
791
+ disabled: props.disabled,
792
+ type: "button",
793
+ onClick: deleteSelectedContent,
794
+ onMousedown: (event) => event.preventDefault(),
795
+ }, [classIcon("x")])),
796
+ toolTip(sourceMode.value ? "预览" : "源码", h("button", {
797
+ "aria-label": sourceMode.value ? "预览" : "源码",
798
+ class: "cc-rich-editor__source-toggle",
799
+ disabled: props.disabled,
800
+ type: "button",
801
+ onClick: () => {
802
+ sourceMode.value = !sourceMode.value;
803
+ },
804
+ }, [classIcon(sourceMode.value ? "image" : "fileCode")])),
805
+ toolTip("清空", h("button", {
806
+ "aria-label": "清空",
807
+ class: "cc-rich-editor__source-toggle",
808
+ disabled: props.disabled,
809
+ type: "button",
810
+ onClick: () => commitHtml(""),
811
+ }, [classIcon("trash")])),
812
+ ]),
813
+ ]),
814
+ notice.value
815
+ ? h("div", {
816
+ class: "cc-rich-editor__notice",
817
+ "data-type": notice.value.type,
818
+ role: "status",
819
+ }, notice.value.text)
820
+ : null,
821
+ h(ClassToastViewport, {
822
+ className: "cc-toast-viewport cc-rich-editor__toast-viewport",
823
+ manager: toastManager,
824
+ maxVisible: 3,
825
+ position: "top-right",
826
+ }),
827
+ urlDialog.value
828
+ ? h("div", {
829
+ "aria-modal": "true",
830
+ class: "cc-rich-editor__url-modal",
831
+ role: "dialog",
832
+ }, [
833
+ h("div", { class: "cc-rich-editor__url-panel" }, [
834
+ h("div", { class: "cc-rich-editor__url-header" }, [
835
+ h("span", { class: "cc-rich-editor__url-title" }, [
836
+ classIcon(urlDialog.value.icon),
837
+ urlDialog.value.title,
838
+ ]),
839
+ h("button", {
840
+ "aria-label": "关闭",
841
+ class: "cc-rich-editor__url-close",
842
+ type: "button",
843
+ onClick: closeFallbackUrlDialog,
844
+ }, [classIcon("x")]),
845
+ ]),
846
+ h("label", { class: "cc-rich-editor__url-field" }, [
847
+ h("span", locale.richEditorUrlFieldLabel),
848
+ h("input", {
849
+ ref: urlDialogInput,
850
+ placeholder: urlDialog.value.placeholder,
851
+ type: "url",
852
+ value: urlDialog.value.value,
853
+ onInput: (event) => {
854
+ if (!urlDialog.value)
855
+ return;
856
+ urlDialog.value = {
857
+ ...urlDialog.value,
858
+ value: event.currentTarget
859
+ .value,
860
+ };
861
+ },
862
+ onKeydown: (event) => {
863
+ if (event.key === "Enter")
864
+ submitFallbackUrlDialog();
865
+ if (event.key === "Escape")
866
+ closeFallbackUrlDialog();
867
+ },
868
+ }),
869
+ ]),
870
+ h("div", { class: "cc-rich-editor__url-actions" }, [
871
+ h("button", {
872
+ type: "button",
873
+ onClick: closeFallbackUrlDialog,
874
+ }, locale.richEditorCancelText),
875
+ h("button", {
876
+ type: "button",
877
+ onClick: submitFallbackUrlDialog,
878
+ }, locale.richEditorInsertText),
879
+ ]),
880
+ ]),
881
+ ])
882
+ : null,
883
+ sourceMode.value
884
+ ? h("textarea", {
885
+ class: "cc-rich-editor__source",
886
+ disabled: props.disabled,
887
+ onInput: (event) => commitHtml(event.target.value),
888
+ placeholder: props.placeholder,
889
+ style: { height: `${props.height}px` },
890
+ value: html.value,
891
+ })
892
+ : ((_c = wang.value) === null || _c === void 0 ? void 0 : _c.Editor)
893
+ ? h(wang.value.Editor, {
894
+ defaultConfig: editorConfig,
895
+ mode: "default",
896
+ onChange: (nextEditor) => commitHtml(nextEditor.getHtml()),
897
+ onCreated: (nextEditor) => {
898
+ var _a;
899
+ editor.value = nextEditor;
900
+ if (props.disabled)
901
+ (_a = nextEditor.disable) === null || _a === void 0 ? void 0 : _a.call(nextEditor);
902
+ },
903
+ "onUpdate:modelValue": (nextHtml) => commitHtml(nextHtml),
904
+ modelValue: html.value,
905
+ style: { height: `${props.height}px`, overflowY: "auto" },
906
+ })
907
+ : h("div", {
908
+ class: "cc-rich-editor__fallback-editor",
909
+ contenteditable: !props.disabled,
910
+ "data-placeholder": props.placeholder,
911
+ onBlur: (event) => commitHtml(event.currentTarget.innerHTML),
912
+ onKeyup: saveFallbackSelection,
913
+ onMouseup: saveFallbackSelection,
914
+ onDragover: (event) => {
915
+ var _a;
916
+ if (props.disabled ||
917
+ getRichEditorImageFiles((_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.files)
918
+ .length === 0)
919
+ return;
920
+ event.preventDefault();
921
+ },
922
+ onDrop: (event) => {
923
+ var _a;
924
+ const files = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.files;
925
+ if (props.disabled ||
926
+ getRichEditorImageFiles(files).length === 0)
927
+ return;
928
+ event.preventDefault();
929
+ void handleFallbackUpload(files !== null && files !== void 0 ? files : null);
930
+ },
931
+ onInput: (event) => commitHtml(event.currentTarget.innerHTML),
932
+ onPaste: (event) => {
933
+ var _a, _b, _c, _d;
934
+ const imageFiles = getRichEditorImageFiles((_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.files);
935
+ if (imageFiles.length > 0) {
936
+ event.preventDefault();
937
+ void handleFallbackUpload((_c = (_b = event.clipboardData) === null || _b === void 0 ? void 0 : _b.files) !== null && _c !== void 0 ? _c : null);
938
+ return;
939
+ }
940
+ const pastedHtml = (_d = event.clipboardData) === null || _d === void 0 ? void 0 : _d.getData("text/html");
941
+ if (!pastedHtml)
942
+ return;
943
+ event.preventDefault();
944
+ document.execCommand("insertHTML", false, controller.sanitize(pastedHtml));
945
+ if (fallbackEditor.value)
946
+ commitHtml(fallbackEditor.value.innerHTML);
947
+ },
948
+ ref: fallbackEditor,
949
+ role: "textbox",
950
+ style: { minHeight: `${props.height}px` },
951
+ }),
952
+ ]);
953
+ };
954
+ },
955
+ });
956
+ const ClassTooltip = /*#__PURE__*/ defineComponent({
957
+ name: "ClassTooltip",
958
+ inheritAttrs: false,
959
+ props: {
960
+ content: {
961
+ type: String,
962
+ required: true,
963
+ },
964
+ animation: {
965
+ type: [Object, Boolean],
966
+ default: undefined,
967
+ },
968
+ placement: {
969
+ type: String,
970
+ default: "top",
971
+ },
972
+ trigger: {
973
+ type: String,
974
+ default: "hover",
975
+ },
976
+ autoAdjust: {
977
+ type: Boolean,
978
+ default: true,
979
+ },
980
+ closeOnEsc: {
981
+ type: Boolean,
982
+ default: true,
983
+ },
984
+ closeOnOutsideClick: {
985
+ type: Boolean,
986
+ default: true,
987
+ },
988
+ portal: {
989
+ type: Boolean,
990
+ default: true,
991
+ },
992
+ className: String,
993
+ },
994
+ setup(props, { attrs, slots }) {
995
+ const rootRef = ref(null);
996
+ const contentRef = ref(null);
997
+ const contentId = `cc-tooltip-${++tooltipIdSeed}`;
998
+ const controller = new TooltipController();
999
+ const open = ref(controller.isOpen());
1000
+ const safePlacement = ref(props.placement);
1001
+ const anchorStyle = ref({
1002
+ height: 0,
1003
+ left: -9999,
1004
+ top: -9999,
1005
+ width: 0,
1006
+ });
1007
+ const updatePlacement = () => {
1008
+ if (rootRef.value) {
1009
+ const rect = rootRef.value.getBoundingClientRect();
1010
+ anchorStyle.value = {
1011
+ height: rect.height,
1012
+ left: rect.left,
1013
+ top: rect.top,
1014
+ width: rect.width,
1015
+ };
1016
+ }
1017
+ if (!props.autoAdjust || !rootRef.value || !contentRef.value) {
1018
+ safePlacement.value = props.placement;
1019
+ return;
1020
+ }
1021
+ safePlacement.value = getSafeTooltipPlacement(rootRef.value.getBoundingClientRect(), contentRef.value.getBoundingClientRect(), props.placement);
1022
+ };
1023
+ watch(open, (nextOpen) => {
1024
+ if (nextOpen)
1025
+ requestAnimationFrame(updatePlacement);
1026
+ });
1027
+ watch(open, (nextOpen, _previous, onCleanup) => {
1028
+ if (!nextOpen ||
1029
+ props.trigger !== "click" ||
1030
+ typeof document === "undefined")
1031
+ return;
1032
+ const handlePointerDown = (event) => {
1033
+ var _a, _b;
1034
+ if (!props.closeOnOutsideClick ||
1035
+ ((_a = rootRef.value) === null || _a === void 0 ? void 0 : _a.contains(event.target)) ||
1036
+ ((_b = contentRef.value) === null || _b === void 0 ? void 0 : _b.contains(event.target)))
1037
+ return;
1038
+ controller.close();
1039
+ };
1040
+ const handleKeydown = (event) => {
1041
+ if (!props.closeOnEsc || event.key !== "Escape")
1042
+ return;
1043
+ event.preventDefault();
1044
+ controller.close();
1045
+ };
1046
+ document.addEventListener("pointerdown", handlePointerDown, true);
1047
+ document.addEventListener("keydown", handleKeydown, true);
1048
+ onCleanup(() => {
1049
+ document.removeEventListener("pointerdown", handlePointerDown, true);
1050
+ document.removeEventListener("keydown", handleKeydown, true);
1051
+ });
1052
+ });
1053
+ const unsubscribe = controller.subscribe((state) => {
1054
+ open.value = state.open;
1055
+ });
1056
+ onBeforeUnmount(() => {
1057
+ unsubscribe();
1058
+ controller.destroy();
1059
+ });
1060
+ watch(() => props.placement, () => updatePlacement());
1061
+ return () => {
1062
+ var _a;
1063
+ const openEvents = props.trigger === "click"
1064
+ ? {
1065
+ onClick: () => {
1066
+ controller.toggle();
1067
+ },
1068
+ }
1069
+ : {
1070
+ onBlur: () => {
1071
+ controller.close();
1072
+ },
1073
+ onFocus: () => {
1074
+ controller.open();
1075
+ },
1076
+ onMouseenter: () => {
1077
+ controller.open();
1078
+ },
1079
+ onMouseleave: () => {
1080
+ controller.close();
1081
+ },
1082
+ };
1083
+ const motion = resolveAnimation(props.animation, "fade");
1084
+ const tooltipClass = [
1085
+ "cc-tooltip",
1086
+ `cc-tooltip--${safePlacement.value}`,
1087
+ props.className,
1088
+ ];
1089
+ const tooltipContent = h("span", {
1090
+ class: "cc-tooltip__content",
1091
+ id: contentId,
1092
+ ref: contentRef,
1093
+ role: "tooltip",
1094
+ }, props.content);
1095
+ const rootNode = h("span", {
1096
+ ...attrs,
1097
+ ...openEvents,
1098
+ "aria-describedby": open.value ? contentId : undefined,
1099
+ class: tooltipClass,
1100
+ "data-animation": motion.name,
1101
+ "data-open": open.value,
1102
+ ref: rootRef,
1103
+ style: animationStyle(motion),
1104
+ tabindex: props.trigger === "click" ? 0 : undefined,
1105
+ }, [(_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots), props.portal ? null : tooltipContent]);
1106
+ if (!props.portal)
1107
+ return rootNode;
1108
+ const portalNode = open.value || anchorStyle.value.left > -9999
1109
+ ? h("span", {
1110
+ class: [...tooltipClass, "cc-tooltip--portal"],
1111
+ "data-animation": motion.name,
1112
+ "data-open": open.value,
1113
+ style: {
1114
+ ...animationStyle(motion),
1115
+ height: `${anchorStyle.value.height}px`,
1116
+ left: `${anchorStyle.value.left}px`,
1117
+ top: `${anchorStyle.value.top}px`,
1118
+ width: `${anchorStyle.value.width}px`,
1119
+ },
1120
+ }, [tooltipContent])
1121
+ : null;
1122
+ return [
1123
+ rootNode,
1124
+ portalNode ? h(Teleport, { to: "body" }, portalNode) : null,
1125
+ ];
1126
+ };
1127
+ },
1128
+ });
1129
+ const ClassToastViewport = /*#__PURE__*/ defineComponent({
1130
+ name: "ClassToastViewport",
1131
+ inheritAttrs: false,
1132
+ props: {
1133
+ animation: {
1134
+ type: [Object, Boolean],
1135
+ default: undefined,
1136
+ },
1137
+ manager: Object,
1138
+ maxVisible: {
1139
+ type: Number,
1140
+ default: undefined,
1141
+ },
1142
+ position: {
1143
+ type: String,
1144
+ default: "top-right",
1145
+ },
1146
+ className: {
1147
+ type: String,
1148
+ default: "cc-toast-viewport",
1149
+ },
1150
+ },
1151
+ setup(props, { attrs, slots }) {
1152
+ var _a;
1153
+ const activeManager = shallowRef((_a = props.manager) !== null && _a !== void 0 ? _a : defaultToastManager);
1154
+ const items = shallowRef(activeManager.value.getToasts());
1155
+ const getVisibleItems = (source) => {
1156
+ const positionItems = source.filter((item) => item.position === props.position);
1157
+ const visible = positionItems.slice(Math.max(0, positionItems.length - normalizeToastMaxVisible(props.maxVisible)));
1158
+ return isToastTopPosition(props.position)
1159
+ ? [...visible].reverse()
1160
+ : visible;
1161
+ };
1162
+ const renderedItems = shallowRef(getVisibleItems(items.value).map((item) => ({
1163
+ item,
1164
+ motion: false,
1165
+ state: "enter",
1166
+ })));
1167
+ const toastNodes = new Map();
1168
+ let rects = new Map();
1169
+ let timer;
1170
+ let frame = 0;
1171
+ let flipFrame = 0;
1172
+ const setToastNode = (id, node) => {
1173
+ if (node instanceof HTMLElement)
1174
+ toastNodes.set(id, node);
1175
+ else
1176
+ toastNodes.delete(id);
1177
+ };
1178
+ const runFlip = async (motion) => {
1179
+ if (flipFrame)
1180
+ cancelAnimationFrame(flipFrame);
1181
+ await nextTick();
1182
+ const previousRects = rects;
1183
+ const nextRects = new Map();
1184
+ const activeIds = new Set(renderedItems.value
1185
+ .filter((entry) => entry.motion && entry.state !== "exit")
1186
+ .map(({ item }) => item.id));
1187
+ toastNodes.forEach((node, id) => {
1188
+ if (!activeIds.has(id))
1189
+ return;
1190
+ const rect = node.getBoundingClientRect();
1191
+ nextRects.set(id, rect);
1192
+ const previous = previousRects.get(id);
1193
+ if (!previous)
1194
+ return;
1195
+ const deltaY = previous.top - rect.top;
1196
+ if (Math.abs(deltaY) < 1)
1197
+ return;
1198
+ node.style.transition = "none";
1199
+ node.style.setProperty("--cc-toast-stack-offset", `${deltaY}px`);
1200
+ node.style.willChange = "transform, opacity";
1201
+ });
1202
+ flipFrame = requestAnimationFrame(() => {
1203
+ toastNodes.forEach((node, id) => {
1204
+ if (!nextRects.has(id))
1205
+ return;
1206
+ node.style.transition = `transform ${motion.duration}ms ${motion.easing}, opacity ${motion.duration}ms ${motion.easing}, margin ${motion.duration}ms ${motion.easing}`;
1207
+ node.style.removeProperty("--cc-toast-stack-offset");
1208
+ window.setTimeout(() => {
1209
+ node.style.transition = "";
1210
+ node.style.willChange = "";
1211
+ }, motion.duration);
1212
+ });
1213
+ flipFrame = 0;
1214
+ });
1215
+ rects = nextRects;
1216
+ };
1217
+ const syncRenderedItems = (nextItems) => {
1218
+ if (frame)
1219
+ cancelAnimationFrame(frame);
1220
+ const motion = resolveAnimation(props.animation, "slide");
1221
+ const currentIds = new Set(renderedItems.value.map(({ item }) => item.id));
1222
+ const incomingIds = new Set(nextItems.map((item) => item.id));
1223
+ const incomingById = new Map(nextItems.map((item) => [item.id, item]));
1224
+ const enteringIds = nextItems
1225
+ .filter((item) => !currentIds.has(item.id))
1226
+ .map((item) => item.id);
1227
+ const retainedOrExiting = renderedItems.value.map(({ item }) => {
1228
+ var _a;
1229
+ return ({
1230
+ item: (_a = incomingById.get(item.id)) !== null && _a !== void 0 ? _a : item,
1231
+ motion: !incomingIds.has(item.id),
1232
+ state: incomingIds.has(item.id)
1233
+ ? "enter"
1234
+ : "exit",
1235
+ });
1236
+ });
1237
+ const entering = nextItems
1238
+ .filter((item) => !currentIds.has(item.id))
1239
+ .map((item) => ({ item, motion: true, state: "prepare" }));
1240
+ renderedItems.value = [...retainedOrExiting, ...entering];
1241
+ void runFlip(motion);
1242
+ if (enteringIds.length) {
1243
+ frame = requestAnimationFrame(() => {
1244
+ renderedItems.value = renderedItems.value.map((entry) => enteringIds.includes(entry.item.id)
1245
+ ? { ...entry, state: "enter" }
1246
+ : entry);
1247
+ });
1248
+ const clearMotion = () => {
1249
+ renderedItems.value = renderedItems.value.map((entry) => enteringIds.includes(entry.item.id) && entry.state === "enter"
1250
+ ? { ...entry, motion: false }
1251
+ : entry);
1252
+ };
1253
+ if (!motion.enabled || motion.duration <= 0)
1254
+ clearMotion();
1255
+ else
1256
+ setTimeout(clearMotion, motion.duration);
1257
+ }
1258
+ if (!retainedOrExiting.some((entry) => entry.state === "exit"))
1259
+ return;
1260
+ if (timer)
1261
+ clearTimeout(timer);
1262
+ if (!motion.enabled || motion.duration <= 0) {
1263
+ renderedItems.value = renderedItems.value.filter((entry) => entry.state !== "exit");
1264
+ return;
1265
+ }
1266
+ timer = setTimeout(() => {
1267
+ renderedItems.value = renderedItems.value.filter((entry) => entry.state !== "exit");
1268
+ }, motion.duration);
1269
+ };
1270
+ let unsubscribe = () => { };
1271
+ const subscribeManager = (nextManager) => {
1272
+ unsubscribe();
1273
+ activeManager.value = nextManager;
1274
+ items.value = nextManager.getToasts();
1275
+ syncRenderedItems(getVisibleItems(items.value));
1276
+ unsubscribe = nextManager.subscribe((nextItems) => {
1277
+ items.value = nextItems;
1278
+ syncRenderedItems(getVisibleItems(nextItems));
1279
+ });
1280
+ };
1281
+ subscribeManager(activeManager.value);
1282
+ watch(() => props.manager, (nextManager) => {
1283
+ subscribeManager(nextManager !== null && nextManager !== void 0 ? nextManager : defaultToastManager);
1284
+ });
1285
+ watch(() => [props.position, props.maxVisible], () => syncRenderedItems(getVisibleItems(items.value)));
1286
+ onBeforeUnmount(() => {
1287
+ if (timer)
1288
+ clearTimeout(timer);
1289
+ if (frame)
1290
+ cancelAnimationFrame(frame);
1291
+ if (flipFrame)
1292
+ cancelAnimationFrame(flipFrame);
1293
+ unsubscribe();
1294
+ });
1295
+ return () => {
1296
+ const motion = resolveAnimation(props.animation, "slide");
1297
+ const viewportNode = h("div", {
1298
+ ...attrs,
1299
+ "aria-live": "polite",
1300
+ class: [props.className, `cc-toast-viewport--${props.position}`],
1301
+ role: "status",
1302
+ style: animationStyle(motion),
1303
+ }, renderedItems.value.map(({ item, motion: isMotionActive, state }, index) => slots.default
1304
+ ? slots.default({
1305
+ item,
1306
+ dismiss: () => activeManager.value.dismiss(item.id),
1307
+ state,
1308
+ })
1309
+ : h("article", {
1310
+ class: `cc-toast cc-toast--${item.tone}`,
1311
+ "data-animation": motion.name,
1312
+ "data-motion": isMotionActive ? "true" : "false",
1313
+ "data-state": state,
1314
+ key: item.id,
1315
+ style: {
1316
+ "--cc-toast-stack-index": index,
1317
+ },
1318
+ ref: (node) => {
1319
+ setToastNode(item.id, node instanceof Element ? node : null);
1320
+ },
1321
+ }, [
1322
+ item.title
1323
+ ? h("strong", { class: "cc-toast__title" }, item.title)
1324
+ : null,
1325
+ h("span", { class: "cc-toast__message" }, item.message),
1326
+ h("button", {
1327
+ "aria-label": "Dismiss toast",
1328
+ class: "cc-toast__close",
1329
+ type: "button",
1330
+ onClick: () => activeManager.value.dismiss(item.id),
1331
+ }, classIcon("x")),
1332
+ ])));
1333
+ return h(Teleport, { to: "body" }, viewportNode);
1334
+ };
1335
+ },
1336
+ });
1337
+
1338
+ export { ClassRichEditor };
1339
+ //# sourceMappingURL=rich-editor.js.map