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,338 @@
1
+ <template>
2
+ <view :id="elId" :data-id="elId" :class="`oxy-long-press-menu ${mode === 'selection' ? 'is-selectable' : ''} ${customClass}`" :style="customStyle">
3
+ <!-- 触发区域 -->
4
+ <!-- mode='normal': 使用 longpress 事件 -->
5
+ <!-- mode='selection': 不使用 longpress,依靠 renderjs/js 监听 selection -->
6
+ <view
7
+ class="oxy-long-press-menu__trigger"
8
+ @longpress="mode === 'normal' ? onLongPress($event) : null"
9
+ :class="{ 'is-active': isVisible && mode === 'normal' }"
10
+ >
11
+ <slot></slot>
12
+ </view>
13
+
14
+ <!-- 遮罩层 (Normal模式使用,Selection模式不需要遮罩,依靠原生行为关闭) -->
15
+ <view v-if="isVisible && mode === 'normal'" class="oxy-long-press-menu__mask" @click="hideMenu" @touchmove.stop.prevent></view>
16
+
17
+ <!-- 气泡菜单 -->
18
+ <view v-if="isVisible" class="oxy-long-press-menu__popover" :style="popoverStyle" @click.stop>
19
+ <view
20
+ v-if="visibleArrow"
21
+ :class="`oxy-long-press-menu__arrow oxy-long-press-menu__${arrowBottom ? 'arrow-down' : 'arrow-up'}`"
22
+ :style="arrowStyle"
23
+ ></view>
24
+ <view class="oxy-long-press-menu__content">
25
+ <view v-for="(item, index) in menus" :key="index" class="oxy-long-press-menu__item" @click="onMenuClick(item)">
26
+ <text class="oxy-long-press-menu__text">{{ item.text }}</text>
27
+ </view>
28
+ </view>
29
+ </view>
30
+
31
+ <!-- #ifdef APP-PLUS || H5 -->
32
+ <view :prop="selectionProp" :change:prop="selection.propObserver"></view>
33
+ <!-- #endif -->
34
+ </view>
35
+ </template>
36
+
37
+ <script>
38
+ import { uuid, getRect, unitConvert } from '../common/util'
39
+
40
+ export default {
41
+ name: 'oxy-long-press-menu',
42
+ props: {
43
+ customClass: {
44
+ type: String,
45
+ default: ''
46
+ },
47
+ customStyle: {
48
+ type: String,
49
+ default: ''
50
+ },
51
+ mode: {
52
+ type: String,
53
+ default: 'normal'
54
+ },
55
+ menus: {
56
+ type: Array,
57
+ default: () => []
58
+ },
59
+ content: {
60
+ type: String,
61
+ default: ''
62
+ },
63
+ visibleArrow: {
64
+ type: Boolean,
65
+ default: true
66
+ }
67
+ },
68
+ data() {
69
+ return {
70
+ elId: `long-press-menu${uuid()}`,
71
+ isVisible: false,
72
+ popoverStyle: {},
73
+ arrowStyle: {},
74
+ rect: null,
75
+ selectedText: '', // 存储选中的文本
76
+ selectionProp: '', // 用于与 renderjs 通信
77
+ arrowBottom: true
78
+ }
79
+ },
80
+ watch: {
81
+ // 监听外部 content 变化
82
+ content(val) {
83
+ if (this.mode === 'normal') {
84
+ this.selectedText = val
85
+ }
86
+ }
87
+ },
88
+ created() {
89
+ if (this.mode === 'normal') {
90
+ this.selectedText = this.content
91
+ }
92
+ },
93
+ methods: {
94
+ // --- RenderJS 通信方法 ---
95
+ // 接收 renderjs 发来的选中区域信息
96
+ onSelectionChange(data) {
97
+ if (this.mode !== 'selection') return
98
+
99
+ if (!data) {
100
+ // 清除选中
101
+ if (this.mode === 'selection') {
102
+ this.isVisible = false
103
+ }
104
+ return
105
+ }
106
+
107
+ const { text, rect } = data
108
+ if (text && rect) {
109
+ this.selectedText = text
110
+ this.showMenu(rect)
111
+ }
112
+ },
113
+
114
+ // --- 现有逻辑 ---
115
+ onLongPress(e) {
116
+ if (this.mode !== 'normal') return
117
+
118
+ // 获取触发元素的位置
119
+ getRect('.oxy-long-press-menu__trigger', false, this)
120
+ .then((rect) => {
121
+ if (rect) {
122
+ this.showMenu(rect)
123
+ }
124
+ })
125
+ .catch(() => {})
126
+ this.$emit('longpress', e)
127
+ },
128
+ showMenu(rect) {
129
+ this.rect = rect
130
+ // 计算气泡位置
131
+ // 默认显示在元素上方
132
+ this.arrowBottom = true // 箭头在底部(气泡在上方)
133
+ let top = rect.top - (this.mode !== 'normal' ? 60 : 10) // 预估气泡高度 + 箭头 + 间距
134
+ let left = rect.left + rect.width / 2
135
+ // 如果上方空间不足,显示在下方
136
+ if (top < 50) {
137
+ // 顶部留一些安全距离
138
+ top = rect.bottom + (this.mode !== 'normal' ? 20 : 60)
139
+ this.arrowBottom = false // 箭头在顶部(气泡在下方)
140
+ }
141
+ this.popoverStyle = {
142
+ top: unitConvert(top, 0, { output: 'px' }),
143
+ left: unitConvert(left, 0, { output: 'px' }),
144
+ animation: 'fadeIn 0.2s ease-out'
145
+ }
146
+ this.arrowStyle = {
147
+ left: unitConvert(rect.width / 2, 0, { output: 'px' })
148
+ }
149
+ this.isVisible = true
150
+ this.$nextTick(() => {
151
+ getRect('.oxy-long-press-menu__popover', false, this)
152
+ .then((prect) => {
153
+ if (prect) {
154
+ const windowWidth = uni.getSystemInfoSync().windowWidth
155
+ let pLeft = left - prect.width / 2
156
+ let arrowLeft = rect.width / 2
157
+ let arrowRight = 'auto'
158
+ if (pLeft < 0) {
159
+ pLeft = rect.left
160
+ } else if (pLeft + prect.width > windowWidth) {
161
+ pLeft = rect.left + rect.width - prect.width
162
+ arrowLeft = 'auto'
163
+ arrowRight = rect.width / 2
164
+ } else {
165
+ arrowLeft = '50%'
166
+ }
167
+ this.popoverStyle.left = unitConvert(pLeft, 0, { output: 'px' })
168
+ this.arrowStyle.left = unitConvert(arrowLeft, 0, { output: 'px' })
169
+ this.arrowStyle.right = unitConvert(arrowRight, 0, { output: 'px' })
170
+ }
171
+ })
172
+ .catch(() => {})
173
+ })
174
+ // 振动反馈 (仅 Normal 模式或首次显示时)
175
+ if (this.mode === 'normal') {
176
+ uni.vibrateShort()
177
+ }
178
+ },
179
+ hideMenu() {
180
+ this.isVisible = false
181
+ // 通知 renderjs 清除状态 (可选)
182
+ this.selectionProp = 'clear-' + Date.now()
183
+ },
184
+ onMenuClick(item) {
185
+ // 不要立即 hideMenu,因为可能要操作 selection
186
+ // 但对于 copy,我们通常会操作完后隐藏
187
+
188
+ // 内置复制功能
189
+ if (item.value === 'copy') {
190
+ const textToCopy = this.selectedText || this.content
191
+ if (textToCopy) {
192
+ uni.setClipboardData({
193
+ data: textToCopy,
194
+ success: () => {
195
+ uni.showToast({
196
+ title: '已复制',
197
+ icon: 'none'
198
+ })
199
+ }
200
+ })
201
+ }
202
+ }
203
+
204
+ this.$emit('menu-click', { ...item, content: this.selectedText })
205
+ this.hideMenu()
206
+ }
207
+ }
208
+ }
209
+ </script>
210
+
211
+ <!-- #ifdef APP-PLUS || H5 -->
212
+ <script module="selection" lang="renderjs">
213
+ module.exports = {
214
+ data() {
215
+ return {
216
+ isSelecting: false,
217
+ ownerId: null,
218
+ selectionDebounce: null
219
+ }
220
+ },
221
+ mounted() {
222
+ // 获取组件ID
223
+ this.ownerId = this.$el.getAttribute('data-id')
224
+
225
+ // 监听 selectionchange
226
+ document.addEventListener('selectionchange', this.handleSelectionChange)
227
+ // 监听 touchend 用于确定选择结束
228
+ document.addEventListener('touchend', this.handleTouchEnd)
229
+ // 同时也监听当前元素的 touchend,以防冒泡问题
230
+ this.$el.addEventListener('touchend', this.handleTouchEnd)
231
+ document.addEventListener('mouseup', this.handleTouchEnd)
232
+
233
+ // 阻止默认上下文菜单(防止系统菜单冲突)
234
+ this.$el.addEventListener('contextmenu', (e) => {
235
+ // 在 selectable 模式下,如果选区在本组件内,阻止默认菜单
236
+ // 在 normal 模式下,也阻止默认菜单
237
+ e.preventDefault()
238
+ return false
239
+ })
240
+ },
241
+ beforeDestroy() {
242
+ document.removeEventListener('selectionchange', this.handleSelectionChange)
243
+ document.removeEventListener('touchend', this.handleTouchEnd)
244
+ if (this.$el) {
245
+ this.$el.removeEventListener('touchend', this.handleTouchEnd)
246
+ }
247
+ document.removeEventListener('mouseup', this.handleTouchEnd)
248
+ },
249
+ methods: {
250
+ propObserver(newValue, oldValue) {
251
+ if (newValue && newValue.startsWith('clear')) {
252
+ const selection = window.getSelection()
253
+ if (selection) {
254
+ selection.removeAllRanges()
255
+ }
256
+ }
257
+ },
258
+ handleSelectionChange() {
259
+ // 清除之前的定时器
260
+ if (this.selectionDebounce) clearTimeout(this.selectionDebounce)
261
+
262
+ // 增加防抖检测,以防 touchend 被系统吞掉或未触发
263
+ // 600ms 后如果没有新的 selectionchange,尝试检查选区
264
+ this.selectionDebounce = setTimeout(() => {
265
+ this.checkSelection()
266
+ }, 600)
267
+ },
268
+ handleTouchEnd() {
269
+ // 立即清除防抖,改用短延时检查
270
+ if (this.selectionDebounce) clearTimeout(this.selectionDebounce)
271
+
272
+ // 延时一下确保 selection 状态已更新
273
+ setTimeout(() => {
274
+ this.checkSelection()
275
+ }, 100)
276
+ },
277
+ checkSelection() {
278
+ const selection = window.getSelection()
279
+ // 如果没有选区或选区为空,清除菜单
280
+ if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
281
+ this.$ownerInstance.callMethod('onSelectionChange', null)
282
+ return
283
+ }
284
+
285
+ const text = selection.toString()
286
+ if (!text || !text.trim()) {
287
+ this.$ownerInstance.callMethod('onSelectionChange', null)
288
+ return
289
+ }
290
+
291
+ // 检查选区是否在这个组件内
292
+ if (!this.isSelectionInThisElement(selection)) {
293
+ // 不属于本组件的选区,应该清除本组件的菜单
294
+ // 这样点击外部或者选择了其他组件的文字时,当前菜单会自动消失
295
+ this.$ownerInstance.callMethod('onSelectionChange', null)
296
+ return
297
+ }
298
+
299
+ // 获取选区坐标
300
+ const range = selection.getRangeAt(0)
301
+ const rect = range.getBoundingClientRect()
302
+
303
+ // 转换为纯对象传递
304
+ this.$ownerInstance.callMethod('onSelectionChange', {
305
+ text: text,
306
+ rect: {
307
+ top: rect.top,
308
+ bottom: rect.bottom,
309
+ left: rect.left,
310
+ right: rect.right,
311
+ width: rect.width,
312
+ height: rect.height
313
+ }
314
+ })
315
+ },
316
+ isSelectionInThisElement(selection) {
317
+ if (!selection) selection = window.getSelection()
318
+ if (selection.rangeCount === 0) return false
319
+
320
+ const range = selection.getRangeAt(0)
321
+ let container = range.commonAncestorContainer
322
+
323
+ // 如果容器是文本节点,取其父元素
324
+ if (container.nodeType === 3) {
325
+ container = container.parentNode
326
+ }
327
+
328
+ // 使用 contains 判断选区是否在当前组件根元素内
329
+ return this.$el.contains(container)
330
+ }
331
+ }
332
+ }
333
+ </script>
334
+ <!-- #endif -->
335
+
336
+ <style lang="scss" scoped>
337
+ @import './index.scss';
338
+ </style>
@@ -0,0 +1,34 @@
1
+ import type { PropType } from 'vue'
2
+ import { baseProps, makeStringProp } from '../common/props'
3
+
4
+ export type LongPressMenuType = 'normal' | 'selection'
5
+
6
+ export type MenusItem = {
7
+ [key: string]: any
8
+ text: string
9
+ value: string
10
+ }
11
+
12
+ export const longPressMenuProps = {
13
+ ...baseProps,
14
+ /**
15
+ * 模式,'normal' (长按直接弹) | 'selection' (选文后弹 - 仅H5/App)
16
+ * 类型: string
17
+ * 默认值: 'normal'
18
+ */
19
+ mode: makeStringProp<LongPressMenuType>('normal'),
20
+ /**
21
+ * 菜单项
22
+ * 类型: array
23
+ * 默认值: [{ text: '复制', value: 'copy' }]
24
+ */
25
+ menus: {
26
+ type: Array as PropType<MenusItem[]>,
27
+ default: () => [{ text: '复制', value: 'copy' }]
28
+ },
29
+ /**
30
+ * 要复制的内容,如果不传则不自动处理复制
31
+ * 类型: string
32
+ */
33
+ content: makeStringProp('')
34
+ }
@@ -31,7 +31,6 @@
31
31
  overflow: hidden;
