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