oxy-uni-ui 1.2.3 → 2.1.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 (246) hide show
  1. package/attributes.json +1 -1
  2. package/components/common/abstracts/variable.scss +512 -343
  3. package/components/common/util.ts +185 -32
  4. package/components/composables/index.ts +1 -0
  5. package/components/composables/usePopover.ts +24 -20
  6. package/components/composables/useVirtualScroll.ts +48 -21
  7. package/components/composables/useWindowResize.ts +35 -0
  8. package/components/oxy-action-sheet/index.scss +24 -11
  9. package/components/oxy-action-sheet/oxy-action-sheet.vue +27 -19
  10. package/components/oxy-action-sheet/types.ts +7 -0
  11. package/components/oxy-backtop/index.scss +4 -4
  12. package/components/oxy-backtop/oxy-backtop.vue +9 -6
  13. package/components/oxy-backtop/types.ts +7 -7
  14. package/components/oxy-badge/index.scss +4 -4
  15. package/components/oxy-badge/oxy-badge.vue +3 -3
  16. package/components/oxy-badge/types.ts +2 -2
  17. package/components/oxy-button/index.scss +5 -5
  18. package/components/oxy-button/oxy-button.vue +5 -1
  19. package/components/oxy-calendar/index.scss +15 -15
  20. package/components/oxy-calendar/oxy-calendar.vue +1 -0
  21. package/components/oxy-calendar/types.ts +5 -0
  22. package/components/oxy-calendar-view/month/index.scss +4 -4
  23. package/components/oxy-calendar-view/month/types.ts +36 -0
  24. package/components/oxy-calendar-view/monthPanel/index.scss +7 -8
  25. package/components/oxy-calendar-view/monthPanel/month-panel.vue +14 -8
  26. package/components/oxy-calendar-view/year/index.scss +5 -5
  27. package/components/oxy-calendar-view/yearPanel/index.scss +4 -4
  28. package/components/oxy-calendar-view/yearPanel/year-panel.vue +21 -5
  29. package/components/oxy-card/index.scss +2 -2
  30. package/components/oxy-cell/index.scss +8 -8
  31. package/components/oxy-checkbox/index.scss +12 -12
  32. package/components/oxy-checkbox-group/index.scss +2 -2
  33. package/components/oxy-circle/oxy-circle.vue +10 -7
  34. package/components/oxy-circle/types.ts +5 -5
  35. package/components/oxy-col/oxy-col.vue +2 -2
  36. package/components/oxy-col-picker/index.scss +4 -4
  37. package/components/oxy-col-picker/oxy-col-picker.vue +6 -5
  38. package/components/oxy-col-picker/types.ts +7 -2
  39. package/components/oxy-collapse/index.scss +2 -2
  40. package/components/oxy-collapse-item/oxy-collapse-item.vue +3 -3
  41. package/components/oxy-corner/index.scss +33 -33
  42. package/components/oxy-count-to/oxy-count-to.vue +3 -3
  43. package/components/oxy-curtain/index.scss +15 -15
  44. package/components/oxy-curtain/oxy-curtain.vue +4 -2
  45. package/components/oxy-curtain/types.ts +6 -1
  46. package/components/oxy-date-strip/oxy-date-strip.vue +2 -2
  47. package/components/oxy-date-strip/types.ts +1 -1
  48. package/components/oxy-date-strip-item/index.scss +3 -3
  49. package/components/oxy-datetime-picker/index.scss +11 -11
  50. package/components/oxy-datetime-picker/oxy-datetime-picker.vue +1 -0
  51. package/components/oxy-datetime-picker/types.ts +5 -0
  52. package/components/oxy-drop-menu/index.scss +5 -5
  53. package/components/oxy-drop-menu/oxy-drop-menu.vue +3 -3
  54. package/components/oxy-drop-menu-item/index.scss +3 -3
  55. package/components/oxy-drop-menu-item/oxy-drop-menu-item.vue +4 -3
  56. package/components/oxy-drop-menu-item/types.ts +5 -0
  57. package/components/oxy-echarts/types.ts +6 -0
  58. package/components/oxy-fab/index.scss +8 -8
  59. package/components/oxy-fab/oxy-fab.vue +22 -3
  60. package/components/oxy-file-list/index.scss +30 -29
  61. package/components/oxy-file-list/oxy-file-list.vue +2 -2
  62. package/components/oxy-floating-panel/oxy-floating-panel.vue +13 -9
  63. package/components/oxy-floating-panel/{type.ts → types.ts} +8 -8
  64. package/components/oxy-footer/index.scss +19 -0
  65. package/components/oxy-footer/oxy-footer.vue +78 -0
  66. package/components/oxy-footer/types.ts +17 -0
  67. package/components/oxy-form-item/types.ts +22 -1
  68. package/components/oxy-gap/oxy-gap.vue +2 -2
  69. package/components/oxy-gap/types.ts +2 -2
  70. package/components/oxy-grid/oxy-grid.vue +1 -1
  71. package/components/oxy-grid/types.ts +1 -1
  72. package/components/oxy-grid-item/index.scss +1 -1
  73. package/components/oxy-grid-item/oxy-grid-item.vue +7 -5
  74. package/components/oxy-grid-item/types.ts +1 -1
  75. package/components/oxy-guidance/index.scss +75 -0
  76. package/components/oxy-guidance/oxy-guidance.vue +201 -0
  77. package/components/oxy-guidance/types.ts +33 -0
  78. package/components/oxy-icon/oxy-icon.vue +2 -2
  79. package/components/oxy-icon/types.ts +1 -1
  80. package/components/oxy-img/oxy-img.vue +4 -4
  81. package/components/oxy-img/types.ts +3 -3
  82. package/components/oxy-img-cropper/index.scss +23 -23
  83. package/components/oxy-img-cropper/oxy-img-cropper.vue +97 -52
  84. package/components/oxy-img-cropper/types.ts +2 -2
  85. package/components/oxy-img-lazy/oxy-img-lazy.vue +3 -3
  86. package/components/oxy-img-lazy/types.ts +3 -3
  87. package/components/oxy-index-anchor/index.scss +2 -2
  88. package/components/oxy-index-anchor/oxy-index-anchor.vue +2 -2
  89. package/components/oxy-index-anchor/{type.ts → types.ts} +3 -0
  90. package/components/oxy-index-bar/index.scss +3 -3
  91. package/components/oxy-index-bar/oxy-index-bar.vue +3 -3
  92. package/components/oxy-index-bar/{type.ts → types.ts} +2 -2
  93. package/components/oxy-input/index.scss +1 -1
  94. package/components/oxy-input-number/index.scss +5 -5
  95. package/components/oxy-input-number/oxy-input-number.vue +2 -2
  96. package/components/oxy-input-number/types.ts +3 -2
  97. package/components/oxy-keyboard/index.scss +5 -5
  98. package/components/oxy-keyboard/key/index.scss +3 -3
  99. package/components/oxy-keyboard/key/index.vue +2 -2
  100. package/components/oxy-keyboard/key/types.ts +15 -0
  101. package/components/oxy-keyboard/oxy-keyboard.vue +1 -0
  102. package/components/oxy-keyboard/types.ts +5 -0
  103. package/components/oxy-link/index.scss +2 -2
  104. package/components/oxy-list/oxy-list.vue +4 -3
  105. package/components/oxy-loading/oxy-loading.vue +8 -4
  106. package/components/oxy-loading/types.ts +1 -1
  107. package/components/oxy-loadmore/index.scss +3 -3
  108. package/components/oxy-long-press-menu/index.scss +93 -0
  109. package/components/oxy-long-press-menu/oxy-long-press-menu.vue +338 -0
  110. package/components/oxy-long-press-menu/types.ts +34 -0
  111. package/components/oxy-message-box/index.scss +12 -11
  112. package/components/oxy-message-box/oxy-message-box.vue +9 -2
  113. package/components/oxy-message-box/types.ts +9 -0
  114. package/components/oxy-navbar/index.scss +2 -2
  115. package/components/oxy-navbar/oxy-navbar.vue +58 -13
  116. package/components/oxy-navbar/types.ts +8 -1
  117. package/components/oxy-navbar-capsule/types.ts +3 -0
  118. package/components/oxy-notice-bar/index.scss +3 -3
  119. package/components/oxy-notice-bar/oxy-notice-bar.vue +9 -5
  120. package/components/oxy-notice-bar/types.ts +3 -3
  121. package/components/oxy-notify/index.ts +1 -0
  122. package/components/oxy-notify/oxy-notify.vue +3 -2
  123. package/components/oxy-notify/types.ts +7 -0
  124. package/components/oxy-pagination/index.scss +6 -5
  125. package/components/oxy-password-input/oxy-password-input.vue +2 -2
  126. package/components/oxy-password-input/types.ts +1 -1
  127. package/components/oxy-picker/index.scss +45 -2
  128. package/components/oxy-picker/oxy-picker.vue +100 -14
  129. package/components/oxy-picker/types.ts +29 -1
  130. package/components/oxy-picker-view/index.scss +4 -4
  131. package/components/oxy-picker-view/oxy-picker-view.vue +4 -4
  132. package/components/oxy-popover/index.scss +13 -13
  133. package/components/oxy-popup/index.scss +4 -4
  134. package/components/oxy-popup/oxy-popup.vue +35 -2
  135. package/components/oxy-popup/types.ts +8 -1
  136. package/components/oxy-progress/index.scss +3 -3
  137. package/components/oxy-qrcode/draw.ts +398 -0
  138. package/components/oxy-qrcode/index.scss +2 -0
  139. package/components/oxy-qrcode/oxy-qrcode.vue +124 -0
  140. package/components/oxy-qrcode/qrcode.ts +936 -0
  141. package/components/oxy-qrcode/types.ts +42 -0
  142. package/components/oxy-radio/index.scss +25 -19
  143. package/components/oxy-radio-group/index.scss +2 -2
  144. package/components/oxy-rate/types.ts +4 -4
  145. package/components/oxy-resize/index.scss +2 -2
  146. package/components/oxy-resize/oxy-resize.vue +4 -4
  147. package/components/oxy-resize/types.ts +3 -0
  148. package/components/oxy-rich-text/index.scss +37 -36
  149. package/components/oxy-rich-text/mp-html/card/card.vue +3 -3
  150. package/components/oxy-rich-text/mp-html/mp-html.vue +33 -24
  151. package/components/oxy-rich-text/mp-html/node/node.vue +30 -19
  152. package/components/oxy-rich-text/oxy-rich-text.vue +31 -31
  153. package/components/oxy-rich-text/types.ts +6 -1
  154. package/components/oxy-row/oxy-row.vue +3 -3
  155. package/components/oxy-row/types.ts +1 -1
  156. package/components/oxy-search/index.scss +7 -7
  157. package/components/oxy-segmented/index.scss +19 -16
  158. package/components/oxy-segmented/oxy-segmented.vue +23 -3
  159. package/components/oxy-select/index.scss +213 -89
  160. package/components/oxy-select/oxy-select.vue +106 -58
  161. package/components/oxy-select/types.ts +13 -1
  162. package/components/oxy-select-picker/index.scss +7 -7
  163. package/components/oxy-select-picker/oxy-select-picker.vue +1 -0
  164. package/components/oxy-select-picker/types.ts +2 -0
  165. package/components/oxy-sidebar-item/index.scss +2 -2
  166. package/components/oxy-signature/oxy-signature.vue +18 -10
  167. package/components/oxy-signature/types.ts +106 -13
  168. package/components/oxy-skeleton/index.scss +1 -1
  169. package/components/oxy-skeleton/oxy-skeleton.vue +6 -6
  170. package/components/oxy-skeleton/types.ts +1 -1
  171. package/components/oxy-slider/index.scss +6 -6
  172. package/components/oxy-sort-button/index.scss +8 -8
  173. package/components/oxy-splitter/index.scss +19 -0
  174. package/components/oxy-splitter/oxy-splitter.vue +409 -0
  175. package/components/oxy-splitter/types.ts +75 -0
  176. package/components/oxy-splitter-panel/index.scss +366 -0
  177. package/components/oxy-splitter-panel/oxy-splitter-panel.vue +432 -0
  178. package/components/oxy-splitter-panel/types.ts +63 -0
  179. package/components/oxy-status-tip/index.scss +4 -4
  180. package/components/oxy-status-tip/oxy-status-tip.vue +5 -5
  181. package/components/oxy-status-tip/types.ts +3 -3
  182. package/components/oxy-step/index.scss +16 -16
  183. package/components/oxy-sticky/oxy-sticky.vue +6 -6
  184. package/components/oxy-stream-render/oxy-stream-render.vue +230 -4
  185. package/components/oxy-stream-render/types.ts +4 -1
  186. package/components/oxy-swipe-action/oxy-swipe-action.vue +27 -2
  187. package/components/oxy-swiper/oxy-swiper.vue +6 -6
  188. package/components/oxy-swiper/types.ts +5 -5
  189. package/components/oxy-swiper-nav/index.scss +3 -3
  190. package/components/oxy-switch/index.scss +10 -10
  191. package/components/oxy-switch/oxy-switch.vue +2 -2
  192. package/components/oxy-switch/types.ts +1 -1
  193. package/components/oxy-tab/index.scss +11 -1
  194. package/components/oxy-tabbar/index.scss +2 -2
  195. package/components/oxy-tabbar/oxy-tabbar.vue +39 -10
  196. package/components/oxy-table/index.scss +8 -8
  197. package/components/oxy-table/oxy-table.vue +8 -6
  198. package/components/oxy-table/types.ts +2 -2
  199. package/components/oxy-table-col/index.scss +3 -3
  200. package/components/oxy-table-col/oxy-table-col.vue +3 -3
  201. package/components/oxy-table-col/types.ts +2 -2
  202. package/components/oxy-tabs/index.scss +52 -22
  203. package/components/oxy-tabs/oxy-tabs.vue +53 -19
  204. package/components/oxy-tabs/types.ts +15 -3
  205. package/components/oxy-tag/index.scss +111 -36
  206. package/components/oxy-text/index.scss +5 -1
  207. package/components/oxy-text/oxy-text.vue +76 -7
  208. package/components/oxy-text/types.ts +12 -0
  209. package/components/oxy-textarea/index.scss +6 -6
  210. package/components/oxy-toast/oxy-toast.vue +24 -8
  211. package/components/oxy-tooltip/index.scss +9 -9
  212. package/components/oxy-tree/index.scss +51 -15
  213. package/components/oxy-tree/oxy-tree.vue +13 -9
  214. package/components/oxy-tree/types.ts +12 -9
  215. package/components/oxy-upload/index.scss +23 -23
  216. package/components/oxy-upload/types.ts +2 -2
  217. package/components/oxy-verification-code/index.scss +6 -0
  218. package/components/oxy-verification-code/oxy-verification-code.vue +187 -0
  219. package/components/oxy-verification-code/types.ts +82 -0
  220. package/components/oxy-video-preview/index.scss +4 -4
  221. package/components/oxy-virtual-scroll/index.scss +5 -5
  222. package/components/oxy-virtual-scroll/oxy-virtual-scroll.vue +11 -7
  223. package/components/oxy-virtual-scroll/types.ts +14 -14
  224. package/components/oxy-voice-player/index.scss +937 -0
  225. package/components/oxy-voice-player/oxy-voice-player.vue +821 -0
  226. package/components/oxy-voice-player/types.ts +567 -0
  227. package/components/oxy-waterfall/oxy-waterfall.vue +6 -6
  228. package/components/oxy-waterfall/types.ts +6 -6
  229. package/components/oxy-watermark/oxy-watermark.vue +35 -13
  230. package/components/oxy-watermark/types.ts +14 -14
  231. package/global.d.ts +4 -0
  232. package/locale/lang/ar-SA.ts +3 -0
  233. package/locale/lang/en-US.ts +3 -0
  234. package/locale/lang/zh-CN.ts +3 -0
  235. package/package.json +97 -1
  236. package/tags.json +1 -1
  237. package/web-types.json +1 -1
  238. package/components/oxy-number-keyboard/index.scss +0 -78
  239. package/components/oxy-number-keyboard/key/index.scss +0 -81
  240. package/components/oxy-number-keyboard/key/index.vue +0 -78
  241. package/components/oxy-number-keyboard/key/types.ts +0 -11
  242. package/components/oxy-number-keyboard/oxy-number-keyboard.vue +0 -151
  243. package/components/oxy-number-keyboard/types.ts +0 -83
  244. package/components/oxy-tree/components/tree-node-content.vue +0 -72
  245. package/components/oxy-tree/index.ts +0 -51
  246. package/oxy-uni-ui.zip +0 -0