32
32
 
33
33
  @include e(container) {
34
- width: $-message-box-width;
35
34
  box-sizing: border-box;
36
35
  }
37
36
 
@@ -40,7 +39,7 @@
40
39
  padding: $-message-box-padding;
41
40
 
42
41
  @include when(no-title) {
43
- padding: 25px 24px 0px;
42
+ padding: 50rpx 48rpx 0rpx;
44
43
  }
45
44
  }
46
45
 
@@ -48,10 +47,10 @@
48
47
  text-align: center;
49
48
  font-size: $-message-box-title-fs;
50
49
  color: $-message-box-title-color;
51
- line-height: 20px;
50
+ line-height: 40rpx;
52
51
  font-weight: 500;
53
- padding-top: 5px;
54
- padding-bottom: 10px;
52
+ padding-top: 10rpx;
53
+ padding-bottom: 20rpx;
55
54
  }
56
55
 
57
56
  @include e(content) {
@@ -60,7 +59,7 @@
60
59
  font-size: $-message-box-content-fs;
61
60
  text-align: center;
62
61
  overflow: auto;
63
- line-height: 20px;
62
+ line-height: 40rpx;
64
63
 
65
64
  &::-webkit-scrollbar {
66
65
  width: $-message-box-content-scrollbar-width;
@@ -74,8 +73,8 @@
74
73
  }
75
74
 
76
75
  @include e(input-error) {
77
- min-height: 18px;
78
- margin-top: 2px;
76
+ min-height: 36rpx;
77
+ margin-top: 4rpx;
79
78
  color: $-message-box-input-error-color;
80
79
  text-align: left;
81
80
 
@@ -85,17 +84,19 @@
85
84
  }
86
85
 
87
86
  @include e(actions) {
88
- padding: 24px;
87
+ padding: 48rpx;
89
88
  }
90
89
 
91
90
  @include edeep(actions-btn) {
92
91
  &:not(:last-child) {
93
- margin-right: 16px;
92
+ margin-right: 32rpx;
94
93
  }
95
94
  }
96
95
 
97
96
  @include e(flex) {
98
97
  display: flex;
98
+ justify-content: center;
99
+ align-items: center;
99
100
  }
100
101
 
101
102
  @include e(block) {
@@ -103,6 +104,6 @@
103
104
  }
104
105
 
105
106
  @include e(cancel) {
106
- margin-right: 16px;
107
+ margin-right: 32rpx;
107
108
  }
108
109
  }
