oxy-uni-ui 1.2.0 → 2.0.0

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 (306) hide show
  1. package/attributes.json +1 -1
  2. package/components/common/abstracts/variable.scss +396 -321
  3. package/components/common/path.ts +9 -0
  4. package/components/common/util.ts +200 -5
  5. package/components/composables/index.ts +1 -0
  6. package/components/composables/useGlobalLoading.ts +42 -0
  7. package/components/composables/useGlobalMessage.ts +48 -0
  8. package/components/composables/useGlobalToast.ts +84 -0
  9. package/components/composables/usePopover.ts +24 -20
  10. package/components/composables/useVirtualScroll.ts +13 -11
  11. package/components/composables/useWindowResize.ts +35 -0
  12. package/components/oxy-action-sheet/index.scss +24 -11
  13. package/components/oxy-action-sheet/oxy-action-sheet.vue +27 -19
  14. package/components/oxy-action-sheet/types.ts +7 -0
  15. package/components/oxy-backtop/index.scss +3 -3
  16. package/components/oxy-backtop/oxy-backtop.vue +9 -6
  17. package/components/oxy-backtop/types.ts +7 -7
  18. package/components/oxy-badge/index.scss +4 -4
  19. package/components/oxy-badge/oxy-badge.vue +3 -3
  20. package/components/oxy-badge/types.ts +2 -2
  21. package/components/oxy-button/index.scss +5 -5
  22. package/components/oxy-button/oxy-button.vue +5 -1
  23. package/components/oxy-calendar/index.scss +11 -11
  24. package/components/oxy-calendar/oxy-calendar.vue +1 -0
  25. package/components/oxy-calendar/types.ts +5 -0
  26. package/components/oxy-calendar-view/month/index.scss +4 -4
  27. package/components/oxy-calendar-view/month/types.ts +36 -0
  28. package/components/oxy-calendar-view/monthPanel/index.scss +7 -7
  29. package/components/oxy-calendar-view/monthPanel/month-panel.vue +14 -8
  30. package/components/oxy-calendar-view/year/index.scss +4 -4
  31. package/components/oxy-calendar-view/yearPanel/index.scss +4 -4
  32. package/components/oxy-calendar-view/yearPanel/year-panel.vue +21 -5
  33. package/components/oxy-card/index.scss +2 -2
  34. package/components/oxy-cell/index.scss +8 -8
  35. package/components/oxy-cell/oxy-cell.vue +15 -2
  36. package/components/oxy-cell/types.ts +4 -0
  37. package/components/oxy-checkbox/index.scss +8 -8
  38. package/components/oxy-checkbox/oxy-checkbox.vue +2 -2
  39. package/components/oxy-checkbox-group/index.scss +2 -2
  40. package/components/oxy-circle/oxy-circle.vue +10 -7
  41. package/components/oxy-circle/types.ts +5 -5
  42. package/components/oxy-col/oxy-col.vue +2 -2
  43. package/components/oxy-col-picker/index.scss +4 -4
  44. package/components/oxy-col-picker/oxy-col-picker.vue +9 -5
  45. package/components/oxy-col-picker/types.ts +12 -3
  46. package/components/oxy-collapse/index.scss +2 -2
  47. package/components/oxy-collapse-item/oxy-collapse-item.vue +3 -3
  48. package/components/oxy-corner/index.scss +32 -32
  49. package/components/oxy-corner/oxy-corner.vue +15 -3
  50. package/components/oxy-corner/types.ts +15 -1
  51. package/components/oxy-count-to/oxy-count-to.vue +3 -3
  52. package/components/oxy-curtain/index.scss +15 -15
  53. package/components/oxy-curtain/oxy-curtain.vue +4 -2
  54. package/components/oxy-curtain/types.ts +6 -1
  55. package/components/oxy-date-strip/index.scss +10 -0
  56. package/components/oxy-date-strip/oxy-date-strip.vue +198 -0
  57. package/components/oxy-date-strip/types.ts +98 -0
  58. package/components/oxy-date-strip/utils.ts +67 -0
  59. package/components/oxy-date-strip-item/index.scss +94 -0
  60. package/components/oxy-date-strip-item/oxy-date-strip-item.vue +102 -0
  61. package/components/oxy-date-strip-item/types.ts +53 -0
  62. package/components/oxy-datetime-picker/index.scss +11 -11
  63. package/components/oxy-datetime-picker/oxy-datetime-picker.vue +4 -1
  64. package/components/oxy-datetime-picker/types.ts +10 -1
  65. package/components/oxy-drop-menu/index.scss +3 -3
  66. package/components/oxy-drop-menu/oxy-drop-menu.vue +3 -3
  67. package/components/oxy-drop-menu-item/index.scss +1 -1
  68. package/components/oxy-drop-menu-item/oxy-drop-menu-item.vue +4 -3
  69. package/components/oxy-drop-menu-item/types.ts +5 -0
  70. package/components/oxy-echarts/index.scss +17 -0
  71. package/components/oxy-echarts/index.ts +1 -0
  72. package/components/oxy-echarts/oxy-echarts.vue +32 -0
  73. package/components/oxy-echarts/types.ts +18 -0
  74. package/components/oxy-fab/index.scss +8 -8
  75. package/components/oxy-fab/oxy-fab.vue +22 -3
  76. package/components/oxy-file-list/index.scss +42 -15
  77. package/components/oxy-file-list/oxy-file-list.vue +208 -34
  78. package/components/oxy-file-list/types.ts +58 -2
  79. package/components/oxy-floating-panel/oxy-floating-panel.vue +13 -9
  80. package/components/oxy-floating-panel/{type.ts → types.ts} +8 -8
  81. package/components/oxy-footer/index.scss +19 -0
  82. package/components/oxy-footer/oxy-footer.vue +78 -0
  83. package/components/oxy-footer/types.ts +17 -0
  84. package/components/oxy-form-item/types.ts +22 -1
  85. package/components/oxy-gap/oxy-gap.vue +2 -2
  86. package/components/oxy-gap/types.ts +2 -2
  87. package/components/oxy-global-loading/oxy-global-loading.vue +53 -0
  88. package/components/oxy-global-message/oxy-global-message.vue +64 -0
  89. package/components/oxy-global-toast/oxy-global-toast.vue +53 -0
  90. package/components/oxy-grid/oxy-grid.vue +1 -1
  91. package/components/oxy-grid/types.ts +1 -1
  92. package/components/oxy-grid-item/index.scss +1 -1
  93. package/components/oxy-grid-item/oxy-grid-item.vue +7 -5
  94. package/components/oxy-grid-item/types.ts +1 -1
  95. package/components/oxy-guidance/index.scss +75 -0
  96. package/components/oxy-guidance/oxy-guidance.vue +201 -0
  97. package/components/oxy-guidance/types.ts +33 -0
  98. package/components/oxy-icon/oxy-icon.vue +2 -2
  99. package/components/oxy-icon/types.ts +1 -1
  100. package/components/oxy-img/oxy-img.vue +4 -4
  101. package/components/oxy-img/types.ts +3 -3
  102. package/components/oxy-img-cropper/index.scss +12 -12
  103. package/components/oxy-img-cropper/oxy-img-cropper.vue +97 -52
  104. package/components/oxy-img-cropper/types.ts +2 -2
  105. package/components/oxy-img-lazy/index.scss +17 -0
  106. package/components/oxy-img-lazy/oxy-img-lazy.vue +332 -0
  107. package/components/oxy-img-lazy/types.ts +69 -0
  108. package/components/oxy-index-anchor/index.scss +2 -2
  109. package/components/oxy-index-anchor/oxy-index-anchor.vue +2 -2
  110. package/components/oxy-index-anchor/{type.ts → types.ts} +3 -0
  111. package/components/oxy-index-bar/index.scss +3 -3
  112. package/components/oxy-index-bar/oxy-index-bar.vue +3 -3
  113. package/components/oxy-index-bar/{type.ts → types.ts} +2 -2
  114. package/components/oxy-input/index.scss +1 -1
  115. package/components/oxy-input-number/index.scss +5 -5
  116. package/components/oxy-input-number/oxy-input-number.vue +2 -2
  117. package/components/oxy-input-number/types.ts +3 -2
  118. package/components/oxy-keyboard/index.scss +5 -5
  119. package/components/oxy-keyboard/key/index.scss +3 -3
  120. package/components/oxy-keyboard/key/index.vue +2 -2
  121. package/components/oxy-keyboard/key/types.ts +15 -0
  122. package/components/oxy-keyboard/oxy-keyboard.vue +1 -0
  123. package/components/oxy-keyboard/types.ts +5 -0
  124. package/components/oxy-link/index.scss +57 -0
  125. package/components/oxy-link/oxy-link.vue +130 -0
  126. package/components/oxy-link/types.ts +81 -0
  127. package/components/oxy-list/index.scss +7 -1
  128. package/components/oxy-list/oxy-list.vue +4 -3
  129. package/components/oxy-list/types.ts +1 -1
  130. package/components/oxy-loading/oxy-loading.vue +8 -4
  131. package/components/oxy-loading/types.ts +1 -1
  132. package/components/oxy-loadmore/index.scss +3 -3
  133. package/components/oxy-long-press-menu/index.scss +93 -0
  134. package/components/oxy-long-press-menu/oxy-long-press-menu.vue +338 -0
  135. package/components/oxy-long-press-menu/types.ts +34 -0
  136. package/components/oxy-message-box/index.scss +12 -11
  137. package/components/oxy-message-box/oxy-message-box.vue +11 -3
  138. package/components/oxy-message-box/types.ts +14 -0
  139. package/components/oxy-navbar/index.scss +2 -2
  140. package/components/oxy-navbar/oxy-navbar.vue +58 -13
  141. package/components/oxy-navbar/types.ts +8 -1
  142. package/components/oxy-navbar-capsule/types.ts +3 -0
  143. package/components/oxy-notice-bar/index.scss +3 -3
  144. package/components/oxy-notice-bar/oxy-notice-bar.vue +9 -5
  145. package/components/oxy-notice-bar/types.ts +3 -3
  146. package/components/oxy-notify/index.ts +1 -0
  147. package/components/oxy-notify/oxy-notify.vue +3 -2
  148. package/components/oxy-notify/types.ts +7 -0
  149. package/components/oxy-pagination/index.scss +1 -1
  150. package/components/oxy-password-input/oxy-password-input.vue +2 -2
  151. package/components/oxy-password-input/types.ts +1 -1
  152. package/components/oxy-picker/index.scss +45 -2
  153. package/components/oxy-picker/oxy-picker.vue +103 -14
  154. package/components/oxy-picker/types.ts +33 -1
  155. package/components/oxy-picker-view/index.scss +3 -3
  156. package/components/oxy-picker-view/oxy-picker-view.vue +4 -4
  157. package/components/oxy-popover/index.scss +9 -9
  158. package/components/oxy-popup/index.scss +2 -2
  159. package/components/oxy-popup/oxy-popup.vue +35 -2
  160. package/components/oxy-popup/types.ts +8 -1
  161. package/components/oxy-progress/index.scss +3 -3
  162. package/components/oxy-qrcode/draw.ts +398 -0
  163. package/components/oxy-qrcode/index.scss +2 -0
  164. package/components/oxy-qrcode/oxy-qrcode.vue +124 -0
  165. package/components/oxy-qrcode/qrcode.ts +936 -0
  166. package/components/oxy-qrcode/types.ts +42 -0
  167. package/components/oxy-radio/index.scss +13 -13
  168. package/components/oxy-radio/oxy-radio.vue +1 -1
  169. package/components/oxy-radio-group/index.scss +2 -2
  170. package/components/oxy-rate/types.ts +4 -4
  171. package/components/oxy-resize/index.scss +2 -2
  172. package/components/oxy-resize/oxy-resize.vue +4 -4
  173. package/components/oxy-resize/types.ts +3 -0
  174. package/components/oxy-rich-text/icon/emjio.svg +1 -0
  175. package/components/oxy-rich-text/icon/quote.svg +1 -0
  176. package/components/oxy-rich-text/icon/text.svg +1 -0
  177. package/components/oxy-rich-text/icon/title.svg +1 -0
  178. package/components/oxy-rich-text/index.scss +160 -0
  179. package/components/oxy-rich-text/mp-html/card/card.vue +122 -0
  180. package/components/oxy-rich-text/mp-html/card/index.js +7 -0
  181. package/components/oxy-rich-text/mp-html/editable/config.js +15 -0
  182. package/components/oxy-rich-text/mp-html/editable/index.js +553 -0
  183. package/components/oxy-rich-text/mp-html/emoji/index.js +203 -0
  184. package/components/oxy-rich-text/mp-html/highlight/config.js +5 -0
  185. package/components/oxy-rich-text/mp-html/highlight/index.js +96 -0
  186. package/components/oxy-rich-text/mp-html/highlight/prism.css +1 -0
  187. package/components/oxy-rich-text/mp-html/highlight/prism.min.js +7 -0
  188. package/components/oxy-rich-text/mp-html/img-cache/index.js +138 -0
  189. package/components/oxy-rich-text/mp-html/latex/index.js +80 -0
  190. package/components/oxy-rich-text/mp-html/latex/katex.css +1 -0
  191. package/components/oxy-rich-text/mp-html/latex/katex.min.js +1 -0
  192. package/components/oxy-rich-text/mp-html/markdown/index.js +50 -0
  193. package/components/oxy-rich-text/mp-html/markdown/marked.min.js +71 -0
  194. package/components/oxy-rich-text/mp-html/mp-html.d.ts +184 -0
  195. package/components/oxy-rich-text/mp-html/mp-html.vue +684 -0
  196. package/components/oxy-rich-text/mp-html/node/node.vue +1172 -0
  197. package/components/oxy-rich-text/mp-html/parser.js +1428 -0
  198. package/components/oxy-rich-text/mp-html/search/index.js +132 -0
  199. package/components/oxy-rich-text/mp-html/style/index.js +129 -0
  200. package/components/oxy-rich-text/mp-html/style/parser.js +175 -0
  201. package/components/oxy-rich-text/mp-html/template/index.js +67 -0
  202. package/components/oxy-rich-text/mp-html/txv-video/index.js +46 -0
  203. package/components/oxy-rich-text/oxy-rich-text.vue +642 -0
  204. package/components/oxy-rich-text/types.ts +76 -0
  205. package/components/oxy-row/oxy-row.vue +3 -3
  206. package/components/oxy-row/types.ts +1 -1
  207. package/components/oxy-search/index.scss +3 -3
  208. package/components/oxy-segmented/index.scss +16 -16
  209. package/components/oxy-segmented/oxy-segmented.vue +23 -3
  210. package/components/oxy-select/index.scss +331 -0
  211. package/components/oxy-select/oxy-select.vue +456 -0
  212. package/components/oxy-select/types.ts +83 -0
  213. package/components/oxy-select-picker/index.scss +7 -7
  214. package/components/oxy-select-picker/oxy-select-picker.vue +4 -0
  215. package/components/oxy-select-picker/types.ts +7 -1
  216. package/components/oxy-sidebar-item/index.scss +1 -1
  217. package/components/oxy-signature/oxy-signature.vue +18 -10
  218. package/components/oxy-signature/types.ts +106 -13
  219. package/components/oxy-skeleton/oxy-skeleton.vue +6 -6
  220. package/components/oxy-skeleton/types.ts +1 -1
  221. package/components/oxy-slider/index.scss +3 -3
  222. package/components/oxy-sort-button/index.scss +8 -8
  223. package/components/oxy-status-tip/index.scss +4 -4
  224. package/components/oxy-status-tip/oxy-status-tip.vue +5 -5
  225. package/components/oxy-status-tip/types.ts +3 -3
  226. package/components/oxy-step/index.scss +14 -14
  227. package/components/oxy-sticky/oxy-sticky.vue +6 -6
  228. package/components/oxy-stream-render/index.scss +6 -0
  229. package/components/oxy-stream-render/oxy-stream-render.vue +204 -0
  230. package/components/oxy-stream-render/types.ts +8 -0
  231. package/components/oxy-swipe-action/oxy-swipe-action.vue +27 -2
  232. package/components/oxy-swiper/oxy-swiper.vue +6 -6
  233. package/components/oxy-swiper/types.ts +5 -5
  234. package/components/oxy-switch/index.scss +8 -8
  235. package/components/oxy-switch/oxy-switch.vue +2 -2
  236. package/components/oxy-switch/types.ts +1 -1
  237. package/components/oxy-tab/index.scss +11 -1
  238. package/components/oxy-tabbar/index.scss +1 -1
  239. package/components/oxy-tabbar/oxy-tabbar.vue +39 -10
  240. package/components/oxy-table/index.scss +5 -5
  241. package/components/oxy-table/oxy-table.vue +8 -6
  242. package/components/oxy-table/types.ts +2 -2
  243. package/components/oxy-table-col/oxy-table-col.vue +3 -3
  244. package/components/oxy-table-col/types.ts +2 -2
  245. package/components/oxy-tabs/index.scss +43 -15
  246. package/components/oxy-tabs/oxy-tabs.vue +53 -19
  247. package/components/oxy-tabs/types.ts +15 -3
  248. package/components/oxy-tag/index.scss +15 -15
  249. package/components/oxy-text/index.scss +5 -1
  250. package/components/oxy-text/oxy-text.vue +76 -7
  251. package/components/oxy-text/types.ts +12 -0
  252. package/components/oxy-textarea/index.scss +6 -6
  253. package/components/oxy-toast/oxy-toast.vue +24 -8
  254. package/components/oxy-tooltip/index.scss +9 -9
  255. package/components/oxy-tree/index.scss +61 -9
  256. package/components/oxy-tree/oxy-tree.vue +102 -17
  257. package/components/oxy-tree/types.ts +23 -10
  258. package/components/oxy-upload/index.scss +21 -21
  259. package/components/oxy-upload/types.ts +2 -2
  260. package/components/oxy-verification-code/index.scss +6 -0
  261. package/components/oxy-verification-code/oxy-verification-code.vue +187 -0
  262. package/components/oxy-verification-code/types.ts +82 -0
  263. package/components/oxy-video-preview/index.scss +4 -4
  264. package/components/oxy-virtual-scroll/index.scss +4 -4
  265. package/components/oxy-virtual-scroll/oxy-virtual-scroll.vue +11 -7
  266. package/components/oxy-virtual-scroll/types.ts +14 -14
  267. package/components/oxy-voice-player/index.scss +908 -0
  268. package/components/oxy-voice-player/oxy-voice-player.vue +821 -0
  269. package/components/oxy-voice-player/types.ts +567 -0
  270. package/components/oxy-waterfall/index.scss +18 -0
  271. package/components/oxy-waterfall/oxy-waterfall.vue +218 -0
  272. package/components/oxy-waterfall/types.ts +90 -0
  273. package/components/oxy-waterfall-item/index.scss +8 -0
  274. package/components/oxy-waterfall-item/oxy-waterfall-item.vue +89 -0
  275. package/components/oxy-waterfall-item/types.ts +16 -0
  276. package/components/oxy-watermark/oxy-watermark.vue +35 -13
  277. package/components/oxy-watermark/types.ts +14 -14
  278. package/global.d.ts +9 -0
  279. package/index.ts +3 -0
  280. package/locale/lang/ar-SA.ts +3 -0
  281. package/locale/lang/en-US.ts +29 -0
  282. package/locale/lang/zh-CN.ts +29 -0
  283. package/package.json +97 -1
  284. package/tags.json +1 -1
  285. package/uni-echarts/changelog.md +2 -0
  286. package/uni-echarts/components/index.js +1 -0
  287. package/uni-echarts/components/uni-echarts/events.js +95 -0
  288. package/uni-echarts/components/uni-echarts/types.d.ts +183 -0
  289. package/uni-echarts/components/uni-echarts/types.js +1 -0
  290. package/uni-echarts/components/uni-echarts/uni-echarts.vue +530 -0
  291. package/uni-echarts/components/uni-echarts/uni-echarts.vue.d.ts +19 -0
  292. package/uni-echarts/global.d.ts +7 -0
  293. package/uni-echarts/index.d.ts +440 -0
  294. package/uni-echarts/index.js +2 -0
  295. package/uni-echarts/package.json +105 -0
  296. package/uni-echarts/shared-core.d.ts +269 -0
  297. package/uni-echarts/shared-core.js +900 -0
  298. package/web-types.json +1 -1
  299. package/components/oxy-number-keyboard/index.scss +0 -78
  300. package/components/oxy-number-keyboard/key/index.scss +0 -81
  301. package/components/oxy-number-keyboard/key/index.vue +0 -78
  302. package/components/oxy-number-keyboard/key/types.ts +0 -11
  303. package/components/oxy-number-keyboard/oxy-number-keyboard.vue +0 -151
  304. package/components/oxy-number-keyboard/types.ts +0 -83
  305. package/components/oxy-tree/components/tree-node-content.vue +0 -72
  306. package/components/oxy-tree/index.ts +0 -51
