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
@@ -20,7 +20,10 @@ export default {
20
20
  },
21
21
  data() {
22
22
  return {
23
- requestTask: null
23
+ requestTask: null,
24
+ mpTextDecoder: null,
25
+ mpUtf8Pending: null,
26
+ pendingText: ''
24
27
  }
25
28
  },
26
29
  watch: {
@@ -34,10 +37,224 @@ export default {
34
37
  }
35
38
  },
36
39
  methods: {
40
+ stripSseFields(input) {
41
+ return input
42
+ .replace(/\r/g, '')
43
+ .split('\n')
44
+ .map((line) => {
45
+ if (line.startsWith('data:')) return line.slice(5).trimStart()
46
+ return line
47
+ })
48
+ .join('\n')
49
+ },
50
+ extractJsonObjects(input) {
51
+ const texts = []
52
+ let start = -1
53
+ let depth = 0
54
+ let inString = false
55
+ let escape = false
56
+
57
+ for (let i = 0; i < input.length; i++) {
58
+ const ch = input[i]
59
+ if (escape) {
60
+ escape = false
61
+ continue
62
+ }
63
+
64
+ if (inString) {
65
+ if (ch === '\\') escape = true
66
+ else if (ch === '"') inString = false
67
+ continue
68
+ }
69
+
70
+ if (ch === '"') {
71
+ inString = true
72
+ continue
73
+ }
74
+
75
+ if (ch === '{') {
76
+ if (depth === 0) start = i
77
+ depth++
78
+ continue
79
+ }
80
+
81
+ if (ch === '}') {
82
+ if (depth > 0) depth--
83
+ if (depth === 0 && start !== -1) {
84
+ texts.push(input.slice(start, i + 1))
85
+ start = -1
86
+ }
87
+ }
88
+ }
89
+
90
+ const rest = start !== -1 ? input.slice(start) : ''
91
+ return { texts, rest }
92
+ },
93
+ emitParsedStreamData({ chunk, finished }) {
94
+ if (finished) {
95
+ if (this.pendingText) {
96
+ const normalized = this.stripSseFields(this.pendingText)
97
+ const { texts, rest } = this.extractJsonObjects(normalized)
98
+ texts.forEach((text) => {
99
+ this.$emit('stream-data', { chunk: text, finished: false })
100
+ })
101
+ this.pendingText = rest
102
+ }
103
+ this.pendingText = ''
104
+ this.$emit('stream-data', { chunk: null, finished: true })
105
+ return
106
+ }
107
+
108
+ if (!chunk) return
109
+
110
+ this.pendingText += chunk
111
+ const normalized = this.stripSseFields(this.pendingText)
112
+ const { texts, rest } = this.extractJsonObjects(normalized)
113
+ texts.forEach((text) => {
114
+ this.$emit('stream-data', { chunk: text, finished: false })
115
+ })
116
+ this.pendingText = rest
117
+ },
118
+ mergeUint8Array(a, b) {
119
+ const merged = new Uint8Array(a.length + b.length)
120
+ merged.set(a, 0)
121
+ merged.set(b, a.length)
122
+ return merged
123
+ },
124
+ splitIncompleteUtf8(bytes) {
125
+ const len = bytes.length
126
+ if (len === 0) {
127
+ return { complete: bytes, pending: null }
128
+ }
129
+
130
+ let i = len
131
+ let cont = 0
132
+ while (i > 0 && cont < 3 && (bytes[i - 1] & 0xc0) === 0x80) {
133
+ cont++
134
+ i--
135
+ }
136
+
137
+ const leadIndex = i - 1
138
+ if (leadIndex < 0) {
139
+ return { complete: new Uint8Array(0), pending: bytes }
140
+ }
141
+
142
+ const lead = bytes[leadIndex]
143
+ let expected = 1
144
+ if ((lead & 0x80) === 0x00) expected = 1
145
+ else if ((lead & 0xe0) === 0xc0) expected = 2
146
+ else if ((lead & 0xf0) === 0xe0) expected = 3
147
+ else if ((lead & 0xf8) === 0xf0) expected = 4
148
+ else expected = 1
149
+
150
+ const actual = len - leadIndex
151
+ if (expected > actual) {
152
+ return {
153
+ complete: bytes.slice(0, leadIndex),
154
+ pending: bytes.slice(leadIndex)
155
+ }
156
+ }
157
+
158
+ return { complete: bytes, pending: null }
159
+ },
160
+ utf8Decode(bytes) {
161
+ let out = ''
162
+ for (let i = 0; i < bytes.length; i++) {
163
+ const b0 = bytes[i]
164
+ if (b0 < 0x80) {
165
+ out += String.fromCharCode(b0)
166
+ continue
167
+ }
168
+
169
+ if ((b0 & 0xe0) === 0xc0) {
170
+ if (i + 1 >= bytes.length) {
171
+ out += '\uFFFD'
172
+ break
173
+ }
174
+ const b1 = bytes[++i]
175
+ if ((b1 & 0xc0) !== 0x80) {
176
+ out += '\uFFFD'
177
+ continue
178
+ }
179
+ const code = ((b0 & 0x1f) << 6) | (b1 & 0x3f)
180
+ out += String.fromCharCode(code)
181
+ continue
182
+ }
183
+
184
+ if ((b0 & 0xf0) === 0xe0) {
185
+ if (i + 2 >= bytes.length) {
186
+ out += '\uFFFD'
187
+ break
188
+ }
189
+ const b1 = bytes[++i]
190
+ const b2 = bytes[++i]
191
+ if ((b1 & 0xc0) !== 0x80 || (b2 & 0xc0) !== 0x80) {
192
+ out += '\uFFFD'
193
+ continue
194
+ }
195
+ const code = ((b0 & 0x0f) << 12) | ((b1 & 0x3f) << 6) | (b2 & 0x3f)
196
+ out += String.fromCharCode(code)
197
+ continue
198
+ }
199
+
200
+ if ((b0 & 0xf8) === 0xf0) {
201
+ if (i + 3 >= bytes.length) {
202
+ out += '\uFFFD'
203
+ break
204
+ }
205
+ const b1 = bytes[++i]
206
+ const b2 = bytes[++i]
207
+ const b3 = bytes[++i]
208
+ if ((b1 & 0xc0) !== 0x80 || (b2 & 0xc0) !== 0x80 || (b3 & 0xc0) !== 0x80) {
209
+ out += '\uFFFD'
210
+ continue
211
+ }
212
+ let codePoint = ((b0 & 0x07) << 18) | ((b1 & 0x3f) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x3f)
213
+ codePoint -= 0x10000
214
+ out += String.fromCharCode(0xd800 + (codePoint >> 10), 0xdc00 + (codePoint & 0x3ff))
215
+ continue
216
+ }
217
+
218
+ out += '\uFFFD'
219
+ }
220
+ return out
221
+ },
222
+ decodeMpChunk(data, finished) {
223
+ if (finished) {
224
+ let tail = null
225
+ if (this.mpTextDecoder) {
226
+ try {
227
+ tail = this.mpTextDecoder.decode()
228
+ } catch (e) {
229
+ tail = null
230
+ }
231
+ } else if (this.mpUtf8Pending && this.mpUtf8Pending.length) {
232
+ tail = this.utf8Decode(this.mpUtf8Pending)
233
+ }
234
+ this.mpTextDecoder = null
235
+ this.mpUtf8Pending = null
236
+ return tail && tail.length ? tail : null
237
+ }
238
+
239
+ let bytes
240
+ if (data instanceof Uint8Array) bytes = data
241
+ else if (data instanceof ArrayBuffer) bytes = new Uint8Array(data)
242
+ else bytes = new Uint8Array(data)
243
+
244
+ if (this.mpUtf8Pending && this.mpUtf8Pending.length) {
245
+ bytes = this.mergeUint8Array(this.mpUtf8Pending, bytes)
246
+ this.mpUtf8Pending = null
247
+ }
248
+
249
+ const { complete, pending } = this.splitIncompleteUtf8(bytes)
250
+ this.mpUtf8Pending = pending
251
+ return this.utf8Decode(complete)
252
+ },
37
253
  handleAppStreamData({ chunk, finished }) {
38
- this.$emit('stream-data', { chunk, finished })
254
+ this.emitParsedStreamData({ chunk, finished })
39
255
  },
40
256
  handleAppStreamError({ message, type }) {
257
+ this.pendingText = ''
41
258
  this.$emit('stream-error', { message, type })
42
259
  },
43
260
  // #ifndef H5 || APP-PLUS
@@ -47,6 +264,7 @@ export default {
47
264
  this.requestTask.abort()
48
265
  this.requestTask = null
49
266
  }
267
+ this.decodeMpChunk(new Uint8Array(0), true)
50
268
  this.handleAppStreamData({
51
269
  chunk: null,
52
270
  finished: true
@@ -62,6 +280,7 @@ export default {
62
280
  this.requestTask.abort()
63
281
  this.requestTask = null
64
282
  }
283
+ this.decodeMpChunk(new Uint8Array(0), true)
65
284
 
66
285
  const { url, method, headers, body } = newVal
67
286
 
@@ -72,6 +291,13 @@ export default {
72
291
  data: body,
73
292
  enableChunked: true,
74
293
  success: (res) => {
294
+ const tail = this.decodeMpChunk(new Uint8Array(0), true)
295
+ if (tail) {
296
+ this.handleAppStreamData({
297
+ chunk: tail,
298
+ finished: false
299
+ })
300
+ }
75
301
  this.handleAppStreamData({
76
302
  chunk: null,
77
303
  finished: true
@@ -79,6 +305,7 @@ export default {
79
305
  this.requestTask = null
80
306
  },
81
307
  fail: (err) => {
308
+ this.decodeMpChunk(new Uint8Array(0), true)
82
309
  this.handleAppStreamError({
83
310
  message: err.errMsg || 'Request failed',
84
311
  type: err.errMsg === 'request:fail abort' ? 'AbortError' : 'Error'
@@ -88,8 +315,7 @@ export default {
88
315
  })
89
316
  // 这里监听消息
90
317
  this.requestTask.onChunkReceived((res) => {
91
- let decoder = new TextDecoder('utf-8')
92
- let chunk = decoder.decode(new Uint8Array(res.data))
318
+ const chunk = this.decodeMpChunk(res.data, false)
93
319
  this.handleAppStreamData({
94
320
  chunk,
95
321
  finished: false
@@ -1,5 +1,8 @@
1
- import type { ExtractPropTypes, PropType } from 'vue'
1
+ import type { ExtractPropTypes } from 'vue'
2
2
 
3
+ /**
4
+ * 流式渲染组件属性
5
+ */
3
6
  export const streamRenderProps = {}
4
7
 
5
8
  export type StreamRenderProps = ExtractPropTypes<typeof streamRenderProps>
@@ -39,7 +39,7 @@ import { getCurrentInstance, inject, onBeforeMount, onBeforeUnmount, onMounted,
39
39
  import { closeOther, pushToQueue, removeFromQueue } from '../common/clickoutside'
40
40
  import { type Queue, queueKey } from '../composables/useQueue'
41
41
  import { useTouch } from '../composables/useTouch'
42
- import { getRect } from '../common/util'
42
+ import { getRect, unitConvert } from '../common/util'
43
43
  import { swipeActionProps, type SwipeActionPosition, type SwipeActionReason, type SwipeActionStatus } from './types'
44
44
 
45
45
  const props = defineProps(swipeActionProps)
@@ -55,6 +55,10 @@ const originOffset = ref<number>(0)
55
55
  const wrapperOffset = ref<number>(0)
56
56
  // 是否处于滑动状态
57
57
  const touching = ref<boolean>(false)
58
+ // 标记本次触摸周期是否发生过横向滑动,用于抑制触摸后的合成 click
59
+ const swiping = ref<boolean>(false)
60
+ // 拖拽计算版本号,避免异步获取宽度结果乱序导致位移回退
61
+ const dragVersion = ref<number>(0)
58
62
 
59
63
  const touch = useTouch()
60
64
 
@@ -139,7 +143,7 @@ function getWidths() {
139
143
  */
140
144
  function swipeMove(offset = 0) {
141
145
  // this.offset = offset
142
- const transform = `translate3d(${offset}px, 0, 0)`
146
+ const transform = `translate3d(${unitConvert(offset, 0, { output: 'px' })}, 0, 0)`
143
147
  // 跟随手指滑动,不需要动画
144
148
  const transition = touching.value ? 'none' : '.6s cubic-bezier(0.18, 0.89, 0.32, 1)'
145
149
  wrapperStyle.value = `
@@ -156,6 +160,11 @@ function swipeMove(offset = 0) {
156
160
  * @param event
157
161
  */
158
162
  function onClick(position?: SwipeActionPosition) {
163
+ if (swiping.value) {
164
+ swiping.value = false
165
+ return
166
+ }
167
+
159
168
  if (props.disabled || wrapperOffset.value === 0) {
160
169
  return
161
170
  }
@@ -172,6 +181,8 @@ function onClick(position?: SwipeActionPosition) {
172
181
  function startDrag(event: TouchEvent) {
173
182
  if (props.disabled) return
174
183
 
184
+ dragVersion.value += 1
185
+ swiping.value = false
175
186
  originOffset.value = wrapperOffset.value
176
187
  touch.touchStart(event)
177
188
  if (queue && queue.closeOther) {
@@ -196,10 +207,17 @@ function onDrag(event: TouchEvent) {
196
207
  }
197
208
 
198
209
  touching.value = true
210
+ swiping.value = true
211
+ const currentDragVersion = ++dragVersion.value
199
212
 
200
213
  // 本次滑动,wrapper应该设置的偏移量
201
214
  const offset = originOffset.value + touch.deltaX.value
202
215
  getWidths().then(([leftWidth, rightWidth]) => {
216
+ // 忽略过期的拖拽帧,避免异步返回顺序打乱造成回弹
217
+ if (!touching.value || currentDragVersion !== dragVersion.value) {
218
+ return
219
+ }
220
+
203
221
  // 如果需要想滑出来的按钮不存在,对应的按钮肯定滑不出来,容器处于初始状态。此时需要模拟一下位于此处的start事件。
204
222
  if ((leftWidth === 0 && offset > 0) || (rightWidth === 0 && offset < 0)) {
205
223
  swipeMove(0)
@@ -224,6 +242,7 @@ function endDrag() {
224
242
  // 滑出"操作按钮"的阈值
225
243
  const THRESHOLD = 0.3
226
244
  touching.value = false
245
+ dragVersion.value += 1
227
246
 
228
247
  getWidths().then(([leftWidth, rightWidth]) => {
229
248
  if (
@@ -261,6 +280,12 @@ function endDrag() {
261
280
  close('swipe')
262
281
  }
263
282
  })
283
+
284
+ if (swiping.value) {
285
+ setTimeout(() => {
286
+ swiping.value = false
287
+ }, 0)
288
+ }
264
289
  }
265
290
  /**
266
291
  * @description 关闭操过按钮,并在合适的时候调用 beforeClose
@@ -14,11 +14,11 @@
14
14
  :circular="loop"
15
15
  :vertical="direction == 'vertical'"
16
16
  :easing-function="easingFunction"
17
- :previous-margin="addUnit(previousMargin)"
18
- :next-margin="addUnit(nextMargin)"
17
+ :previous-margin="withDefaultUnit(previousMargin)"
18
+ :next-margin="withDefaultUnit(nextMargin)"
19
19
  :snap-to-edge="snapToEdge"
20
20
  :display-multiple-items="displayMultipleItems"
21
- :style="{ height: addUnit(height) }"
21
+ :style="{ height: withDefaultUnit(height) }"
22
22
  @change="handleChange"
23
23
  @animationfinish="handleAnimationfinish"
24
24
  >
@@ -27,7 +27,7 @@
27
27
  <video
28
28
  v-if="isVideo(item)"
29
29
  :id="`video-${index}-${uid}`"
30
- :style="{ height: addUnit(height) }"
30
+ :style="{ height: withDefaultUnit(height) }"
31
31
  :src="isObj(item) ? item[valueKey] : item"
32
32
  :poster="isObj(item) ? item.poster : ''"
33
33
  :class="`oxy-swiper__video ${customItemClass} ${getCustomItemClass(currentValue, index, list)}`"
@@ -44,7 +44,7 @@
44
44
  v-else
45
45
  :src="isObj(item) ? item[valueKey] : item"
46
46
  :class="`oxy-swiper__image ${customImageClass} ${customItemClass} ${getCustomItemClass(currentValue, index, list)}`"
47
- :style="{ height: addUnit(height) }"
47
+ :style="{ height: withDefaultUnit(height) }"
48
48
  :mode="imageMode"
49
49
  @click="handleClick(index, item)"
50
50
  />
@@ -89,7 +89,7 @@ export default {
89
89
  <script lang="ts" setup>
90
90
  import OxySwiperNav from '../oxy-swiper-nav/oxy-swiper-nav.vue'
91
91
  import { computed, watch, ref, getCurrentInstance, useSlots } from 'vue'
92
- import { addUnit, isObj, isImageUrl, isVideoUrl, uuid, isDef } from '../common/util'
92
+ import { withDefaultUnit, isObj, isImageUrl, isVideoUrl, uuid, isDef } from '../common/util'
93
93
  import { swiperProps, type SwiperList } from './types'
94
94
  import type { SwiperNavProps } from '../oxy-swiper-nav/types'
95
95
  const slots = useSlots()
@@ -86,10 +86,10 @@ export const swiperProps = {
86
86
 
87
87
  /**
88
88
  * 轮播的高度
89
- * 类型:number 或 string(数字或可转换为数字的字符串)
90
- * 默认值:'192'
89
+ * 类型:number 或 string(数字或纯数字字符串默认按 rpx 处理)
90
+ * 默认值:'384'
91
91
  */
92
- height: makeNumericProp('192'),
92
+ height: makeNumericProp('384'),
93
93
 
94
94
  /**
95
95
  * 轮播间隔时间,单位为毫秒
@@ -131,7 +131,7 @@ export const swiperProps = {
131
131
 
132
132
  /**
133
133
  * 后边距
134
- * 类型:number 或 string(数字或可转换为数字的字符串)
134
+ * 类型:number 或 string(数字或纯数字字符串默认按 rpx 处理)
135
135
  * 默认值:'0'
136
136
  */
137
137
  nextMargin: makeNumericProp('0'),
@@ -144,7 +144,7 @@ export const swiperProps = {
144
144
  indicatorPosition: makeStringProp<IndicatorPositionType>('bottom'),
145
145
  /**
146
146
  * 前边距
147
- * 类型:number 或 string(数字或可转换为数字的字符串)
147
+ * 类型:number 或 string(数字或纯数字字符串默认按 rpx 处理)
148
148
  * 默认值:'0'
149
149
  */
150
150
  previousMargin: makeNumericProp('0'),
@@ -69,11 +69,11 @@
69
69
  height: $-swiper-nav-dot-size;
70
70
  background: $-swiper-nav-dot-color;
71
71
  border-radius: 50%;
72
- margin: 0 10rpx;
72
+ margin: 0 12rpx;
73
73
  transition: all 0.4s ease-in;
74
74
 
75
75
  @include when(vertical) {
76
- margin: 10rpx 0;
76
+ margin: 12rpx 0;
77
77
  }
78
78
 
79
79
  @include when(active) {
@@ -156,4 +156,4 @@
156
156
  flex-direction: column;
157
157
  }
158
158
 
159
- }
159
+ }
@@ -24,22 +24,22 @@
24
24
  display: inline-block;
25
25
  width: $-switch-circle-size;
26
26
  height: $-switch-circle-size;
27
- top: 2px;
28
- left: 2px;
29
- background: #fff;
27
+ top: 4rpx;
28
+ left: 4rpx;
29
+ background: $-switch-circle-bg;
30
30
  border-radius: 50%;
31
31
  transition: left .3s ease-out;
32
- box-shadow: 0 2px 4px 0 $-switch-inactive-shadow-color;
32
+ box-shadow: 0 4rpx 8rpx 0 $-switch-inactive-shadow-color;
33
33
 
34
34
  &::after {
35
35
  position: absolute;
36
36
  content: '';
37
- width: calc(200% - 2px);
38
- height: calc(200% - 2px);
37
+ width: calc(200% - 4rpx);
38
+ height: calc(200% - 4rpx);
39
39
  top: 50%;
40
40
  left: 50%;
41
41
  transform: translate(-50%, -50%) scale(0.5);
42
- border: 1px solid $-switch-border-color;
42
+ border: 2rpx solid $-switch-border-color;
43
43
  border-radius: 50%;
44
44
  }
45
45
  }
@@ -48,11 +48,11 @@
48
48
  border-color: $-switch-active-color;
49
49
 
50
50
  .oxy-switch__circle {
51
- left: calc($-switch-width - $-switch-circle-size - 2px);
52
- box-shadow: 0 2px 4px 0 $-switch-active-shadow-color
51
+ left: calc($-switch-width - $-switch-circle-size - 4rpx);
52
+ box-shadow: 0 4rpx 8rpx 0 $-switch-active-shadow-color
53
53
  }
54
54
  }
55
55
  @include when(disabled) {
56
56
  opacity: 0.5;
57
57
  }
58
- }
58
+ }
@@ -16,7 +16,7 @@ export default {
16
16
 
17
17
  <script lang="ts" setup>
18
18
  import { computed, type CSSProperties, onBeforeMount } from 'vue'
19
- import { addUnit, isFunction, objToStyle } from '../common/util'
19
+ import { withDefaultUnit, isFunction, objToStyle } from '../common/util'
20
20
  import { switchProps } from './types'
21
21
 
22
22
  const props = defineProps(switchProps)
@@ -32,7 +32,7 @@ const rootStyle = computed(() => {
32
32
  'border-color': props.modelValue === props.activeValue ? props.activeColor : props.inactiveColor
33
33
  }
34
34
  if (props.size) {
35
- rootStyle['font-size'] = addUnit(props.size)
35
+ rootStyle['font-size'] = withDefaultUnit(props.size)
36
36
  }
37
37
  return `${objToStyle(rootStyle)}${props.customStyle}`
38
38
  })
@@ -45,7 +45,7 @@ export const switchProps = {
45
45
  */
46
46
  inactiveColor: String,
47
47
  /**
48
- * 大小
48
+ * 大小,number 类型按 `rpx` 语义处理
49
49
  */
50
50
  size: {
51
51
  type: numericProp
@@ -13,4 +13,14 @@
13
13
  transition: height 0.3s ease-in-out;
14
14
  }
15
15
  }
16
- }
16
+ }
17
+
18
+ .is-fullscreen {
19
+ .oxy-tab {
20
+ height: 100%;
21
+ overflow: hidden;
22
+ .oxy-tab__body {
23
+ height: 100%;
24
+ }
25
+ }
26
+ }
@@ -24,7 +24,7 @@
24
24
  @include m(round) {
25
25
  margin-left: 32rpx;
26
26
  margin-right: 32rpx;
27
- border-radius: 999px;
27
+ border-radius: $-tabbar-round-radius;
28
28
  box-shadow: $-tabbar-box-shadow;
29
29
 
30
30
  @include when(fixed) {
@@ -59,4 +59,4 @@
59
59
  right: 0;
60
60
  z-index: 500;
61
61
  }
62
- }
62
+ }
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <view :class="{ 'oxy-tabbar__placeholder': fixed && placeholder && safeAreaInsetBottom && shape === 'round' }" :style="{ height: addUnit(height) }">
2
+ <view :class="{ 'oxy-tabbar__placeholder': fixed && placeholder && safeAreaInsetBottom && shape === 'round' }" :style="placeholderStyle">
3
3
  <view
4
4
  :class="`oxy-tabbar oxy-tabbar--${shape} ${customClass} ${fixed ? 'is-fixed' : ''} ${safeAreaInsetBottom ? 'is-safe' : ''} ${
5
5
  bordered ? 'is-border' : ''
@@ -23,14 +23,15 @@ export default {
23
23
  <script lang="ts" setup>
24
24
  import { getCurrentInstance, onMounted, ref, watch, nextTick, computed, type CSSProperties } from 'vue'
25
25
  import type { TabbarItem } from '../oxy-tabbar-item/types'
26
- import { addUnit, getRect, isDef, objToStyle } from '../common/util'
26
+ import { getRect, isDef, objToStyle } from '../common/util'
27
27
  import { useChildren } from '../composables/useChildren'
28
+ import { useWindowResize } from '../composables/useWindowResize'
28
29
  import { TABBAR_KEY, tabbarProps } from './types'
29
30
 
30
31
  const props = defineProps(tabbarProps)
31
32
  const emit = defineEmits(['change', 'update:modelValue'])
32
33
 
33
- const height = ref<number | string>('') // 占位高度
34
+ const placeholderHeight = ref<number | string>('') // 占位高度(rpx 语义)
34
35
  const { proxy } = getCurrentInstance() as any
35
36
 
36
37
  const { linkChildren } = useChildren(TABBAR_KEY)
@@ -48,19 +49,26 @@ const rootStyle = computed(() => {
48
49
  return `${objToStyle(style)}${props.customStyle}`
49
50
  })
50
51
 
52
+ const placeholderStyle = computed(() => {
53
+ if (!props.fixed || !props.placeholder) {
54
+ return {}
55
+ }
56
+ return {
57
+ height: `${Number(placeholderHeight.value) || 0}rpx`
58
+ }
59
+ })
60
+
51
61
  watch(
52
- [() => props.fixed, () => props.placeholder],
62
+ [() => props.fixed, () => props.placeholder, () => props.safeAreaInsetBottom, () => props.shape, () => props.customStyle],
53
63
  () => {
54
64
  setPlaceholderHeight()
55
65
  },
56
- { deep: true, immediate: false }
66
+ { immediate: false }
57
67
  )
58
68
 
59
69
  onMounted(() => {
60
70
  if (props.fixed && props.placeholder) {
61
- nextTick(() => {
62
- setPlaceholderHeight()
63
- })
71
+ setPlaceholderHeight()
64
72
  }
65
73
  })
66
74
 
@@ -76,13 +84,34 @@ function setChange(child: TabbarItem) {
76
84
  })
77
85
  }
78
86
 
87
+ function handleWindowResize() {
88
+ if (props.fixed && props.placeholder) {
89
+ setPlaceholderHeight()
90
+ }
91
+ }
92
+
93
+ useWindowResize(handleWindowResize)
94
+
79
95
  function setPlaceholderHeight() {
80
96
  if (!props.fixed || !props.placeholder) {
97
+ placeholderHeight.value = ''
81
98
  return
82
99
  }
83
100
 
84
- getRect('.oxy-tabbar', false, proxy).then((res) => {
85
- height.value = Number(res.height)
101
+ nextTick(() => {
102
+ getRect('.oxy-tabbar', false, proxy)
103
+ .then((res) => {
104
+ const rectHeight = Number(res.height) || 0
105
+ const rectTop = Number(res.top)
106
+ const { windowHeight = 0, windowWidth = 0 } = uni.getSystemInfoSync()
107
+ const occupiedHeight = windowHeight && !Number.isNaN(rectTop) ? Math.max(windowHeight - rectTop, 0) : rectHeight
108
+ const occupiedHeightInRpx = windowWidth ? (occupiedHeight * 750) / windowWidth : occupiedHeight * 2
109
+
110
+ placeholderHeight.value = occupiedHeight ? occupiedHeightInRpx : ''
111
+ })
112
+ .catch(() => {
113
+ placeholderHeight.value = ''
114
+ })
86
115
  })
87
116
  }
88
117
  </script>