@@ -9,7 +9,7 @@
9
9
 
10
10
  @include e(label) {
11
11
  color: $-dark-color;
12
- background-color: rgba($color: $-dark-background2, $alpha: 0.5);
12
+ background-color: $-slider-dark-label-bg;
13
13
  }
14
14
 
15
15
  @include m(disabled) {
@@ -38,16 +38,16 @@
38
38
  font-size: $-slider-fs;
39
39
  line-height: 1.2;
40
40
  color: $-slider-color;
41
- background-color: rgba($color: #fff, $alpha: 0.5);
41
+ background-color: $-slider-label-bg;
42
42
  border-radius: 100%;
43
43
  position: absolute;
44
- bottom: calc($-slider-handle-radius * 2 + 8px);
44
+ bottom: calc($-slider-handle-radius * 2 + 16rpx);
45
45
  }
46
46
  @include e(bar-wrapper) {
47
47
  flex: 1;
48
48
  position: relative;
49
49
  border-radius: calc($-slider-axie-height / 2);
50
- background-color: #e5e5e5;
50
+ background-color: $-slider-axie-bg;
51
51
  margin: calc($-slider-handle-radius - $-slider-axie-height / 2) 0;
52
52
  }
53
53
  @include e(bar) {
@@ -70,7 +70,7 @@
70
70
  }
71
71
  }
