oxy-uni-ui 2.0.0 → 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 (75) hide show
  1. package/attributes.json +1 -1
  2. package/components/common/abstracts/variable.scss +338 -194
  3. package/components/composables/useVirtualScroll.ts +40 -14
  4. package/components/oxy-action-sheet/index.scss +3 -3
  5. package/components/oxy-backtop/index.scss +2 -2
  6. package/components/oxy-button/index.scss +2 -2
  7. package/components/oxy-calendar/index.scss +9 -9
  8. package/components/oxy-calendar-view/monthPanel/index.scss +4 -5
  9. package/components/oxy-calendar-view/year/index.scss +1 -1
  10. package/components/oxy-calendar-view/yearPanel/index.scss +3 -3
  11. package/components/oxy-cell/index.scss +1 -1
  12. package/components/oxy-checkbox/index.scss +9 -9
  13. package/components/oxy-checkbox-group/index.scss +2 -2
  14. package/components/oxy-col-picker/index.scss +3 -3
  15. package/components/oxy-corner/index.scss +1 -1
  16. package/components/oxy-datetime-picker/index.scss +5 -5
  17. package/components/oxy-drop-menu/index.scss +3 -3
  18. package/components/oxy-drop-menu-item/index.scss +2 -2
  19. package/components/oxy-file-list/index.scss +20 -20
  20. package/components/oxy-guidance/index.scss +13 -13
  21. package/components/oxy-img-cropper/index.scss +14 -14
  22. package/components/oxy-index-anchor/index.scss +2 -2
  23. package/components/oxy-index-bar/index.scss +3 -3
  24. package/components/oxy-input/index.scss +1 -1
  25. package/components/oxy-keyboard/index.scss +2 -2
  26. package/components/oxy-long-press-menu/index.scss +2 -2
  27. package/components/oxy-message-box/index.scss +7 -7
  28. package/components/oxy-message-box/oxy-message-box.vue +4 -5
  29. package/components/oxy-message-box/types.ts +0 -5
  30. package/components/oxy-pagination/index.scss +5 -4
  31. package/components/oxy-picker/index.scss +14 -14
  32. package/components/oxy-picker-view/index.scss +2 -2
  33. package/components/oxy-popover/index.scss +8 -8
  34. package/components/oxy-popup/index.scss +4 -4
  35. package/components/oxy-progress/index.scss +1 -1
  36. package/components/oxy-radio/index.scss +20 -14
  37. package/components/oxy-radio-group/index.scss +2 -2
  38. package/components/oxy-rich-text/index.scss +18 -18
  39. package/components/oxy-rich-text/mp-html/card/card.vue +3 -3
  40. package/components/oxy-rich-text/mp-html/mp-html.vue +4 -4
  41. package/components/oxy-rich-text/mp-html/node/node.vue +2 -2
  42. package/components/oxy-rich-text/oxy-rich-text.vue +8 -8
  43. package/components/oxy-search/index.scss +5 -5
  44. package/components/oxy-segmented/index.scss +13 -10
  45. package/components/oxy-select/index.scss +116 -68
  46. package/components/oxy-select/oxy-select.vue +24 -11
  47. package/components/oxy-select-picker/index.scss +2 -2
  48. package/components/oxy-sidebar-item/index.scss +2 -2
  49. package/components/oxy-skeleton/index.scss +1 -1
  50. package/components/oxy-slider/index.scss +4 -4
  51. package/components/oxy-splitter/index.scss +19 -0
  52. package/components/oxy-splitter/oxy-splitter.vue +409 -0
  53. package/components/oxy-splitter/types.ts +75 -0
  54. package/components/oxy-splitter-panel/index.scss +366 -0
  55. package/components/oxy-splitter-panel/oxy-splitter-panel.vue +432 -0
  56. package/components/oxy-splitter-panel/types.ts +63 -0
  57. package/components/oxy-step/index.scss +5 -5
  58. package/components/oxy-stream-render/oxy-stream-render.vue +230 -4
  59. package/components/oxy-swiper-nav/index.scss +3 -3
  60. package/components/oxy-switch/index.scss +2 -2
  61. package/components/oxy-tabbar/index.scss +2 -2
  62. package/components/oxy-table/index.scss +5 -5
  63. package/components/oxy-table-col/index.scss +3 -3
  64. package/components/oxy-tabs/index.scss +14 -12
  65. package/components/oxy-tag/index.scss +111 -36
  66. package/components/oxy-textarea/index.scss +3 -3
  67. package/components/oxy-tooltip/index.scss +1 -1
  68. package/components/oxy-tree/index.scss +4 -4
  69. package/components/oxy-upload/index.scss +17 -17
  70. package/components/oxy-virtual-scroll/index.scss +1 -1
  71. package/components/oxy-voice-player/index.scss +68 -39
  72. package/global.d.ts +2 -0
  73. package/package.json +1 -1
  74. package/tags.json +1 -1
  75. package/web-types.json +1 -1