@@ -5,13 +5,14 @@
5
5
  v-model="messageState.show"
6
6
  :close-on-click-modal="messageState.closeOnClickModal"
7
7
  :lazy-render="messageState.lazyRender"
8
+ :max-width="popupMaxWidth"
8
9
  custom-class="oxy-message-box"
9
10
  @click-modal="toggleModal('modal')"
10
11
  :z-index="messageState.zIndex"
11
12
  :duration="200"
12
13
  :root-portal="rootPortal"
13
14
  >
14
- <view :class="rootClass">
15
+ <view :class="rootClass" :style="containerStyle">
15
16
  <view :class="bodyClass">
16
17
  <view v-if="messageState.title" class="oxy-message-box__title">
17
18
  {{ messageState.title }}
@@ -62,7 +63,7 @@ import OxyInput from '../oxy-input/oxy-input.vue'
62
63
  import { computed, inject, reactive, ref, watch } from 'vue'
63
64
  import { messageBoxProps, type MessageOptionsWithCallBack, type MessageResult } from './types'
64
65
  import { defaultOptions, getMessageDefaultOptionKey } from '.'
65
- import { deepAssign, isDef, isFunction, isUndefined, omitBy } from '../common/util'
66
+ import { deepAssign, isDef, isFunction, isUndefined, omitBy, resolveSizeWithScreenWidth } from '../common/util'
66
67
  import { useTranslate } from '../composables/useTranslate'
