@wot-ui/ui 2.0.8 → 2.2.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 (49) hide show
  1. package/README.md +11 -11
  2. package/attributes.json +1 -1
  3. package/changelog.md +40 -0
  4. package/components/wd-avatar/wd-avatar.vue +1 -1
  5. package/components/wd-button/index.scss +1 -0
  6. package/components/wd-button/types.ts +14 -11
  7. package/components/wd-button/wd-button.vue +26 -4
  8. package/components/wd-calendar-view/monthPanel/month-panel.vue +1 -0
  9. package/components/wd-calendar-view/yearPanel/year-panel.vue +1 -0
  10. package/components/wd-cell/index.scss +12 -1
  11. package/components/wd-config-provider/global-config.ts +50 -0
  12. package/components/wd-config-provider/theme-vars.ts +2073 -0
  13. package/components/wd-config-provider/types.ts +20 -2071
  14. package/components/wd-config-provider/wd-config-provider.vue +15 -4
  15. package/components/wd-dialog/wd-dialog.vue +1 -0
  16. package/components/wd-drop-menu/wd-drop-menu.vue +1 -0
  17. package/components/wd-form/wd-form.vue +32 -7
  18. package/components/wd-grid/wd-grid.vue +0 -2
  19. package/components/wd-icon/wd-icon.vue +2 -2
  20. package/components/wd-img/wd-img.vue +1 -0
  21. package/components/wd-index-anchor/index.scss +5 -5
  22. package/components/wd-index-bar/index.scss +14 -14
  23. package/components/wd-keyboard/key/index.vue +2 -0
  24. package/components/wd-notify/wd-notify.vue +1 -0
  25. package/components/wd-picker-view/useSelection.ts +3 -1
  26. package/components/wd-root-portal/wd-root-portal.vue +1 -1
  27. package/components/wd-select-picker/wd-select-picker.vue +1 -0
  28. package/components/wd-signature/wd-signature.vue +1 -0
  29. package/components/wd-slider/index.scss +45 -45
  30. package/components/wd-slider/wd-slider.vue +19 -3
  31. package/components/wd-switch/wd-switch.vue +2 -0
  32. package/components/wd-tabs/wd-tabs.vue +1 -0
  33. package/components/wd-tag/index.scss +8 -7
  34. package/components/wd-tag/types.ts +10 -7
  35. package/components/wd-tag/wd-tag.vue +23 -6
  36. package/components/wd-toast/index.scss +0 -1
  37. package/components/wd-toast/wd-toast.vue +4 -0
  38. package/components/wd-video-preview/index.scss +19 -1
  39. package/components/wd-video-preview/types.ts +21 -2
  40. package/components/wd-video-preview/wd-video-preview.vue +109 -30
  41. package/composables/index.ts +2 -0
  42. package/composables/useChildren.ts +0 -6
  43. package/composables/useConfigProvider.ts +27 -12
  44. package/composables/useGlobalConfig.ts +9 -0
  45. package/index.ts +1 -1
  46. package/package.json +1 -1
  47. package/styles/variable.scss +381 -381
  48. package/tags.json +1 -1
  49. package/web-types.json +1 -1
@@ -33,6 +33,15 @@ $video-preview-close-z-index: var(--wot-video-preview-close-z-index, 10) !defaul
33
33
  width: 100%;
34
34
  height: $video-preview-video-height;
35
35
  transition: all 0.3s ease;
36
+
37
+ @include when(fullscreen) {
38
+ height: 100%;
39
+ }
40
+ }
41
+
42
+ @include e(video-player) {
43
+ width: 100%;
44
+ height: 100%;
36
45
  }
37
46
 
38
47
  @include e(close) {
@@ -42,8 +51,17 @@ $video-preview-close-z-index: var(--wot-video-preview-close-z-index, 10) !defaul
42
51
  justify-content: center;
43
52
  align-items: center;
44
53
  top: $video-preview-close-margin;
45
- right: $video-preview-close-margin;
46
54
  cursor: pointer;
55
+
56
+ @include when(left-top) {
57
+ left: $video-preview-close-margin;
58
+ right: auto;
59
+ }
60
+
61
+ @include when(right-top) {
62
+ left: auto;
63
+ right: $video-preview-close-margin;
64
+ }
47
65
  }