@@ -0,0 +1,432 @@
1
+ <template>
2
+ <view class="oxy-splitter-panel" :style="panelStyle">
3
+ <view class="oxy-splitter-panel__content">
4
+ <slot />
5
+ </view>
6
+ </view>
7
+ <view
8
+ v-if="showBar"
9
+ :class="barClass"
10
+ :style="barStyle"
11
+ @touchstart.stop="onTouchStart"
12
+ @touchmove="onTouchMove"
13
+ @touchend="onTouchEnd"
14
+ @touchcancel="onTouchEnd"
15
+ @mousedown.stop.prevent="onMouseDown"
16
+ >
17
+ <view v-if="isBarDraggable" class="oxy-splitter-panel__grip" />
18
+
19
+ <view v-if="showActionGroup" class="oxy-splitter-panel__action-group" @touchstart.stop="noop" @mousedown.stop="noop">
20
+ <view class="oxy-splitter-panel__action-segment oxy-splitter-panel__action-segment--start" @tap.stop="onCollapse('start')">
21
+ <slot name="start-collapsible">
22
+ <oxy-icon :name="startIconName" size="24rpx" custom-class="oxy-splitter-panel__icon"></oxy-icon>
23
+ </slot>
24
+ </view>
25
+ <view class="oxy-splitter-panel__action-separator"></view>
26
+ <view class="oxy-splitter-panel__action-segment oxy-splitter-panel__action-segment--end" @tap.stop="onCollapse('end')">
27
+ <slot name="end-collapsible">
28
+ <oxy-icon :name="endIconName" size="24rpx" custom-class="oxy-splitter-panel__icon"></oxy-icon>
29
+ </slot>
30
+ </view>
31
+ </view>
32
+
33
+ <view
34
+ v-if="showSingleStartAction"
35
+ class="oxy-splitter-panel__action oxy-splitter-panel__action--start"
36
+ @tap.stop="onCollapse('start')"
37
+ @touchstart.stop="noop"
38
+ @mousedown.stop="noop"
39
+ >
40
+ <slot name="start-collapsible">
41
+ <oxy-icon :name="startIconName" size="24rpx" custom-class="oxy-splitter-panel__icon"></oxy-icon>
42
+ </slot>
43
+ </view>
44
+
45
+ <view
46
+ v-if="showSingleEndAction"
47
+ class="oxy-splitter-panel__action oxy-splitter-panel__action--end"
48
+ @tap.stop="onCollapse('end')"
49
+ @touchstart.stop="noop"
50
+ @mousedown.stop="noop"
51
+ >
52
+ <slot name="end-collapsible">
53
+ <oxy-icon :name="endIconName" size="24rpx" custom-class="oxy-splitter-panel__icon"></oxy-icon>
54
+ </slot>
55
+ </view>
56
+ </view>
57
+ </template>
58
+
59
+ <script lang="ts">
60
+ export default {
61
+ name: 'oxy-splitter-panel',
62
+ options: {
63
+ addGlobalClass: true,
64
+ virtualHost: true,
65
+ styleIsolation: 'shared'
66
+ }
67
+ }
68
+ </script>
69
+
70
+ <script lang="ts" setup>
71
+ import OxyIcon from '../oxy-icon/oxy-icon.vue'
72
+ import { computed, getCurrentInstance, inject, onMounted, onUnmounted, ref, watch } from 'vue'
73
+ import { isDef, objToStyle, unitConvert } from '../common/util'
74
+ import { useTouch } from '../composables/useTouch'
75
+ import { SPLITTER_KEY, type SplitterCollapseType } from '../oxy-splitter/types'
76
+ import { splitterPanelProps, type SplitterPanelEmits, type SplitterPanelExpose } from './types'
77
+
78
+ const props = defineProps(splitterPanelProps)
79
+ const emit = defineEmits<SplitterPanelEmits>()
80
+
81
+ const splitter = inject(SPLITTER_KEY, null)
82
+ const { uid } = getCurrentInstance()!
83
+
84
+ const startPosition = ref(0)
85
+ const dragging = ref(false)
86
+ const touchPending = ref(false)
87
+ const touch = useTouch()
88
+
89
+ const TOUCH_DRAG_SLOP = 6
90
+
91
+ const noop = () => {}
92
+
93
+ const syncPanelState = () => {
94
+ splitter?.updatePanel(uid, {
95
+ size: props.size,
96
+ min: props.min,
97
+ max: props.max,
98
+ resizable: props.resizable,
99
+ collapsible: props.collapsible
100
+ })
101
+ }
102
+
103
+ onMounted(() => {
104
+ splitter?.registerPanel({
105
+ uid,
106
+ size: props.size,
107
+ min: props.min,
108
+ max: props.max,
109
+ resizable: props.resizable,
110
+ collapsible: props.collapsible
111
+ })
112
+ splitter?.refresh()
113
+ })
114
+
115
+ onUnmounted(() => {
116
+ splitter?.unregisterPanel(uid)
117
+ })
118
+
119
+ watch(
120
+ () => [props.size, props.min, props.max, props.resizable, props.collapsible],
121
+ () => {
122
+ syncPanelState()
123
+ },
124
+ { deep: true }
125
+ )
126
+
127
+ const index = computed(() => {
128
+ return splitter ? splitter.getPanelIndex(uid) : -1
129
+ })
130
+
131
+ const panelSize = computed(() => {
132
+ if (!splitter || index.value < 0) {
133
+ return 0
134
+ }
135
+ return splitter.getPanelSize(index.value)
136
+ })
137
+
138
+ const showBar = computed(() => {
139
+ if (!splitter || index.value < 0) {
140
+ return false
141
+ }
142
+ return index.value < splitter.panels.value.length - 1
143
+ })
144
+
145
+ const currentPanel = computed(() => {
146
+ if (!splitter || index.value < 0) {
147
+ return undefined
148
+ }
149
+ return splitter.panels.value[index.value]
150
+ })
151
+
152
+ const nextPanel = computed(() => {
153
+ if (!splitter || index.value < 0) {
154
+ return undefined
155
+ }
156
+ return splitter.panels.value[index.value + 1]
157
+ })
158
+
159
+ const startCollapsible = computed(() => {
160
+ return Boolean(currentPanel.value?.collapsible)
161
+ })
162
+
163
+ const endCollapsible = computed(() => {
164
+ return Boolean(nextPanel.value?.collapsible)
165
+ })
166
+
167
+ const nextPanelSize = computed(() => {
168
+ if (!splitter || index.value < 0) {
169
+ return 0
170
+ }
171
+ return splitter.getPanelSize(index.value + 1)
172
+ })
173
+
174
+ const isVertical = computed(() => splitter?.layout.value === 'vertical')
175
+ const panelCollapsed = computed(() => panelSize.value === 0)
176
+ const nextPanelCollapsed = computed(() => nextPanelSize.value === 0)
177
+
178
+ const startIconName = computed(() => {
179
+ const isSingleStartCollapsed = showSingleStartAction.value && panelCollapsed.value
180
+ if (isVertical.value) {
181
+ return isSingleStartCollapsed ? 'arrow-down' : 'arrow-up'
182
+ }
183
+ return isSingleStartCollapsed ? 'arrow-right' : 'arrow-left'
184
+ })
185
+
186
+ const endIconName = computed(() => {
187
+ const isSingleEndCollapsed = showSingleEndAction.value && nextPanelCollapsed.value
188
+ if (isVertical.value) {
189
+ return isSingleEndCollapsed ? 'arrow-up' : 'arrow-down'
190
+ }
191
+ return isSingleEndCollapsed ? 'arrow-left' : 'arrow-right'
192
+ })
193
+
194
+ const panelStyle = computed(() => {
195
+ if (!splitter || index.value < 0) {
196
+ return ''
197
+ }
198
+
199
+ const style: Record<string, string> = {
200
+ 'flex-grow': '0',
201
+ 'flex-shrink': '0'
202
+ }
203
+
204
+ if (splitter.layout.value === 'horizontal') {
205
+ style.width = `${panelSize.value}px`
206
+ style.height = '100%'
207
+ } else {
208
+ style.height = `${panelSize.value}px`
209
+ style.width = '100%'
210
+ }
211
+
212
+ return objToStyle(style)
213
+ })
214
+
215
+ const barClass = computed(() => {
216
+ const draggable = splitter ? splitter.isDraggable(index.value) : false
217
+ const moving = splitter ? splitter.movingIndex.value === index.value : false
218
+ return [
219
+ 'oxy-splitter-panel__bar',
220
+ `oxy-splitter-panel__bar--${splitter?.layout.value || 'horizontal'}`,
221
+ draggable ? 'is-draggable' : 'is-static',
222
+ showCollapseAction.value ? 'has-action' : '',
223
+ hasDoubleAction.value ? 'has-double-action' : '',
224
+ moving ? 'is-moving' : ''
225
+ ]
226
+ .filter(Boolean)
227
+ .join(' ')
228
+ })
229
+
230
+ const isBarDraggable = computed(() => {
231
+ return splitter ? splitter.isDraggable(index.value) : false
232
+ })
233
+
234
+ const hasDoubleAction = computed(() => {
235
+ return startCollapsible.value && endCollapsible.value
236
+ })
237
+
238
+ const actionDenseThreshold = computed(() => {
239
+ return unitConvert(hasDoubleAction.value ? '104rpx' : '76rpx')
240
+ })
241
+
242
+ const hideCollapseActionByDensity = computed(() => {
243
+ if (!splitter || index.value < 0) {
244
+ return false
245
+ }
246
+
247
+ if (!startCollapsible.value && !endCollapsible.value) {
248
+ return false
249
+ }
250
+
251
+ // 已折叠状态必须保留还原入口,避免交互“锁死”
252
+ if (panelSize.value === 0 || nextPanelSize.value === 0) {
253
+ return false
254
+ }
255
+
256
+ return Math.min(panelSize.value, nextPanelSize.value) < actionDenseThreshold.value
257
+ })
258
+
259
+ const showCollapseAction = computed(() => {
260
+ return (startCollapsible.value || endCollapsible.value) && !hideCollapseActionByDensity.value
261
+ })
262
+
263
+ const showActionGroup = computed(() => {
264
+ return showCollapseAction.value && hasDoubleAction.value
265
+ })
266
+
267
+ const showSingleStartAction = computed(() => {
268
+ return showCollapseAction.value && startCollapsible.value && !endCollapsible.value
269
+ })
270
+
271
+ const showSingleEndAction = computed(() => {
272
+ return showCollapseAction.value && endCollapsible.value && !startCollapsible.value
273
+ })
274
+
275
+ const barStyle = computed(() => {
276
+ if (!splitter || !splitter.lazy.value) {
277
+ return ''
278
+ }
279
+
280
+ if (splitter.movingIndex.value !== index.value) {
281
+ return ''
282
+ }
283
+
284
+ const offset = splitter.lazyOffset.value
285
+ if (!offset) {
286
+ return ''
287
+ }
288
+
289
+ if (splitter.layout.value === 'horizontal') {
290
+ return `transform: translateX(${offset}px);`
291
+ }
292
+
293
+ return `transform: translateY(${offset}px);`
294
+ })
295
+
296
+ const getClientPosition = (event: any) => {
297
+ if (event?.touches && event.touches[0]) {
298
+ return splitter?.layout.value === 'horizontal' ? event.touches[0].clientX : event.touches[0].clientY
299
+ }
300
+
301
+ if (event?.changedTouches && event.changedTouches[0]) {
302
+ return splitter?.layout.value === 'horizontal' ? event.changedTouches[0].clientX : event.changedTouches[0].clientY
303
+ }
304
+
305
+ if (isDef(event?.clientX) && isDef(event?.clientY)) {
306
+ return splitter?.layout.value === 'horizontal' ? event.clientX : event.clientY
307
+ }
308
+
309
+ return 0
310
+ }
311
+
312
+ const startMove = (position: number) => {
313
+ if (!splitter || index.value < 0 || !splitter.isDraggable(index.value)) {
314
+ return
315
+ }
316
+
317
+ dragging.value = true
318
+ startPosition.value = position
319
+ splitter.onMoveStart(index.value)
320
+ }
321
+
322
+ const move = (position: number) => {
323
+ if (!splitter || !dragging.value || index.value < 0) {
324
+ return
325
+ }
326
+
327
+ const offset = position - startPosition.value
328
+ splitter.onMoving(index.value, offset)
329
+ }
330
+
331
+ const endMove = () => {
332
+ if (!splitter || !dragging.value || index.value < 0) {
333
+ return
334
+ }
335
+
336
+ dragging.value = false
337
+ splitter.onMoveEnd(index.value)
338
+ }
339
+
340
+ const onTouchStart = (event: any) => {
341
+ if (!splitter || index.value < 0 || !splitter.isDraggable(index.value)) {
342
+ return
343
+ }
344
+
345
+ touch.touchStart(event)
346
+ touchPending.value = true
347
+ startPosition.value = getClientPosition(event)
348
+ }
349
+
350
+ const onTouchMove = (event: any) => {
351
+ if (!splitter || index.value < 0 || (!dragging.value && !touchPending.value)) {
352
+ return
353
+ }
354
+
355
+ touch.touchMove(event)
356
+ const expectedDirection = splitter.layout.value === 'horizontal' ? 'horizontal' : 'vertical'
357
+ const mainOffset = expectedDirection === 'horizontal' ? touch.offsetX.value : touch.offsetY.value
358
+
359
+ if (!dragging.value) {
360
+ if (touch.direction.value && touch.direction.value !== expectedDirection) {
361
+ touchPending.value = false
362
+ return
363
+ }
364
+
365
+ if (mainOffset < TOUCH_DRAG_SLOP) {
366
+ return
367
+ }
368
+
369
+ touchPending.value = false
370
+ startMove(startPosition.value)
371
+ }
372
+
373
+ move(getClientPosition(event))
374
+ }
375
+
376
+ const onTouchEnd = () => {
377
+ touchPending.value = false
378
+ endMove()
379
+ }
380
+
381
+ const onMouseMove = (event: MouseEvent) => {
382
+ move(getClientPosition(event))
383
+ }
384
+
385
+ const onMouseUp = () => {
386
+ endMove()
387
+ if (typeof document !== 'undefined') {
388
+ document.removeEventListener('mousemove', onMouseMove)
389
+ document.removeEventListener('mouseup', onMouseUp)
390
+ }
391
+ }
392
+
393
+ const onMouseDown = (event: MouseEvent) => {
394
+ // #ifdef H5
395
+ startMove(getClientPosition(event))
396
+ if (typeof document !== 'undefined') {
397
+ document.addEventListener('mousemove', onMouseMove)
398
+ document.addEventListener('mouseup', onMouseUp)
399
+ }
400
+ // #endif
401
+ }
402
+
403
+ const onCollapse = (type: SplitterCollapseType) => {
404
+ if (!splitter || index.value < 0) {
405
+ return
406
+ }
407
+ splitter.onCollapse(index.value, type)
408
+ }
409
+
410
+ watch(
411
+ panelSize,
412
+ (value) => {
413
+ emit('update:size', value)
414
+ },
415
+ { immediate: true }
416
+ )
417
+
418
+ onUnmounted(() => {
419
+ if (typeof document !== 'undefined') {
420
+ document.removeEventListener('mousemove', onMouseMove)
421
+ document.removeEventListener('mouseup', onMouseUp)
422
+ }
423
+ })
424
+
425
+ defineExpose<SplitterPanelExpose>({
426
+ getSize: () => panelSize.value
427
+ })
428
+ </script>
429
+
430
+ <style lang="scss" scoped>
431
+ @import './index.scss';
432
+ </style>
@@ -0,0 +1,63 @@
1
+ import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
2
+ import { baseProps, makeBooleanProp } from '../common/props'
3
+ import type { SplitterPanelSize } from '../oxy-splitter/types'
4
+
5
+ export const splitterPanelProps = {
6
+ ...baseProps,
7
+
8
+ /**
9
+ * 面板尺寸
10
+ * 支持 `number(px)`、`px`、`rpx`、`%`
11
+ */
12
+ size: {
13
+ type: [Number, String] as PropType<SplitterPanelSize>,
14
+ default: undefined
15
+ },
16
+
17
+ /**
18
+ * 面板最小尺寸
19
+ * 支持 `number(px)`、`px`、`rpx`、`%`
20
+ */
21
+ min: {
22
+ type: [Number, String] as PropType<SplitterPanelSize>,
23
+ default: undefined
24
+ },
25
+
26
+ /**
27
+ * 面板最大尺寸
28
+ * 支持 `number(px)`、`px`、`rpx`、`%`
29
+ */
30
+ max: {
31
+ type: [Number, String] as PropType<SplitterPanelSize>,
32
+ default: undefined
33
+ },
34
+
35
+ /**
36
+ * 是否允许拖拽调整
37
+ */
38
+ resizable: makeBooleanProp(true),
39
+
40
+ /**
41
+ * 是否可折叠
42
+ * 默认 `false`,允许在相邻分割条上显示折叠入口
43
+ */
44
+ collapsible: makeBooleanProp(false)
45
+ }
46
+
47
+ export type SplitterPanelProps = ExtractPropTypes<typeof splitterPanelProps>
48
+
49
+ export type SplitterPanelEmits = {
50
+ /**
51
+ * 面板尺寸变化(单位 px)
52
+ */
53
+ 'update:size': [size: number]
54
+ }
55
+
56
+ export type SplitterPanelExpose = {
57
+ /**
58
+ * 当前面板 size(px)
59
+ */
60
+ getSize: () => number
61
+ }
62
+
63
+ export type SplitterPanelInstance = ComponentPublicInstance<SplitterPanelProps, SplitterPanelExpose>
@@ -57,7 +57,7 @@
57
57
  position: relative;
58
58
  width: $-steps-icon-size;
59
59
  height: $-steps-icon-size;
60
- background: #fff;
60
+ background: $-color-white;
61
61
  z-index: 1;
62
62
 
63
63
  @include when(icon) {
@@ -105,7 +105,7 @@
105
105
  background: $-steps-line-color;
106
106
  }
107
107
  @include e(content){
108
- margin-top: 14rpx;
108
+ margin-top: 16rpx;
109
109
  color: $-steps-inactive-color;
110
110
  font-size: $-steps-label-fs;
111
111
  }
@@ -118,8 +118,8 @@
118
118
  }
119
119
  }
120
120
  @include e(description) {
121
- margin-top: 10rpx;
122
- padding: 0 4rpx;
121
+ margin-top: 12rpx;
122
+ padding: 0 8rpx;
123
123
  color: $-steps-description-color;
124
124
  }
125
125
  @include when(wait) {
@@ -149,7 +149,7 @@
149
149
  }
150
150
  }
151
151
  .oxy-step__icon-outer {
152
- color: #fff;
152
+ color: $-color-white;
153
153
  background: $-steps-finished-color;
154
154
  border-color: $-steps-finished-color;
155
155
  }