67
68
  import type { ButtonProps } from '../oxy-button/types'
68
69
 
@@ -78,6 +79,11 @@ const bodyClass = computed(() => {
78
79
  return `oxy-message-box__body ${!messageState.title ? 'is-no-title' : ''} ${messageState.type === 'prompt' ? 'is-prompt' : ''}`
79
80
  })
80
81
 
82
+ const containerStyle = computed(() => {
83
+ const width = resolveSizeWithScreenWidth(messageState.width || props.width, { defaultUnit: 'rpx' })
84
+ return `width:${width};`
85
+ })
86
+
81
87
  const messageOptionKey = getMessageDefaultOptionKey(props.selector)
82
88
  const messageOption = inject(messageOptionKey, ref<MessageOptionsWithCallBack>(defaultOptions)) // message选项
83
89
 
@@ -96,7 +102,8 @@ const messageState = reactive<MessageOptionsWithCallBack>({
96
102
  inputError: '', // 输入框错误提示文案
97
103
  showErr: false, // 是否显示错误提示
98
104
  zIndex: 99, // 弹窗层级
99
- lazyRender: true // 弹层内容懒渲染
105
+ lazyRender: true, // 弹层内容懒渲染
106
+ width: props.width // 弹框宽度
100
107
  })
101
108
 