48
66
 
49
67
  @include edeep(close-icon) {
@@ -10,7 +10,9 @@
10
10
  import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
11
11
  import { baseProps } from '../../common/props'
12
12
 
13
- import { makeStringProp, makeNumberProp } from '../../common/props'
13
+ import { makeBooleanProp, makeNumberProp, makeStringProp } from '../../common/props'
14
+
15
+ export type VideoPreviewClosePosition = 'left-top' | 'right-top'
14
16
 
15
17
  export const videoPreviewProps = {
16
18
  ...baseProps,
@@ -24,6 +26,19 @@ export const videoPreviewProps = {
24
26
  * 默认值: 1000
25
27
  */
26
28
  zIndex: makeNumberProp(1000),
29
+ /**
30
+ * 是否全屏预览
31
+ * 类型: boolean
32
+ * 默认值: false
33
+ */
34
+ fullScreen: makeBooleanProp(false),
35
+ /**
36
+ * 关闭按钮位置
37
+ * 类型: VideoPreviewClosePosition
38
+ * 可选值: 'left-top' | 'right-top'
39
+ * 默认值: 'left-top'
40
+ */
41
+ closePosition: makeStringProp<VideoPreviewClosePosition>('left-top'),
27
42
  /**
28
43
  * 打开时的回调
29
44
  */
@@ -45,6 +60,10 @@ export type VideoPreviewProps = ExtractPropTypes<typeof videoPreviewProps>
45
60
  export interface VideoPreviewOptions extends PreviewVideo {
46
61
  show?: boolean
47
62
  zIndex?: number
63
+ /** 是否全屏预览 */
64
+ fullScreen?: boolean
65
+ /** 关闭按钮位置 */
66
+ closePosition?: VideoPreviewClosePosition
48
67
  /** 打开时的回调 */
49
68
  onOpen?: () => void
50
69
  /** 关闭时的回调 */
@@ -58,7 +77,7 @@ export type VideoPreview = {
58
77
 
59
78
  export type VideoPreviewExpose = {
60
79
  /** 打开预览 */
61
- open: (video: PreviewVideo) => void
80
+ open: (video: VideoPreviewOptions) => void
62
81
  /** 关闭预览 */
63
82
  close: () => void
64
83
  }
@@ -1,31 +1,51 @@
1
1
  <template>
2
- <wd-overlay
3
- :show="state.show"
4
- :z-index="options.zIndex"
5
- :lock-scroll="true"
6
- :custom-class="`wd-video-preview ${customClass}`"
7
- :custom-style="customStyle"
8
- @click="close"
9
- @enter="handleEnter"
10
- @after-leave="handleAfterLeave"
11
- >
12
- <view class="wd-video-preview__video" @click.stop="">
13
- <video
14
- class="wd-video-preview__video"
15
- v-if="state.visible && previewVideo.url"
16
- :controls="true"
17
- :poster="previewVideo.poster"
18
- :title="previewVideo.title"
19
- play-btn-position="center"
20
- :enableNative="true"
21
- :src="previewVideo.url"
22
- :enable-progress-gesture="false"
23
- ></video>
24
- </view>
25
- <view class="wd-video-preview__close" @click.stop="close">
26
- <wd-icon name="close" custom-class="wd-video-preview__close-icon" />
27
- </view>
28
- </wd-overlay>
2
+ <!-- #ifdef APP-PLUS -->
3
+ <view v-if="state.show" :class="`wd-video-preview ${customClass}`" :style="`z-index: ${options.zIndex}; ${customStyle}`" @click="close">
4
+ <!-- #endif -->
5
+ <!-- #ifndef APP-PLUS -->
6
+ <wd-overlay
7
+ :show="state.show"
8
+ :z-index="options.zIndex"
9
+ :lock-scroll="true"
10
+ :custom-class="`wd-video-preview ${customClass}`"
11
+ :custom-style="customStyle"
12
+ @click="close"
13
+ @enter="handleEnter"
14
+ @after-leave="handleAfterLeave"
15
+ >
16
+ <!-- #endif -->
17
+
18
+ <view :class="videoClass" @click.stop="">
19
+ <video
20
+ :id="videoId"
21
+ class="wd-video-preview__video-player"
22
+ v-if="state.visible && previewVideo.url"
23
+ :controls="true"
24
+ :poster="previewVideo.poster"
25
+ :title="previewVideo.title"
26
+ play-btn-position="center"
27
+ :enableNative="true"
28
+ :src="previewVideo.url"
29
+ :enable-progress-gesture="false"
30
+ @fullscreenchange="handleFullscreenChange"
31
+ ></video>
32
+ </view>
33
+ <!-- #ifndef APP-PLUS -->
34
+ <view :class="closeClass" @click.stop="close">
35
+ <wd-icon name="close" custom-class="wd-video-preview__close-icon" />
36
+ </view>
37
+ <!-- #endif -->
38
+ <!-- #ifdef APP-PLUS -->
39
+ <view v-if="!isFullScreen" :class="closeClass" @click.stop="close">
40
+ <wd-icon name="close" custom-class="wd-video-preview__close-icon" />
41
+ </view>
42
+ <!-- #endif -->
43
+ <!-- #ifndef APP-PLUS -->
44
+ </wd-overlay>
45
+ <!-- #endif -->
46
+ <!-- #ifdef APP-PLUS -->
47
+ </view>
48
+ <!-- #endif -->
29
49
  </template>
30
50
 
31
51
  <script lang="ts">
@@ -44,10 +64,10 @@ export default {
44
64
  <script lang="ts" setup>
45
65
  import wdIcon from '../wd-icon/wd-icon.vue'
46
66
  import wdOverlay from '../wd-overlay/wd-overlay.vue'
47
- import { reactive, ref, inject, watch, computed } from 'vue'
67
+ import { reactive, ref, inject, watch, computed, getCurrentInstance, nextTick } from 'vue'
48
68
  import { videoPreviewProps, type PreviewVideo, type VideoPreviewOptions, type VideoPreviewExpose } from './types'
49
69
  import { defaultOptions, getVideoPreviewOptionKey } from './index'
50
- import { isDef, isFunction } from '../../common/util'
70
+ import { isDef, isFunction, uuid } from '../../common/util'
51
71
 
52
72
  const props = defineProps(videoPreviewProps)
53
73
 
@@ -62,6 +82,12 @@ const state = reactive({
62
82
  })
63
83
 
64
84
  const previewVideo = reactive<PreviewVideo>({ url: '', poster: '', title: '' })
85
+ const fullScreenValue = ref<boolean | undefined>()
86
+ const closePositionValue = ref<VideoPreviewOptions['closePosition']>()
87
+
88
+ // App 端原生 video 走系统全屏,需要唯一 id 创建上下文
89
+ const videoId = `wd-video-preview-${uuid()}`
90
+ const { proxy } = getCurrentInstance() as any
65
91
 
66
92
  // 获取注入的选项
67
93
  const videoPreviewOptionKey = getVideoPreviewOptionKey(props.selector)
@@ -73,6 +99,21 @@ const options = computed(() => ({
73
99
  onClose: videoPreviewOption.value.onClose || props.onClose || null
74
100
  }))
75
101
 
102
+ const isFullScreen = computed(() => {
103
+ const optionFullScreen = videoPreviewOption.value.fullScreen
104
+ if (isDef(optionFullScreen)) return optionFullScreen!
105
+ return isDef(fullScreenValue.value) ? fullScreenValue.value! : props.fullScreen
106
+ })
107
+
108
+ const closePosition = computed(() => {
109
+ const optionClosePosition = videoPreviewOption.value.closePosition
110
+ if (isDef(optionClosePosition)) return optionClosePosition!
111
+ return isDef(closePositionValue.value) ? closePositionValue.value! : props.closePosition
112
+ })
113
+
114
+ const videoClass = computed(() => ['wd-video-preview__video', isFullScreen.value ? 'is-fullscreen' : ''])
115
+ const closeClass = computed(() => ['wd-video-preview__close', `is-${closePosition.value}`])
116
+
76
117
  // 监听选项变化
77
118
  watch(
78
119
  () => videoPreviewOption.value,
@@ -87,11 +128,23 @@ watch(
87
128
  () => state.show,
88
129
  (newVal, oldVal) => {
89
130
  if (newVal && !oldVal) {
131
+ // #ifdef APP-PLUS
132
+ // App 端不使用 overlay,直接驱动 video 渲染并进入系统全屏
133
+ state.visible = true
134
+ enterFullScreen()
135
+ // #endif
90
136
  emit('open')
91
137
  if (isFunction(options.value.onOpen)) {
92
138
  options.value.onOpen()
93
139
  }
94
140
  } else if (!newVal && oldVal) {
141
+ // #ifdef APP-PLUS
142
+ // App 端关闭时重置 video 渲染与预览数据
143
+ state.visible = false
144
+ previewVideo.url = ''
145
+ previewVideo.poster = ''
146
+ previewVideo.title = ''
147
+ // #endif
95
148
  emit('close')
96
149
  if (isFunction(options.value.onClose)) {
97
150
  options.value.onClose()
@@ -106,9 +159,12 @@ function reset(option: VideoPreviewOptions) {
106
159
  previewVideo.url = option.url
107
160
  previewVideo.poster = option.poster
108
161
  previewVideo.title = option.title
162
+ fullScreenValue.value = option.fullScreen
163
+ closePositionValue.value = option.closePosition
109
164
  }
110
165
  }
111
166
 
167
+ // #ifndef APP-PLUS
112
168
  function handleEnter() {
113
169
  state.visible = true
114
170
  }
@@ -119,15 +175,38 @@ function handleAfterLeave() {
119
175
  previewVideo.poster = ''
120
176
  previewVideo.title = ''
121
177
  }
178
+ // #endif
179
+
180
+ // App 端全屏预览时进入原生全屏播放,规避原生 video 同层渲染遮挡自定义浮层的问题
181
+ function enterFullScreen() {
182
+ // #ifdef APP-PLUS
183
+ if (!isFullScreen.value) return
184
+ nextTick(() => {
185
+ const videoContext = uni.createVideoContext(videoId, proxy)
186
+ videoContext && videoContext.requestFullScreen({ direction: 0 })
187
+ })
188
+ // #endif
189
+ }
190
+
191
+ // 监听原生全屏状态变化,全屏预览模式下退出全屏时关闭预览
192
+ function handleFullscreenChange(event: any) {
193
+ // #ifdef APP-PLUS
194
+ if (isFullScreen.value && event && event.detail && !event.detail.fullScreen) {
195
+ close()
196
+ }
197
+ // #endif
198
+ }
122
199
 
123
200
  function close() {
124
201
  state.show = false
125
202
  }
126
203
 
127
- function open(video: PreviewVideo) {
204
+ function open(video: VideoPreviewOptions) {
128
205
  previewVideo.url = video.url
129
206
  previewVideo.poster = video.poster
130
207
  previewVideo.title = video.title
208
+ fullScreenValue.value = video.fullScreen
209
+ closePositionValue.value = video.closePosition
131
210
  state.show = true
132
211
  }
133
212
 
@@ -10,7 +10,9 @@ export { useTouch } from './useTouch'
10
10
  export { useTranslate } from './useTranslate'
11
11
  export { useUpload } from './useUpload'
12
12
  export { useConfigProvider } from './useConfigProvider'
13
+ export { useGlobalConfig } from './useGlobalConfig'
13
14
  export { useToast } from '../components/wd-toast'
14
15
  export { useDialog } from '../components/wd-dialog'
15
16
  export { useImagePreview } from '../components/wd-image-preview'
17
+ export { useVideoPreview } from '../components/wd-video-preview'
16
18
  export { useNotify, setNotifyDefaultOptions, resetNotifyDefaultOptions } from '../components/wd-notify'
@@ -80,14 +80,8 @@ export function useChildren<
80
80
  const link = (child: ComponentInternalInstance) => {
81
81
  if (child.proxy) {
82
82
  if (internalChildren.indexOf(child) === -1) {
83
- // #ifdef MP-ALIPAY
84
- internalChildren.unshift(child)
85
- publicChildren.unshift(child.proxy as Child)
86
- // #endif
87
- // #ifndef MP-ALIPAY
88
83
  internalChildren.push(child)
89
84
  publicChildren.push(child.proxy as Child)
90
- // #endif
91
85
  sortChildren(parent, publicChildren, internalChildren)
92
86
  }
93
87
  }
@@ -1,6 +1,13 @@
1
- import { computed, provide, unref, type Ref } from 'vue'
2
- import { type ConfigProviderThemeVars } from '../components/wd-config-provider/types'
1
+ import { computed, provide, unref, type MaybeRef } from 'vue'
2
+ import { type ConfigProviderThemeVars } from '../components/wd-config-provider/theme-vars'
3
3
  import { objToStyle } from '../common/util'
4
+ import {
5
+ mergeConfig,
6
+ type GlobalConfig,
7
+ type ConfigProviderInput,
8
+ type ButtonConfig,
9
+ type TagConfig
10
+ } from '../components/wd-config-provider/global-config'
4
11
 
5
12
  export const USE_CONFIG_PROVIDER_KEY = '__CONFIG_PROVIDER__'
6
13
 
@@ -22,24 +29,32 @@ export const mapThemeVarsToCSSVars = (themeVars: Record<string, string>) => {
22
29
  return cssVars
23
30
  }
24
31
 
25
- export function useConfigProvider({
26
- themeVars,
27
- theme
28
- }: {
29
- themeVars?: ConfigProviderThemeVars | Ref<ConfigProviderThemeVars>
30
- theme?: string | Ref<string>
31
- }) {
32
+ export interface UseConfigProviderOptions {
33
+ themeVars?: MaybeRef<ConfigProviderThemeVars>
34
+ theme?: MaybeRef<string>
35
+ button?: MaybeRef<ButtonConfig>
36
+ tag?: MaybeRef<TagConfig>
37
+ }
38
+
39
+ export function useConfigProvider(options: UseConfigProviderOptions = {}) {
40
+ const { themeVars, theme, button, tag } = options
41
+
32
42
  const themeStyle = computed(() => {
33
43
  const styleObj = mapThemeVarsToCSSVars(unref(themeVars) || {})
34
44
  return styleObj ? `${objToStyle(styleObj)}` : ''
35
45
  })
36
46
 
37
- const themeValue = computed(() => {
38
- return unref(theme) || 'light'
47
+ const globalConfig = computed<GlobalConfig>(() => {
48
+ return mergeConfig(null, {
49
+ theme: unref(theme) || 'light',
50
+ themeVars: unref(themeVars) || {},
51
+ button: unref(button) || {},
52
+ tag: unref(tag) || {}
53
+ } as ConfigProviderInput)
39
54
  })
40
55
 
41
56
  provide(USE_CONFIG_PROVIDER_KEY, {
42
57
  themeStyle,
43
- theme: themeValue
58
+ globalConfig
44
59
  })
45
60
  }
@@ -0,0 +1,9 @@
1
+ import { computed, inject, type ComputedRef } from 'vue'
2
+ import { CONFIG_PROVIDER_KEY, type ConfigProviderProvide } from '../components/wd-config-provider/types'
3
+ import { DEFAULT_GLOBAL_CONFIG, type GlobalConfig } from '../components/wd-config-provider/global-config'
4
+
5
+ export function useGlobalConfig(): ComputedRef<GlobalConfig> {
6
+ const injected = inject<ConfigProviderProvide | null>(CONFIG_PROVIDER_KEY, null)
7
+ if (injected) return injected.globalConfig
8
+ return computed(() => ({ ...DEFAULT_GLOBAL_CONFIG }))
9
+ }
package/index.ts CHANGED
@@ -3,4 +3,4 @@ export { zodAdapter } from './components/wd-form'
3
3
  export type { FormSchema, FormSchemaIssue, FormValidateEvent, FormValidateTrigger } from './components/wd-form'
4
4
  export * as CommonUtil from './common/util'
5
5
  export * from './locale'
6
- export type { ConfigProviderThemeVars } from './components/wd-config-provider/types'
6
+ export type { ConfigProviderThemeVars } from './components/wd-config-provider/theme-vars'
package/package.json CHANGED
@@ -1 +1 @@
1
- {"id":"wot-ui","name":"@wot-ui/ui","displayName":"wot-ui 一个轻量、美观、AI友好的 uni-app 组件库","version":"2.0.8","license":"MIT","description":"wot-ui 一个轻量、美观、AI友好的 uni-app 组件库。","keywords":["wot-ui","国际化","组件库","vue3","暗黑模式"],"main":"index.ts","repository":{"type":"git","url":"https://github.com/wot-ui/wot-ui.git"},"engines":{"HBuilderX":"^3.8.7"},"dcloudext":{"type":"component-vue","sale":{"regular":{"price":"0.00"},"sourcecode":{"price":"0.00"}},"contact":{"qq":""},"declaration":{"ads":"无","data":"插件不采集任何数据","permissions":"无"},"npmurl":"https://www.npmjs.com/package/@wot-ui/ui"},"vetur":{"tags":"tags.json","attributes":"attributes.json"},"web-types":"web-types.json","uni_modules":{"dependencies":[],"encrypt":[],"platforms":{"cloud":{"tcb":"y","aliyun":"y","alipay":"n"},"client":{"Vue":{"vue2":"n","vue3":"y"},"App":{"app-vue":"y","app-nvue":"n","app-uvue":"n"},"H5-mobile":{"Safari":"y","Android Browser":"y","微信浏览器(Android)":"y","QQ浏览器(Android)":"y"},"H5-pc":{"Chrome":"y","IE":"u","Edge":"y","Firefox":"y","Safari":"y"},"小程序":{"微信":"y","阿里":"y","百度":"u","字节跳动":"u","QQ":"y","钉钉":"y","快手":"u","飞书":"u","京东":"u"},"快应用":{"华为":"u","联盟":"u"}}}},"peerDependencies":{"vue":">=3.2.47"}}
1
+ {"id":"wot-ui","name":"@wot-ui/ui","displayName":"wot-ui 一个轻量、美观、AI友好的 uni-app 组件库","version":"2.2.0","license":"MIT","description":"wot-ui 一个轻量、美观、AI友好的 uni-app 组件库。","keywords":["wot-ui","国际化","组件库","vue3","暗黑模式"],"main":"index.ts","repository":{"type":"git","url":"https://github.com/wot-ui/wot-ui.git"},"engines":{"HBuilderX":"^3.8.7"},"dcloudext":{"type":"component-vue","sale":{"regular":{"price":"0.00"},"sourcecode":{"price":"0.00"}},"contact":{"qq":""},"declaration":{"ads":"无","data":"插件不采集任何数据","permissions":"无"},"npmurl":"https://www.npmjs.com/package/@wot-ui/ui"},"vetur":{"tags":"tags.json","attributes":"attributes.json"},"web-types":"web-types.json","uni_modules":{"dependencies":[],"encrypt":[],"platforms":{"cloud":{"tcb":"y","aliyun":"y","alipay":"n"},"client":{"Vue":{"vue2":"n","vue3":"y"},"App":{"app-vue":"y","app-nvue":"n","app-uvue":"n"},"H5-mobile":{"Safari":"y","Android Browser":"y","微信浏览器(Android)":"y","QQ浏览器(Android)":"y"},"H5-pc":{"Chrome":"y","IE":"u","Edge":"y","Firefox":"y","Safari":"y"},"小程序":{"微信":"y","阿里":"y","百度":"u","字节跳动":"u","QQ":"y","钉钉":"y","快手":"u","飞书":"u","京东":"u"},"快应用":{"华为":"u","联盟":"u"}}}},"peerDependencies":{"vue":">=3.2.47"}}