72
72
  @include e(has-label) {
73
- padding-top: calc($-slider-fs * 1.2 + 8px);
73
+ padding-top: calc($-slider-fs * 1.2 + 16rpx);
74
74
  }
75
75
  @include e(button) {
76
76
  height: calc($-slider-handle-radius * 2);
@@ -79,7 +79,7 @@
79
79
  border-radius: 100%;
80
80
  border: 1px solid $-slider-axie-bg;
81
81
  box-sizing: border-box;
82
- box-shadow: 0 2px 4px 0 rgba($color: #9b9b9b, $alpha: 0.5);
82
+ box-shadow: 0 4rpx 8rpx 0 $-slider-button-shadow-color;
83
83
  }
84
84
  @include e(label-min) {
85
85
  margin-right: calc($-slider-handle-radius * 2);
@@ -20,9 +20,9 @@
20
20
  &::after {
21
21
  position: absolute;
22
22
  content: '';
23
- width: 19px;
24
- height: 3px;
25
- bottom: 6px;
23
+ width: 38rpx;
24
+ height: 6rpx;
25
+ bottom: 12rpx;
26
26
  left: 50%;
27
27
  transform: translate(-50%, 0);
28
28
  background: $-sort-button-line-color;
@@ -61,8 +61,8 @@
61
61
 
62
62
  @include e(right) {
63
63
  display: inline-block;
64
- min-width: 14px;
65
- margin-left: 2px;
64
+ min-width: 28rpx;
65
+ margin-left: 4rpx;
66
66
  vertical-align: middle;
67
67
  line-height: 1.1;
68
68
 
@@ -78,12 +78,12 @@
78
78
  @include edeep(icon-up) {
79
79
  display: block !important;
80
80
  line-height: 1.1;
81
- transform: scale(calc((10 / 14))) translate(0, 7px);
81
+ transform: scale(calc((10 / 14))) translate(0, 14rpx);
82
82
  }
83
83
 
84
84
  @include edeep(icon-down) {
85
85
  display: block !important;
86
86
  line-height: 1.1;
87
- transform: scale(calc((10 / 14))) translate(0, -7px);
87
+ transform: scale(calc((10 / 14))) translate(0, -14rpx);
88
88
  }
89
- }
89
+ }
@@ -0,0 +1,19 @@
1
+ @import './../common/abstracts/_mixin.scss';
2
+ @import './../common/abstracts/variable.scss';
3
+
4
+ @include b(splitter) {
5
+ position: relative;
6
+ display: flex;
7
+ width: 100%;
8
+ height: 100%;
9
+ overflow: hidden;
10
+ box-sizing: border-box;
11
+
12
+ @include m(horizontal) {
13
+ flex-direction: row;
14
+ }
15
+
16
+ @include m(vertical) {
17
+ flex-direction: column;
18
+ }
19
+ }
@@ -0,0 +1,409 @@
1
+ <template>
2
+ <view :id="splitterId" :class="rootClass" :style="customStyle">
3
+ <slot />
4
+ </view>
5
+ </template>
6
+
7
+ <script lang="ts">
8
+ export default {
9
+ name: 'oxy-splitter',
10
+ options: {
11
+ addGlobalClass: true,
12
+ virtualHost: true,
13
+ styleIsolation: 'shared'
14
+ }
15
+ }
16
+ </script>
17
+
18
+ <script lang="ts" setup>
19
+ import { computed, getCurrentInstance, nextTick, onMounted, onUnmounted, provide, ref, watch } from 'vue'
20
+ import { getRect, isDef, isNumber, isString, unitConvert, uuid } from '../common/util'
21
+ import { SPLITTER_KEY, splitterProps, type SplitterCollapseType, type SplitterPanelSize, type SplitterPanelState, type SplitterExpose } from './types'
22
+
23
+ const props = defineProps(splitterProps)
24
+ const emit = defineEmits(['resize-start', 'resize', 'resize-end', 'collapse'])
25
+
26
+ const { proxy } = getCurrentInstance() as any
27
+
28
+ const splitterId = ref<string>(`splitter-${uuid()}`)
29
+ const containerSize = ref<number>(0)
30
+ const panels = ref<SplitterPanelState[]>([])
31
+ const percentSizes = ref<number[]>([])
32
+ const movingIndex = ref<number>(-1)
33
+ const lazyOffset = ref<number>(0)
34
+
35
+ const cacheSizes = ref<number[]>([])
36
+ const cacheCollapsedSize = ref<number[]>([])
37
+ const confirmedMovingIndex = ref<number>(-1)
38
+
39
+ const rootClass = computed(() => `oxy-splitter oxy-splitter--${props.layout} ${props.customClass}`)
40
+
41
+ const pxSizes = computed(() => {
42
+ return percentSizes.value.map((item) => item * containerSize.value)
43
+ })
44
+
45
+ const getContainerSize = () => containerSize.value
46
+
47
+ const isPercentSize = (size: SplitterPanelSize | undefined): size is string => isString(size) && size.trim().endsWith('%')
48
+
49
+ const getPercentValue = (size: string) => {
50
+ const value = Number.parseFloat(size)
51
+ return Number.isFinite(value) ? value / 100 : 0
52
+ }
53
+
54
+ const getPixelValue = (size: SplitterPanelSize) => {
55
+ return unitConvert(size, containerSize.value)
56
+ }
57
+
58
+ const normalizePanelPercent = (size?: SplitterPanelSize) => {
59
+ if (!isDef(size)) {
60
+ return undefined
61
+ }
62
+
63
+ if (!containerSize.value) {
64
+ return undefined
65
+ }
66
+
67
+ if (isPercentSize(size)) {
68
+ return getPercentValue(size)
69
+ }
70
+
71
+ return getPixelValue(size) / containerSize.value
72
+ }
73
+
74
+ const normalizePercentList = (percentList: Array<number | undefined>) => {
75
+ const list = [...percentList]
76
+ const undefinedCount = list.filter((item) => !isDef(item)).length
77
+ const definedTotal = list.reduce<number>((total, item) => total + (item ?? 0), 0)
78
+
79
+ if (definedTotal > 1 || undefinedCount === 0) {
80
+ const total = list.reduce<number>((sum, item) => sum + (item ?? 0), 0)
81
+ if (total > 0) {
82
+ return list.map((item) => (item ?? 0) / total)
83
+ }
84
+
85
+ const equal = list.length ? 1 / list.length : 0
86
+ return list.map(() => equal)
87
+ }
88
+
89
+ const fill = undefinedCount ? (1 - definedTotal) / undefinedCount : 0
90
+ return list.map((item) => (isDef(item) ? item : fill))
91
+ }
92
+
93
+ const syncPercentSizes = () => {
94
+ if (!panels.value.length) {
95
+ percentSizes.value = []
96
+ return
97
+ }
98
+
99
+ if (!containerSize.value) {
100
+ const equal = 1 / panels.value.length
101
+ percentSizes.value = panels.value.map(() => equal)
102
+ return
103
+ }
104
+
105
+ const rawPercent = panels.value.map((panel) => normalizePanelPercent(panel.size))
106
+ percentSizes.value = normalizePercentList(rawPercent)
107
+ }
108
+
109
+ const getPanelSize = (index: number) => {
110
+ return pxSizes.value[index] || 0
111
+ }
112
+
113
+ const toPx = (value: SplitterPanelSize | undefined, defaultValue: number) => {
114
+ if (!isDef(value)) {
115
+ return defaultValue
116
+ }
117
+
118
+ if (isPercentSize(value)) {
119
+ return getPercentValue(value) * containerSize.value
120
+ }
121
+
122
+ return getPixelValue(value)
123
+ }
124
+
125
+ const getLimitSize = (size: SplitterPanelSize | undefined, defaultValue: number) => {
126
+ if (!containerSize.value) {
127
+ return defaultValue
128
+ }
129
+ return toPx(size, defaultValue)
130
+ }
131
+
132
+ const clamp = (value: number, min: number, max: number) => {
133
+ return Math.min(Math.max(value, min), max)
134
+ }
135
+
136
+ const isDraggable = (index: number) => {
137
+ const panel = panels.value[index]
138
+ const nextPanel = panels.value[index + 1]
139
+ return Boolean(panel?.resizable && nextPanel?.resizable)
140
+ }
141
+
142
+ const registerPanel = (panel: SplitterPanelState) => {
143
+ panels.value.push(panel)
144
+ nextTick(syncPercentSizes)
145
+ }
146
+
147
+ const unregisterPanel = (uid: number) => {
148
+ const index = panels.value.findIndex((item) => item.uid === uid)
149
+ if (index < 0) {
150
+ return
151
+ }
152
+ panels.value.splice(index, 1)
153
+ nextTick(syncPercentSizes)
154
+ }
155
+
156
+ const updatePanel = (uid: number, patch: Partial<SplitterPanelState>) => {
157
+ const panel = panels.value.find((item) => item.uid === uid)
158
+ if (!panel) {
159
+ return
160
+ }
161
+ Object.assign(panel, patch)
162
+ nextTick(syncPercentSizes)
163
+ }
164
+
165
+ const getPanelIndex = (uid: number) => {
166
+ return panels.value.findIndex((item) => item.uid === uid)
167
+ }
168
+
169
+ const movePanelSize = (index: number, offset: number) => {
170
+ const panel = panels.value[index]
171
+ const nextPanel = panels.value[index + 1]
172
+ if (!panel || !nextPanel) {
173
+ return
174
+ }
175
+
176
+ const panelSize = cacheSizes.value[index] || 0
177
+ const nextSize = cacheSizes.value[index + 1] || 0
178
+ const panelMin = getLimitSize(panel.min, 0)
179
+ const panelMax = getLimitSize(panel.max, Number.MAX_SAFE_INTEGER)
180
+ const nextMin = getLimitSize(nextPanel.min, 0)
181
+ const nextMax = getLimitSize(nextPanel.max, Number.MAX_SAFE_INTEGER)
182
+
183
+ const minOffset = -Math.min(panelSize - panelMin, nextMax - nextSize)
184
+ const maxOffset = Math.min(nextSize - nextMin, panelMax - panelSize)
185
+ const mergedOffset = clamp(offset, minOffset, maxOffset)
186
+
187
+ const nextPanelSize = nextSize - mergedOffset
188
+ panel.size = panelSize + mergedOffset
189
+ nextPanel.size = nextPanelSize
190
+
191
+ syncPercentSizes()
192
+ emit('resize', index, [panel.size, nextPanel.size])
193
+ }
194
+
195
+ const onMoveStart = (index: number) => {
196
+ cacheSizes.value = [...pxSizes.value]
197
+ confirmedMovingIndex.value = -1
198
+ movingIndex.value = index
199
+ lazyOffset.value = 0
200
+ emit('resize-start', index)
201
+ }
202
+
203
+ const onMoving = (index: number, offset: number) => {
204
+ if (movingIndex.value < 0) {
205
+ return
206
+ }
207
+
208
+ const currentPanelSize = getPanelSize(index)
209
+ const nextPanelSize = getPanelSize(index + 1)
210
+
211
+ if (confirmedMovingIndex.value === -1) {
212
+ const isCurrentZero = currentPanelSize === 0
213
+ const isNextZero = nextPanelSize === 0
214
+ if (isCurrentZero || isNextZero) {
215
+ confirmedMovingIndex.value = isCurrentZero ? index - 1 : index + 1
216
+ cacheSizes.value = [...pxSizes.value]
217
+ } else {
218
+ confirmedMovingIndex.value = index
219
+ }
220
+ }
221
+
222
+ const mergedIndex = confirmedMovingIndex.value
223
+ if (mergedIndex < 0) {
224
+ return
225
+ }
226
+
227
+ if (props.lazy) {
228
+ lazyOffset.value = offset
229
+ return
230
+ }
231
+
232
+ movePanelSize(mergedIndex, offset)
233
+ }
234
+
235
+ const onMoveEnd = (index: number) => {
236
+ if (movingIndex.value < 0) {
237
+ return
238
+ }
239
+
240
+ if (props.lazy) {
241
+ movePanelSize(confirmedMovingIndex.value > -1 ? confirmedMovingIndex.value : index, lazyOffset.value)
242
+ }
243
+
244
+ lazyOffset.value = 0
245
+ movingIndex.value = -1
246
+ confirmedMovingIndex.value = -1
247
+ cacheSizes.value = []
248
+ emit('resize-end', index)
249
+ }
250
+
251
+ const onCollapse = (index: number, type: SplitterCollapseType) => {
252
+ const panel = panels.value[index]
253
+ const nextPanel = panels.value[index + 1]
254
+ if (!panel || !nextPanel) {
255
+ return
256
+ }
257
+
258
+ const panelSize = getPanelSize(index)
259
+ const nextPanelSize = getPanelSize(index + 1)
260
+ const panelCollapsed = panelSize === 0
261
+ const nextPanelCollapsed = nextPanelSize === 0
262
+
263
+ // 交互约定:
264
+ // 只要任一侧已折叠,点击任意折叠按钮都优先执行“还原已折叠侧”
265
+ if (panelCollapsed || nextPanelCollapsed) {
266
+ if (panelCollapsed) {
267
+ const panelMin = getLimitSize(panel.min, 0)
268
+ const panelMax = getLimitSize(panel.max, Number.MAX_SAFE_INTEGER)
269
+ const cached = cacheCollapsedSize.value[index]
270
+ const fallback = panelMin > 0 ? panelMin : nextPanelSize / 2
271
+ const restore = clamp(cached || fallback, panelMin, Math.min(panelMax, nextPanelSize))
272
+
273
+ if (restore > 0) {
274
+ panel.size = restore
275
+ nextPanel.size = nextPanelSize - restore
276
+ }
277
+ } else {
278
+ const nextMin = getLimitSize(nextPanel.min, 0)
279
+ const nextMax = getLimitSize(nextPanel.max, Number.MAX_SAFE_INTEGER)
280
+ const cached = cacheCollapsedSize.value[index]
281
+ const fallback = nextMin > 0 ? nextMin : panelSize / 2
282
+ const restore = clamp(cached || fallback, nextMin, Math.min(nextMax, panelSize))
283
+
284
+ if (restore > 0) {
285
+ panel.size = panelSize - restore
286
+ nextPanel.size = restore
287
+ }
288
+ }
289
+
290
+ syncPercentSizes()
291
+ emit('collapse', index, type)
292
+ return
293
+ }
294
+
295
+ const isStart = type === 'start'
296
+ const collapseSize = isStart ? panelSize : nextPanelSize
297
+ const expandSize = isStart ? nextPanelSize : panelSize
298
+ const collapsed = collapseSize === 0
299
+
300
+ if (!collapsed) {
301
+ cacheCollapsedSize.value[index] = collapseSize
302
+ }
303
+
304
+ if (collapsed) {
305
+ const mergedSize = cacheCollapsedSize.value[index] || 0
306
+ const targetSize = getLimitSize(isStart ? panel.max : nextPanel.max, Number.MAX_SAFE_INTEGER)
307
+
308
+ if (targetSize <= mergedSize) {
309
+ return
310
+ }
311
+
312
+ if (expandSize < mergedSize) {
313
+ return
314
+ }
315
+
316
+ if (isStart) {
317
+ panel.size = mergedSize
318
+ nextPanel.size = expandSize - mergedSize
319
+ } else {
320
+ panel.size = expandSize - mergedSize
321
+ nextPanel.size = mergedSize
322
+ }
323
+ } else {
324
+ if (isStart) {
325
+ panel.size = 0
326
+ nextPanel.size = expandSize + collapseSize
327
+ } else {
328
+ panel.size = expandSize + collapseSize
329
+ nextPanel.size = 0
330
+ }
331
+ }
332
+
333
+ syncPercentSizes()
334
+ emit('collapse', index, type)
335
+ }
336
+
337
+ const refresh = async () => {
338
+ try {
339
+ const rect = await getRect(`#${splitterId.value}`, false, proxy)
340
+ const nextSize = props.layout === 'horizontal' ? Number(rect.width) : Number(rect.height)
341
+ if (isNumber(nextSize) && Number.isFinite(nextSize) && nextSize > 0) {
342
+ containerSize.value = nextSize
343
+ syncPercentSizes()
344
+ }
345
+ } catch (error) {
346
+ // empty
347
+ }
348
+ }
349
+
350
+ const onWindowResize = () => {
351
+ refresh()
352
+ }
353
+
354
+ watch(
355
+ () => panels.value.length,
356
+ () => {
357
+ nextTick(refresh)
358
+ }
359
+ )
360
+
361
+ watch(
362
+ () => props.layout,
363
+ () => {
364
+ nextTick(refresh)
365
+ }
366
+ )
367
+
368
+ provide(SPLITTER_KEY, {
369
+ layout: computed(() => props.layout),
370
+ lazy: computed(() => props.lazy),
371
+ panels,
372
+ pxSizes,
373
+ movingIndex,
374
+ lazyOffset,
375
+ registerPanel,
376
+ unregisterPanel,
377
+ updatePanel,
378
+ getPanelIndex,
379
+ getPanelSize,
380
+ getContainerSize,
381
+ isDraggable,
382
+ onMoveStart,
383
+ onMoving,
384
+ onMoveEnd,
385
+ onCollapse,
386
+ refresh
387
+ })
388
+
389
+ onMounted(() => {
390
+ nextTick(refresh)
391
+ // #ifdef H5
392
+ window.addEventListener('resize', onWindowResize)
393
+ // #endif
394
+ })
395
+
396
+ onUnmounted(() => {
397
+ // #ifdef H5
398
+ window.removeEventListener('resize', onWindowResize)
399
+ // #endif
400
+ })
401
+
402
+ defineExpose<SplitterExpose>({
403
+ refresh
404
+ })
405
+ </script>
406
+
407
+ <style lang="scss" scoped>
408
+ @import './index.scss';
409
+ </style>
@@ -0,0 +1,75 @@
1
+ import type { ComputedRef, ComponentPublicInstance, ExtractPropTypes, InjectionKey, Ref } from 'vue'
2
+ import { baseProps, makeBooleanProp, makeStringProp } from '../common/props'
3
+
4
+ export type SplitterLayout = 'horizontal' | 'vertical'
5
+
6
+ export type SplitterPanelSize = number | string
7
+
8
+ export type SplitterCollapsible = boolean
9
+
10
+ export type SplitterCollapseType = 'start' | 'end'
11
+
12
+ export type SplitterPanelState = {
13
+ /** panel 唯一标识 */
14
+ uid: number
15
+ /** 当前 size,支持 number(px) / string(px|rpx|%) */
16
+ size?: SplitterPanelSize
17
+ /** 最小尺寸 */
18
+ min?: SplitterPanelSize
19
+ /** 最大尺寸 */
20
+ max?: SplitterPanelSize
21
+ /** 是否允许拖拽 */
22
+ resizable: boolean
23
+ /** 是否支持折叠 */
24
+ collapsible: SplitterCollapsible
25
+ }
26
+
27
+ export type SplitterProvide = {
28
+ layout: ComputedRef<SplitterLayout>
29
+ lazy: ComputedRef<boolean>
30
+ panels: Ref<SplitterPanelState[]>
31
+ pxSizes: ComputedRef<number[]>
32
+ movingIndex: Ref<number>
33
+ lazyOffset: Ref<number>
34
+ registerPanel: (panel: SplitterPanelState) => void
35
+ unregisterPanel: (uid: number) => void
36
+ updatePanel: (uid: number, patch: Partial<SplitterPanelState>) => void
37
+ getPanelIndex: (uid: number) => number
38
+ getPanelSize: (index: number) => number
39
+ getContainerSize: () => number
40
+ isDraggable: (index: number) => boolean
41
+ onMoveStart: (index: number) => void
42
+ onMoving: (index: number, offset: number) => void
43
+ onMoveEnd: (index: number) => void
44
+ onCollapse: (index: number, type: SplitterCollapseType) => void
45
+ refresh: () => void
46
+ }
47
+
48
+ export const SPLITTER_KEY: InjectionKey<SplitterProvide> = Symbol('oxy-splitter')
49
+
50
+ export const splitterProps = {
51
+ ...baseProps,
52
+
53
+ /**
54
+ * 分隔方向
55
+ * `horizontal` 为左右布局,`vertical` 为上下布局
56
+ */
57
+ layout: makeStringProp<SplitterLayout>('horizontal'),
58
+
59
+ /**
60
+ * 是否启用懒更新
61
+ * 拖拽中仅更新分割线,松手后再提交尺寸
62
+ */
63
+ lazy: makeBooleanProp(false)
64
+ }
65
+
66
+ export type SplitterProps = ExtractPropTypes<typeof splitterProps>
67
+
68
+ export type SplitterExpose = {
69
+ /**
70
+ * 手动刷新尺寸(例如在 popup 打开后调用)
71
+ */
72
+ refresh: () => void
73
+ }
74
+
75
+ export type SplitterInstance = ComponentPublicInstance<SplitterProps, SplitterExpose>