102
109
  /**
@@ -280,6 +287,7 @@ function reset(option: MessageOptionsWithCallBack) {
280
287
  messageState.showErr = option.showErr
281
288
  messageState.zIndex = option.zIndex
282
289
  messageState.lazyRender = option.lazyRender
290
+ messageState.width = isDef(option.width) ? option.width : props.width
283
291
  messageState.confirmButtonProps = option.confirmButtonProps
284
292
  messageState.cancelButtonProps = option.cancelButtonProps
285
293
  }
@@ -77,6 +77,10 @@ export type MessageOptions = {
77
77
  * 弹层内容懒渲染,触发展示时才渲染内容
78
78
  */
79
79
  lazyRender?: boolean
80
+ /**
81
+ * 弹框宽度,支持带单位的值(如 `640rpx`、`480px`、`80%`)
82
+ */
83
+ width?: string
80
84
  /**
81
85
  * 确认前钩子
82
86
  */
@@ -125,6 +129,16 @@ export const messageBoxProps = {
125
129
  * 指定唯一标识
126
130
  */
127
131
  selector: makeStringProp(''),
132
+ /**
133
+ * 弹框宽度,支持带单位的值(如 `640rpx`、`480px`、`80%`)
134
+ * @default '80%'
135
+ */
136
+ width: makeStringProp('80%'),
137
+ /**
138
+ * 弹层最大宽度,支持 `rpx`、`px`、`%` 等单位;
139
+ * `%` 在弹层打开时按屏幕宽度换算为 `rpx`
140
+ */
141
+ popupMaxWidth: makeStringProp('1200rpx'),
128
142
  /**
129
143
  * 是否从页面中脱离出来,用于解决各种 fixed 失效问题 (H5: teleport, APP: renderjs, 小程序: root-portal)
130
144
  */
@@ -58,7 +58,7 @@
58
58
  font-size: $-navbar-desc-font-size;
59
59
  display: flex;
60
60
  align-items: center;
61
- padding: 0 12px;
61
+ padding: 0 24rpx;
62
62
 
63
63
  @include when(disabled) {
64
64
  opacity: $-navbar-disabled-opacity;
@@ -90,4 +90,4 @@
90
90
  width: 100%;
91
91
  z-index: 500;
92
92
  }
93
- }
93
+ }
@@ -1,7 +1,10 @@
1
1
  <template>