@@ -0,0 +1,642 @@
1
+ <template>
2
+ <view class="oxy-rich-text" :style="customStyle" :class="{ editable }">
3
+ <view v-if="editable" class="editor_toolbox">
4
+ <template v-for="(button, index) in toolButtons" :key="index">
5
+ <image width="32rpx" height="32rpx" v-if="button.icon" :src="button.icon" alt="" @click="button.tap()" />
6
+ <oxy-icon v-else size="18" :name="button.name" :class="button.class" @click="button.tap()" />
7
+ </template>
8
+ </view>
9
+ <view class="rich-text-main">
10
+ <mp-html
11
+ ref="articleRef"
12
+ v-bind="$attrs"
13
+ class="oxy-rich-text__html"
14
+ :key="mpkey"
15
+ :editable="editable"
16
+ :tag-style="tagStyle"
17
+ :markdown="true"
18
+ :content="contentAi"
19
+ @remove="remove"
20
+ ></mp-html>
21
+ </view>
22
+
23
+ <oxy-popup v-model="dialog" position="bottom" :max-width="popupMaxWidth" closable @close="dialog = false">
24
+ <view class="oxy-rich-text__popup">
25
+ <view class="dialog-title">{{ translate('insert' + (dialogType === 'emoji' ? 'Emoji' : 'Template')) }}</view>
26
+ <template v-if="dialogType === 'emoji'">
27
+ <view v-for="(line, index) in emojis" :key="index" class="oxy-rich-text__emoji-content">
28
+ <view class="oxy-rich-text__emoji-block" v-for="(item, index2) in line" :key="index2" @click="insertEmoji(item)">
29
+ {{ item }}
30
+ </view>
31
+ </view>
32
+ </template>
33
+ <template v-if="dialogType === 'template'">
34
+ <view v-for="(item, index) in templates" @click="closeDialog" :key="index">
35
+ <view @click="insertHtml(item)">
36
+ <rich-text :nodes="item" />
37
+ <view class="oxy-rich-text__popup-divider" />
38
+ </view>
39
+ </view>
40
+ </template>
41
+ </view>
42
+ </oxy-popup>
43
+ <oxy-popup v-model="linkDialog" position="bottom" :max-width="popupMaxWidth" closable @close="linkDialog = false">
44
+ <view class="oxy-rich-text__popup">
45
+ <view class="dialog-title">{{ translate('insertLink') }}</view>
46
+ <view class="oxy-rich-text__link-input">
47
+ <view class="oxy-rich-text__link-label">{{ translate('linkText') }}</view>
48
+ <oxy-input v-model="linkText" :placeholder="translate('linkTextPlaceholder')" />
49
+ </view>
50
+ <view class="oxy-rich-text__link-input">
51
+ <view class="oxy-rich-text__link-label">{{ translate('linkAddress') }}</view>
52
+ <oxy-input v-model="linkHref" :placeholder="translate('linkAddressPlaceholder')" />
53
+ </view>
54
+ <view class="oxy-rich-text__link-buttons">
55
+ <oxy-button type="default" @click="linkDialog = false">{{ translate('cancel') }}</oxy-button>
56
+ <oxy-button type="primary" @click="confirmInsertLink">{{ translate('confirm') }}</oxy-button>
57
+ </view>
58
+ </view>
59
+ </oxy-popup>
60
+ <oxy-action-sheet
61
+ v-model="actionSheetShow"
62
+ :actions="actions"
63
+ @close="mediaActionClose"
64
+ @select="actionSelected"
65
+ :cancel-text="translate('cancel')"
66
+ />
67
+ <oxy-message-box />
68
+ <oxy-message-box selector="oxy-message-box-table">
69
+ <oxy-input-number v-model="rows" />
70
+ {{ translate('row') }}
71
+ <oxy-input-number v-model="cols" />
72
+ {{ translate('column') }}
73
+ </oxy-message-box>
74
+ <oxy-toast />
75
+ </view>
76
+ </template>
77
+ <script lang="ts">
78
+ export default {
79
+ name: 'oxy-rich-mardown',
80
+ options: {
81
+ virtualHost: true,
82
+ addGlobalClass: true,
83
+ styleIsolation: 'shared'
84
+ }
85
+ }
86
+ </script>
87
+ <script lang="ts" setup>
88
+ import { ref, computed, watch, nextTick, onBeforeMount, onMounted } from 'vue'
89
+ import { uuid } from '../common/util'
90
+ import mpHtml from './mp-html/mp-html.vue'
91
+ import type { MpHtmlComponent } from './mp-html/mp-html.d.js'
92
+ import OxyIcon from '../oxy-icon/oxy-icon.vue'
93
+ import OxyInputNumber from '../oxy-input-number/oxy-input-number.vue'
94
+ import OxyInput from '../oxy-input/oxy-input.vue'
95
+ import OxyButton from '../oxy-button/oxy-button.vue'
96
+ import { useMessage } from '../../index'
97
+ import { useTranslate } from '../composables/useTranslate'
98
+ import { type ActionSheetInfo, type RemoveEvent, richTextProps, type ToolButton } from './types'
99
+ import emjio from './icon/emjio.svg'
100
+ import quote from './icon/quote.svg'
101
+ import text from './icon/text.svg'
102
+ import title from './icon/title.svg'
103
+
104
+ const props = defineProps(richTextProps)
105
+
106
+ const emit = defineEmits<{
107
+ save: [value: string]
108
+ clear: [void]
109
+ remove: [event: RemoveEvent]
110
+ }>()
111
+ const { translate } = useTranslate('richText')
112
+ const templates = [
113
+ '<section style="text-align: center; margin: 0 auto;"><section style="border-radius: 8rpx; border: 1px solid #757576; display: inline-block; padding: 10rpx 40rpx;"><span style="font-size: 36rpx; color: #595959;">标题</span></section></section>',
114
+ '<div style="width: 100%; box-sizing: border-box; border-radius: 10rpx; background-color: #f6f6f6; padding: 20rpx; margin: 20rpx 0"><div>卡片</div><div style="font-size: 24rpx; color: gray">正文</div></div>',
115
+ '<div style="border: 1px solid gray; box-shadow: 6rpx 6rpx 0 #cfcfce; padding: 20rpx; margin: 20rpx 0">段落</div>'
116
+ ]
117
+ const emojis = [
118
+ ['😄', '😷', '😂', '😝', '😳', '😱', '😔', '😒', '😉'],
119
+ ['😎', '😭', '😍', '😘', '🤔', '😕', '🙃', '🤑', '😲'],
120
+ ['🙄', '😤', '😴', '🤓', '😡', '😑', '😮', '🤒', '🤮']
121
+ ]
122
+ const message = useMessage()
123
+ const messageTable = useMessage('oxy-message-box-table')
124
+ const content = ref<string>('')
125
+ const mpkey = ref<string>(uuid())
126
+ const articleRef = ref<MpHtmlComponent | null>(null)
127
+ const dialog = ref<boolean>(false)
128
+ const dialogType = ref<string>('')
129
+ const linkDialog = ref<boolean>(false)
130
+ const linkText = ref<string>('')
131
+ const linkHref = ref<string>('')
132
+ const rows = ref<number>(1)
133
+ const cols = ref<number>(1)
134
+ const actionSheetShow = ref<boolean>(false)
135
+ const actions = ref([
136
+ {
137
+ name: translate('localSelect')
138
+ },
139
+ {
140
+ name: translate('remoteLink')
141
+ }
142
+ ])
143
+
144
+ const customTagStyle = {
145
+ p: `
146
+ font-size: 32rpx;
147
+ color: var(--oxy-rich-text-primary-color, #262626);
148
+ `,
149
+ h1: `
150
+ margin: 36rpx 0 20rpx 0;
151
+ font-size: 48rpx;
152
+ font-weight: 700;
153
+ color: var(--oxy-rich-text-title-color, #000);
154
+ `,
155
+ h2: `
156
+ margin: 28rpx 0 20rpx 0;
157
+ font-size: 40rpx;
158
+ font-weight: 600;
159
+ color: var(--oxy-rich-text-title-color, #000);
160
+ `,
161
+ h3: `
162
+ margin: 24rpx 0 16rpx 0;
163
+ font-size: 36rpx;
164
+ font-weight: 600;
165
+ color: var(--oxy-rich-text-title-color, #000);
166
+ `,
167
+ h4: `
168
+ margin: 24rpx 0 16rpx 0;
169
+ font-size: 32rpx;
170
+ font-weight: 600;
171
+ color: var(--oxy-rich-text-title-color, #000);
172
+ `,
173
+ h5: `
174
+ margin: 20rpx 0 16rpx 0;
175
+ font-size: 30rpx;
176
+ font-weight: 600;
177
+ color: var(--oxy-rich-text-title-color, #000);
178
+ `,
179
+ h6: `
180
+ margin: 16rpx 0;
181
+ font-size: 28rpx;
182
+ color: var(--oxy-rich-text-title-color, #000);
183
+ `,
184
+ blockquote: `
185
+ margin: 28rpx 0;
186
+ padding: 20rpx 24rpx;
187
+ color: var(--oxy-rich-text-blockquote-color, #555);
188
+ background: var(--oxy-rich-text-blockquote-bg, #f7f8fa);
189
+ border-left: 8rpx solid var(--oxy-rich-text-blockquote-border-color, #007AFF);
190
+ `,
191
+ 'blockquote>p': `
192
+ margin-block-start: 0;
193
+ margin-block-end: 0;
194
+ `,
195
+ ul: `
196
+ margin: 0 0 20rpx 0;
197
+ color: var(--oxy-rich-text-list-color, #444);
198
+ `,
199
+ li: `
200
+ margin: 12rpx 0;
201
+ line-height: 1.65;
202
+ color: var(--oxy-rich-text-list-color, #444);
203
+ `,
204
+ a: `
205
+ color: var(--oxy-rich-text-a-color, #007AFF);
206
+ text-decoration: underline;
207
+ `,
208
+ strong: `
209
+ font-weight: 700;
210
+ color: var(--oxy-rich-text-strong-color, #222);
211
+ `,
212
+ em: `
213
+ font-style: italic;
214
+ color: var(--oxy-rich-text-em-color, #222);
215
+ `,
216
+ hr: `
217
+ height: 1px;
218
+ padding: 0;
219
+ border: none;
220
+ background: var(--oxy-rich-text-hr-color, #e5e6eb);
221
+ margin: 36rpx 0;
222
+ `,
223
+ table: `
224
+ border-spacing: 0;
225
+ overflow: auto;
226
+ min-width: 100%;
227
+ margin: 24rpx 0;
228
+ border-collapse: collapse;
229
+ `,
230
+ th: `
231
+ border: 1px solid var(--oxy-rich-text-table-border-color, #e5e6eb);
232
+ background: var(--oxy-rich-text-table-head-bg, #f7f8fa);
233
+ color: var(--oxy-rich-text-table-head-color, #333);
234
+ padding: 16rpx 24rpx;
235
+ font-weight: 600;
236
+ `,
237
+ td: `
238
+ border: 1px solid var(--oxy-rich-text-table-border-color, #e5e6eb);
239
+ color: var(--oxy-rich-text-table-text-color, #444);
240
+ padding: 16rpx 24rpx;
241
+ `,
242
+ pre: `
243
+ border-radius: 12rpx;
244
+ white-space: pre;
245
+ background: var(--oxy-rich-text-code-bg, #2d2d2d);
246
+ color: var(--oxy-rich-text-code-color, #f8f8f2);
247
+ font-size: 26rpx;
248
+ line-height: 1.65;
249
+ padding: 24rpx;
250
+ overflow: auto;
251
+ position: relative;
252
+ `
253
+ }
254
+
255
+ const tagStyle = computed(() => {
256
+ // Merge customTagStyle with props.tagStyle, with props.tagStyle taking precedence
257
+ return {
258
+ ...customTagStyle,
259
+ ...props.tagStyle
260
+ }
261
+ })
262
+
263
+ const contentAi = computed<string>(() => {
264
+ if (!content.value) {
265
+ return ''
266
+ }
267
+ let htmlString = ''
268
+ const codeBlocks = content.value.match(/```[\s\S]*?```|```[\s\S]*?$/g) || []
269
+ const lastBlock = codeBlocks[codeBlocks.length - 1]
270
+ if (lastBlock && !lastBlock.endsWith('```')) {
271
+ htmlString = content.value + '\n'
272
+ } else {
273
+ htmlString = content.value
274
+ }
275
+ return htmlString
276
+ })
277
+
278
+ watch(
279
+ () => props.markdown,
280
+ (val) => {
281
+ nextTick(() => {
282
+ content.value = val
283
+ })
284
+ },
285
+ { immediate: true }
286
+ )
287
+ onBeforeMount(() => {
288
+ content.value = props.markdown
289
+ })
290
+ onMounted(() => {
291
+ if (articleRef.value) {
292
+ articleRef.value.getSrc = (type: string, value: any) => {
293
+ return new Promise((resolve, reject) => {
294
+ const titleMap: { img: string; video: string; audio: string; link: string; [key: string]: any } = {
295
+ img: translate('imageLink'),
296
+ video: translate('videoLink'),
297
+ audio: translate('audioLink'),
298
+ link: translate('linkAddress')
299
+ }
300
+ let title = titleMap[type] || translate('linkAddress')
301
+
302
+ const tapIndex = actionSheetInfo.value.index
303
+ if (type === 'img' || type === 'video') {
304
+ if (tapIndex === 0) {
305
+ // 本地选取
306
+ if (type === 'img') {
307
+ uni.chooseImage({
308
+ count: value === undefined ? 9 : 1, // 2.2.0 版本起插入图片时支持多张(修改图片链接时仅限一张)
309
+ success: (res) => {
310
+ // #ifdef MP-WEIXIN
311
+ if (res.tempFilePaths.length == 1 && wx.editImage) {
312
+ // 单张图片时进行编辑
313
+ wx.editImage({
314
+ src: res.tempFilePaths[0],
315
+ complete: (res2: any) => {
316
+ uni.showLoading({
317
+ title: translate('uploading')
318
+ })
319
+ upload(res2.tempFilePath || res.tempFilePaths[0], type).then((res) => {
320
+ uni.hideLoading()
321
+ resolve(res)
322
+ })
323
+ }
324
+ })
325
+ } else {
326
+ // #endif
327
+ uni.showLoading({
328
+ title: translate('uploading')
329
+ })
330
+ ;(async () => {
331
+ const arr = []
332
+ for (let item of res.tempFilePaths) {
333
+ // 依次上传
334
+ const src = await upload(item, type)
335
+ arr.push(src)
336
+ }
337
+ return arr
338
+ })().then((res) => {
339
+ uni.hideLoading()
340
+ resolve(res)
341
+ })
342
+ // #ifdef MP-WEIXIN
343
+ }
344
+ // #endif
345
+ },
346
+ fail: reject
347
+ })
348
+ } else {
349
+ uni.chooseVideo({
350
+ success: (res) => {
351
+ uni.showLoading({
352
+ title: translate('uploading')
353
+ })
354
+ upload(res.tempFilePath, type).then((res) => {
355
+ uni.hideLoading()
356
+ resolve(res)
357
+ })
358
+ },
359
+ fail: reject
360
+ })
361
+ }
362
+ } else {
363
+ message
364
+ .prompt({
365
+ title: title,
366
+ inputValue: value
367
+ })
368
+ .then((resp) => {
369
+ resolve(resp.value || '')
370
+ })
371
+ }
372
+ } else {
373
+ message
374
+ .prompt({
375
+ title: title,
376
+ inputValue: value
377
+ })
378
+ .then((resp) => {
379
+ resolve(resp.value || '')
380
+ })
381
+ }
382
+ })
383
+ }
384
+ }
385
+ })
386
+
387
+ // 上传图片方法
388
+ function upload(src: string, type: string): Promise<string> {
389
+ if (props.uploadMethod) {
390
+ return props.uploadMethod(src, type)
391
+ }
392
+ return Promise.resolve(src)
393
+ }
394
+
395
+ function remove(e: RemoveEvent): void {
396
+ emit('remove', e)
397
+ }
398
+
399
+ // 处理底部弹窗
400
+ function openDialog(btn: ToolButton): void {
401
+ dialog.value = true
402
+ dialogType.value = btn.method || ''
403
+ }
404
+
405
+ function closeDialog(): void {
406
+ dialog.value = false
407
+ }
408
+
409
+ const actionSheetInfo = ref<ActionSheetInfo>({ type: '' })
410
+
411
+ const openActionSheet = (type: string): void => {
412
+ actionSheetShow.value = true
413
+ actionSheetInfo.value = {
414
+ type: type
415
+ }
416
+ }
417
+
418
+ const actionSelected = ({ index }: { index: number }): void => {
419
+ const type = actionSheetInfo.value.type
420
+ actionSheetInfo.value.index = index
421
+
422
+ if (type === 'insertHtml') {
423
+ const tagName = ['h1', 'h3', 'h5'][index]
424
+ if (tagName && articleRef.value) {
425
+ articleRef.value.insertHtml(`<${tagName}>标题</${tagName}>`)
426
+ }
427
+ } else if (type === 'code') {
428
+ const lan = ['css', 'javascript', 'json'][index]
429
+ if (lan && articleRef.value) {
430
+ articleRef.value.insertHtml(`<pre><code class="language-${lan}">${lan} code</code></pre>`)
431
+ }
432
+ } else {
433
+ articleRef.value?.[type]()
434
+ }
435
+ }
436
+
437
+ const mediaActionClose = (): void => {
438
+ actionSheetInfo.value = { type: '' }
439
+ }
440
+
441
+ // 清空编辑器内容
442
+ const clear = (): void => {
443
+ message
444
+ .confirm({
445
+ msg: translate('clearConfirm'),
446
+ title: translate('confirm')
447
+ })
448
+ .then(() => {
449
+ articleRef.value?.clear()
450
+ content.value = ''
451
+ emit('clear')
452
+ })
453
+ }
454
+
455
+ // 保存编辑器内容
456
+ const save = (): void => {
457
+ setTimeout(() => {
458
+ if (props.editable && articleRef.value) {
459
+ const contentHtml = articleRef.value.getContent()
460
+ emit('save', contentHtml)
461
+ }
462
+ }, 50)
463
+ }
464
+
465
+ // 撤销操作
466
+ const undo = (): void => {
467
+ articleRef.value?.undo()
468
+ }
469
+
470
+ // 重做操作
471
+ const redo = (): void => {
472
+ articleRef.value?.redo()
473
+ }
474
+
475
+ // 插入图片
476
+ const insertImg = (): void => {
477
+ actions.value = [
478
+ {
479
+ name: translate('localSelect')
480
+ },
481
+ {
482
+ name: translate('remoteLink')
483
+ }
484
+ ]
485
+ openActionSheet('insertImg')
486
+ }
487
+
488
+ // 插入视频
489
+ const insertVideo = (): void => {
490
+ actions.value = [
491
+ {
492
+ name: translate('localSelect')
493
+ },
494
+ {
495
+ name: translate('remoteLink')
496
+ }
497
+ ]
498
+ openActionSheet('insertVideo')
499
+ }
500
+
501
+ // 插入链接
502
+ const insertLink = (): void => {
503
+ linkText.value = ''
504
+ linkHref.value = ''
505
+ linkDialog.value = true
506
+ }
507
+
508
+ // 确认插入链接
509
+ const confirmInsertLink = (): void => {
510
+ if (articleRef.value) {
511
+ const text = linkText.value || linkHref.value
512
+ const href = linkHref.value
513
+ if (href) {
514
+ articleRef.value.insertHtml(`<a href="${href}">${text}</a>`)
515
+ }
516
+ }
517
+ linkDialog.value = false
518
+ }
519
+
520
+ // 插入文本
521
+ const insertText = (): void => {
522
+ articleRef.value?.insertText()
523
+ }
524
+
525
+ // 插入HTML
526
+ const insertHtml = (html: string): void => {
527
+ articleRef.value?.insertHtml(html)
528
+ }
529
+
530
+ // 插入表格
531
+ const insertTable = (row?: number, col?: number): void => {
532
+ messageTable
533
+ .confirm({
534
+ title: translate('insertTable')
535
+ })
536
+ .then(() => {
537
+ if (articleRef.value) {
538
+ const rowValue = row ?? rows.value
539
+ const colValue = col ?? cols.value
540
+ articleRef.value.insertTable(rowValue, colValue)
541
+ }
542
+ })
543
+ }
544
+
545
+ // 插入代码
546
+ const insertCode = (language?: 'css' | 'javascript' | 'json'): void => {
547
+ const lan = language || 'javascript'
548
+ actions.value = [
549
+ {
550
+ name: 'css'
551
+ },
552
+ {
553
+ name: 'javascript'
554
+ },
555
+ {
556
+ name: 'json'
557
+ }
558
+ ]
559
+ openActionSheet('code')
560
+ }
561
+
562
+ // 插入表情
563
+ const insertEmoji = (emoji: string): void => {
564
+ if (articleRef.value) {
565
+ articleRef.value.insertHtml(emoji)
566
+ }
567
+ closeDialog()
568
+ }
569
+
570
+ // 插入模板
571
+ const insertTemplate = (): void => {
572
+ openDialog({ method: 'template', name: '', tap: () => {} })
573
+ }
574
+
575
+ // 插入标题
576
+ const insertHead = (level?: 'h1' | 'h3' | 'h5'): void => {
577
+ actions.value = [
578
+ {
579
+ name: translate('largeTitle')
580
+ },
581
+ {
582
+ name: translate('mediumTitle')
583
+ },
584
+ {
585
+ name: translate('smallTitle')
586
+ }
587
+ ]
588
+ openActionSheet('insertHtml')
589
+ }
590
+ // 工具按钮数组,按组分类
591
+ const toolButtons = ref<ToolButton[]>([
592
+ { name: 'rollback', method: 'undo', tap: () => undo() },
593
+ { name: 'rollback', method: 'redo', tap: () => redo(), class: 'reverse' },
594
+ { name: 'image', method: 'insertImg', tap: () => insertImg() },
595
+ { name: 'video1', method: 'insertVideo', tap: () => insertVideo() },
596
+ { name: 'link', method: 'insertLink', tap: () => insertLink() },
597
+ { name: 'note', method: 'insertText', tap: () => insertText(), icon: text },
598
+ { name: 'format-vertical-align-center', tap: () => insertHead(), icon: title },
599
+ {
600
+ name: 'discount',
601
+ method: 'insertHtml',
602
+ tap: () => insertHtml('<blockquote >引用</blockquote>'),
603
+ icon: quote
604
+ },
605
+ { name: 'windows', tap: () => insertTable() },
606
+ { name: 'code', tap: () => insertCode() },
607
+ { name: 'emjio', method: 'emoji', tap: () => openDialog({ method: 'emoji', name: '', tap: () => {} }), icon: emjio },
608
+ { name: 'file-copy', method: 'template', tap: () => insertTemplate() },
609
+ { name: 'clear', tap: clear },
610
+ { name: 'save', tap: save }
611
+ ])
612
+
613
+ // 暴露方法给外部调用
614
+ defineExpose({
615
+ undo,
616
+ redo,
617
+ insertImg,
618
+ insertVideo,
619
+ insertLink,
620
+ insertText,
621
+ insertHtml,
622
+ insertTable,
623
+ insertCode,
624
+ insertEmoji,
625
+ insertTemplate,
626
+ insertHead,
627
+ clear,
628
+ save,
629
+ getContent: () => articleRef.value?.getContent() || '',
630
+ in: (page: any, selector: string, scrollTop: string) => articleRef.value?.in(page, selector, scrollTop),
631
+ navigateTo: (id: string, offset?: number) => articleRef.value?.navigateTo(id, offset),
632
+ getText: (nodes?: any[]) => articleRef.value?.getText(nodes) || '',
633
+ getRect: () => articleRef.value?.getRect(),
634
+ pauseMedia: () => articleRef.value?.pauseMedia(),
635
+ setPlaybackRate: (rate: number) => articleRef.value?.setPlaybackRate(rate),
636
+ setContent: (content: string, append?: boolean) => articleRef.value?.setContent(content, append)
637
+ })
638
+ </script>
639
+
640
+ <style lang="scss" scoped>
641
+ @import './index.scss';
642
+ </style>
@@ -0,0 +1,76 @@
1
+ import type { ComponentPublicInstance, ExtractPropTypes } from 'vue'
2
+ import { baseProps, makeStringProp } from '../common/props'
3
+
4
+ export const richTextProps = {
5
+ ...baseProps,
6
+ markdown: {
7
+ type: String,
8
+ default: ''
9
+ },
10
+ tagStyle: {
11
+ type: Object,
12
+ default: () => ({})
13
+ },
14
+ editable: {
15
+ type: Boolean,
16
+ default: false
17
+ },
18
+ /**
19
+ * 弹层最大宽度,支持 `rpx`、`px`、`%` 等单位;
20
+ * `%` 在弹层打开时按屏幕宽度换算为 `rpx`
21
+ */
22
+ popupMaxWidth: makeStringProp('1200rpx'),
23
+ uploadMethod: {
24
+ type: Function as any,
25
+ default: null
26
+ }
27
+ }
28
+
29
+ export type RichTextExpose = {
30
+ undo: () => void
31
+ redo: () => void
32
+ insertImg: () => void
33
+ insertVideo: () => void
34
+ insertLink: () => void
35
+ insertText: () => void
36
+ insertHtml: (html: string) => void
37
+ insertTable: (row?: number, col?: number) => void
38
+ insertCode: (language?: 'css' | 'javascript' | 'json') => void
39
+ insertEmoji: (emoji: string) => void
40
+ insertTemplate: () => void
41
+ insertHead: (level?: 'h1' | 'h3' | 'h5') => void
42
+ clear: () => void
43
+ save: () => void
44
+ getContent: () => string
45
+ in: (page: any, selector: string, scrollTop: string) => void
46
+ navigateTo: (id: string, offset?: number) => Promise<void>
47
+ getText: (nodes?: any[]) => string
48
+ getRect: () => Promise<{ width: number; height: number; top: number; left: number }>
49
+ pauseMedia: () => void
50
+ setPlaybackRate: (rate: number) => void
51
+ setContent: (content: string, append?: boolean) => void
52
+ }
53
+
54
+ export type RichTextProps = ExtractPropTypes<typeof richTextProps>
55
+
56
+ export type RichTextInstance = ComponentPublicInstance<RichTextExpose, RichTextProps>
57
+
58
+ export interface ToolButton {
59
+ name: string
60
+ method?: string
61
+ param?: string
62
+ tap: () => void
63
+ icon?: string
64
+ class?: string
65
+ }
66
+
67
+ export interface ActionSheetInfo {
68
+ type: string
69
+ index?: number
70
+ }
71
+
72
+ // 删除图片/视频/音频标签事件
73
+ export interface RemoveEvent {
74
+ src: string
75
+ type: string
76
+ }