2
- <view :style="{ height: addUnit(height) }">
2
+ <view :style="placeholderStyle">
3
3
  <view :class="`oxy-navbar ${customClass} ${fixed ? 'is-fixed' : ''} ${bordered ? 'is-border' : ''}`" :style="rootStyle">
4
- <view class="oxy-navbar__content">
4
+ <view
5
+ class="oxy-navbar__content"
6
+ :style="{ width: fixed && avoidMenuButtonMode === 'full' ? unitConvert(navWidth, 0, { output: 'px' }) : '100%' }"
7
+ >
5
8
  <view class="oxy-navbar__capsule" v-if="$slots.capsule">
6
9
  <slot name="capsule" />
7
10
  </view>
@@ -19,7 +22,12 @@
19
22
  <slot name="title" />
20
23
  <block v-if="!$slots.title && title">{{ title }}</block>
21
24
  </view>
22
- <view :class="`oxy-navbar__right ${rightDisabled ? 'is-disabled' : ''}`" @click="handleClickRight" v-if="$slots.right || rightText">
25
+ <view
26
+ :class="`oxy-navbar__right ${rightDisabled ? 'is-disabled' : ''}`"
27
+ @click="handleClickRight"
28
+ v-if="$slots.right || rightText"
29
+ :style="rightStyle"
30
+ >
23
31
  <slot name="right" />
24
32
 
25
33
  <view v-if="!$slots.right && rightText" class="oxy-navbar__text" hover-class="oxy-navbar__text--hover" :hover-stay-time="70">
@@ -44,41 +52,63 @@ export default {
44
52
  <script lang="ts" setup>
45
53
  import OxyIcon from '../oxy-icon/oxy-icon.vue'
46
54
  import { type CSSProperties, computed, getCurrentInstance, nextTick, onMounted, ref, watch } from 'vue'
47
- import { getRect, addUnit, isDef, objToStyle } from '../common/util'
55
+ import { getRect, isDef, objToStyle, unitConvert } from '../common/util'
48
56
  import { navbarProps } from './types'
49
57
 
50
58
  const props = defineProps(navbarProps)
51
59
  const emit = defineEmits(['click-left', 'click-right'])
52
60
 
53
- const height = ref<number | ''>('') // 占位高度
61
+ const placeholderHeight = ref<number | ''>('') // 占位高度(rpx 语义)
62
+ const navWidth = ref<number | 'auto'>('auto') // 导航栏宽度
54
63
 
55
64
  const { statusBarHeight } = uni.getSystemInfoSync()
56
65
 
57
66
  watch(
58
- [() => props.fixed, () => props.placeholder],
67
+ [() => props.fixed, () => props.placeholder, () => props.safeAreaInsetTop, () => props.customStyle],
59
68
  () => {
60
69
  setPlaceholderHeight()
61
70
  },
62
- { deep: true, immediate: false }
71
+ { immediate: false }
63
72
  )
64
73
 
74
+ const placeholderStyle = computed(() => {
75
+ if (!props.fixed || !props.placeholder) {
76
+ return {}
77
+ }
78
+ return {
79
+ height: `${Number(placeholderHeight.value) || 0}rpx`
80
+ }
81
+ })
82
+
65
83
  const rootStyle = computed(() => {
66
84
  const style: CSSProperties = {}
67
85
  if (props.fixed && isDef(props.zIndex)) {
68
86
  style['z-index'] = props.zIndex
69
87
  }
70
88
  if (props.safeAreaInsetTop) {
71
- style['padding-top'] = addUnit(statusBarHeight || 0)
89
+ style['padding-top'] = unitConvert(statusBarHeight || 0, 0, { output: 'px' })
72
90
  }
73
91
  return `${objToStyle(style)}${props.customStyle}`
74
92
  })
75
93
 
94
+ const rightStyle = computed(() => {
95
+ const style: CSSProperties = {}
96
+ if (props.fixed && props.avoidMenuButtonMode === 'right' && navWidth.value !== 'auto') {
97
+ style['right'] = `calc(100% - ${unitConvert(navWidth.value, 0, { output: 'px' })})`
98
+ }
99
+ return style
100
+ })
101
+
76
102
  onMounted(() => {
77
103
  if (props.fixed && props.placeholder) {
78
- nextTick(() => {
79
- setPlaceholderHeight()
80
- })
104
+ setPlaceholderHeight()
105
+ }
106
+ // #ifdef MP-WEIXIN
107
+ if (props.fixed && props.avoidMenuButtonMode) {
108
+ const menuBtnInfo = uni.getMenuButtonBoundingClientRect()
109
+ navWidth.value = menuBtnInfo.left
81
110
  }
111
+ // #endif
82
112
  })
83
113
 
84
114
  function handleClickLeft() {
@@ -97,11 +127,26 @@ const { proxy } = getCurrentInstance() as any
97
127
 
98
128
  function setPlaceholderHeight() {
99
129
  if (!props.fixed || !props.placeholder) {
130
+ placeholderHeight.value = ''
100
131
  return
101
132
  }
102
133
 
103
- getRect('.oxy-navbar', false, proxy).then((res) => {
104
- height.value = res.height as number
134
+ nextTick(() => {
135
+ getRect('.oxy-navbar', false, proxy)
136
+ .then((res) => {
137
+ const rectHeight = Number(res.height) || 0
138
+ const rectTop = Number(res.top)
139
+ const rectBottom = Number(res.bottom)
140
+ const occupiedHeight =
141
+ rectHeight > 0 ? rectHeight : !Number.isNaN(rectTop) && !Number.isNaN(rectBottom) ? Math.max(rectBottom - rectTop, 0) : 0
142
+ const pxPer100Rpx = uni.upx2px(100)
143
+ const occupiedHeightInRpx = pxPer100Rpx ? (occupiedHeight / pxPer100Rpx) * 100 : occupiedHeight * 2
144
+
145
+ placeholderHeight.value = occupiedHeight ? occupiedHeightInRpx : ''
146
+ })
147
+ .catch(() => {
148
+ placeholderHeight.value = ''
149
+ })
105
150
  })
106
151
  }
107
152
  </script>
@@ -46,7 +46,14 @@ export const navbarProps = {
46
46
  /**
47
47
  * 是否禁用右侧按钮,禁用时透明度降低,且无法点击
48
48
  */
49
- rightDisabled: makeBooleanProp(false)
49
+ rightDisabled: makeBooleanProp(false),
50
+ /**
51
+ * 胶囊避让模式:'full' 整体缩小宽度,'right' 仅右侧避让,不传则不避让
52
+ */
53
+ avoidMenuButtonMode: {
54
+ type: String,
55
+ default: ''
56
+ }
50
57
  }
51
58
 
52
59
  export type NavbarProps = ExtractPropTypes<typeof navbarProps>