@vyr/design 0.0.1

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 (83) hide show
  1. package/package.json +16 -0
  2. package/src/components/Button.vue +64 -0
  3. package/src/components/Card.vue +203 -0
  4. package/src/components/Cascader.vue +171 -0
  5. package/src/components/Checked.vue +124 -0
  6. package/src/components/CheckedGroup.vue +51 -0
  7. package/src/components/Col.vue +52 -0
  8. package/src/components/ColorPicker.vue +331 -0
  9. package/src/components/Confirm.vue +86 -0
  10. package/src/components/Dialog.vue +220 -0
  11. package/src/components/Divider.vue +40 -0
  12. package/src/components/Draggable.vue +50 -0
  13. package/src/components/Dropdown.vue +175 -0
  14. package/src/components/DynamicDialog.vue +113 -0
  15. package/src/components/DynamicLayouter.vue +235 -0
  16. package/src/components/Form.vue +88 -0
  17. package/src/components/Input.vue +254 -0
  18. package/src/components/InputNumber.vue +96 -0
  19. package/src/components/Label.vue +116 -0
  20. package/src/components/Loading.vue +196 -0
  21. package/src/components/Mask.vue +47 -0
  22. package/src/components/Notify.vue +130 -0
  23. package/src/components/Option.vue +159 -0
  24. package/src/components/Options.vue +202 -0
  25. package/src/components/Popover.vue +271 -0
  26. package/src/components/Provider.vue +12 -0
  27. package/src/components/RightMenu.vue +127 -0
  28. package/src/components/Row.vue +50 -0
  29. package/src/components/Scroll.vue +99 -0
  30. package/src/components/Select.vue +223 -0
  31. package/src/components/Slot.vue +23 -0
  32. package/src/components/SubTree.vue +262 -0
  33. package/src/components/Tree.vue +129 -0
  34. package/src/components/common/DraggableController.ts +113 -0
  35. package/src/components/common/ResizeListener.ts +49 -0
  36. package/src/components/composables/useDefaultProps.ts +179 -0
  37. package/src/components/composables/useDraggable.ts +65 -0
  38. package/src/components/composables/useGetter.ts +15 -0
  39. package/src/components/composables/useMarginStyle.ts +45 -0
  40. package/src/components/composables/usePopover.ts +33 -0
  41. package/src/components/composables/useProvider.ts +186 -0
  42. package/src/components/composables/useScroll.ts +46 -0
  43. package/src/components/composables/useSearch.ts +97 -0
  44. package/src/components/composables/useTimer.ts +5 -0
  45. package/src/components/index.ts +1 -0
  46. package/src/components/singleton/confirm.ts +25 -0
  47. package/src/components/singleton/dialog.ts +25 -0
  48. package/src/components/singleton/index.ts +5 -0
  49. package/src/components/singleton/loading.ts +36 -0
  50. package/src/components/singleton/notify.ts +36 -0
  51. package/src/components/types/index.ts +82 -0
  52. package/src/components/utils/Cascader.ts +52 -0
  53. package/src/components/utils/Confirm.ts +41 -0
  54. package/src/components/utils/Dialog.ts +38 -0
  55. package/src/components/utils/DynamicDialog.ts +41 -0
  56. package/src/components/utils/DynamicLayouter.ts +5 -0
  57. package/src/components/utils/FloatLayer.ts +40 -0
  58. package/src/components/utils/InputNumber.ts +3 -0
  59. package/src/components/utils/Notify.ts +25 -0
  60. package/src/components/utils/Popover.ts +58 -0
  61. package/src/components/utils/RightMenu.ts +21 -0
  62. package/src/components/utils/Scroll.ts +4 -0
  63. package/src/components/utils/Slot.ts +73 -0
  64. package/src/components/utils/index.ts +12 -0
  65. package/src/font/demo.css +539 -0
  66. package/src/font/demo_index.html +1292 -0
  67. package/src/font/iconfont.css +207 -0
  68. package/src/font/iconfont.js +1 -0
  69. package/src/font/iconfont.json +345 -0
  70. package/src/font/iconfont.ttf +0 -0
  71. package/src/font/iconfont.woff +0 -0
  72. package/src/font/iconfont.woff2 +0 -0
  73. package/src/index.ts +68 -0
  74. package/src/locale/Language.ts +10 -0
  75. package/src/locale/LanguageProvider.ts +38 -0
  76. package/src/locale/index.ts +2 -0
  77. package/src/theme/global.less +91 -0
  78. package/src/theme/index.ts +155 -0
  79. package/src/tool/ArrayUtils.ts +38 -0
  80. package/src/tool/Color.ts +7 -0
  81. package/src/tool/Draggable.ts +36 -0
  82. package/src/tool/Listener.ts +59 -0
  83. package/src/tool/index.ts +4 -0
@@ -0,0 +1,254 @@
1
+ <template>
2
+ <div class="vyr-input" :class="{ 'clearable': curClearable, 'icon': $slots.icon }" :style="`width:${curInputWidth};`"
3
+ @click="e => emit('click', e)" @mouseenter="mouseenter" @mouseleave="mouseleave" @mouseup="mouseup">
4
+ <input ref="refInput" class="input-wrapper" tabindex="-1" v-focus="curReadonly ? false : autofocus"
5
+ :class="{ 'readonly': curReadonly, 'icon': curClearable, 'draggable': drag.draggable }" :type="type"
6
+ :placeholder="placeholder" :value="currentValue" :readonly="curReadonly" @input="inputValue" @focus="focus"
7
+ @blur="blurValue" @compositionstart="compositionstart" @compositionend="compositionend" />
8
+ <div class="icon-wrapper">
9
+ <slot name="icon" :clearable="curClearable">
10
+ <transition name="vyr-transition">
11
+ <i class="vyrfont vyr-shanchu vyr-input-icon"
12
+ v-if="showClear(curClearable, curReadonly, curReadonlyClearable, currentValue) && drag.enabled === false"
13
+ @click.stop="clear"></i>
14
+ </transition>
15
+ </slot>
16
+ </div>
17
+ </div>
18
+ </template>
19
+
20
+ <script lang="ts" setup>
21
+ import { ref, reactive, Directive, watch, useTemplateRef } from 'vue'
22
+ import { commonDefaultProps, inputCommonDefaultProps, inputDefaultProps, useInputCommonProps } from './composables/useDefaultProps'
23
+ import { useCommonPropsOnInput } from './composables/useDefaultProps';
24
+ import { useValidateItemProvider } from './composables/useProvider';
25
+ import { DraggableController } from './common/DraggableController';
26
+ import { Draggable } from '../tool'
27
+
28
+ const props = defineProps({
29
+ ...commonDefaultProps,
30
+ ...inputCommonDefaultProps,
31
+ ...inputDefaultProps,
32
+ type: { default: 'text' },
33
+ trigger: { default: 'input' as 'input' | 'blur' },
34
+ autofocus: { default: false },
35
+ })
36
+ const vFocus: Directive = { mounted(el, props) { if (props.value === true) el.focus() } }
37
+
38
+ const currentValue = ref('')
39
+ const watchModelValue = () => currentValue.value = props.modelValue
40
+ watch(() => props.modelValue, watchModelValue, { immediate: true })
41
+
42
+ const refInput = useTemplateRef('refInput')
43
+ const emit = defineEmits(['update:modelValue', 'focus', 'blur', 'click', 'clear'])
44
+ const { curReadonly, curClearable, curReadonlyClearable, enterInput, leaveInput, showClear } = useCommonPropsOnInput(props)
45
+ const { curInputWidth } = useInputCommonProps(props)
46
+
47
+ const composition = ref(false)
48
+ const isFocus = ref(false)
49
+ const confirm = (e: KeyboardEvent) => {
50
+ if (e.code === 'Escape') expose.blur()
51
+ }
52
+ const compositionstart = () => {
53
+ composition.value = true
54
+ }
55
+ const compositionend = (e: CompositionEvent) => {
56
+ if (composition.value === false) return
57
+ composition.value = false
58
+ inputValue()
59
+ }
60
+ const focus = () => {
61
+ if (curReadonly.value === true) return
62
+ emit('focus')
63
+ window.addEventListener('keydown', confirm)
64
+ isFocus.value = true
65
+ }
66
+ const inputValue = () => {
67
+ if (composition.value === true) return
68
+ currentValue.value = refInput.value?.value ?? ''
69
+ if (props.trigger !== 'input') return
70
+ emit('update:modelValue', currentValue.value)
71
+ }
72
+ const validateProvider = useValidateItemProvider()
73
+ const blurValue = () => {
74
+ composition.value = false
75
+ if (curReadonly.value === true) return
76
+ currentValue.value = refInput.value?.value ?? ''
77
+ if (props.trigger === 'blur') emit('update:modelValue', currentValue.value)
78
+ emit('blur', currentValue.value)
79
+ validateProvider.value.validate(currentValue.value)
80
+ isFocus.value = false
81
+ window.removeEventListener('keydown', confirm)
82
+ }
83
+ const clear = (e: MouseEvent) => {
84
+ emit('update:modelValue', '')
85
+ emit('clear', e)
86
+ if (isFocus.value === false) validateProvider.value.validate('')
87
+ }
88
+
89
+ const drag = reactive({
90
+ enabled: false,
91
+ draggable: false
92
+ })
93
+ const mouseenter = (e: MouseEvent) => {
94
+ if (composition.value === true) return
95
+ enterInput()
96
+ if (curReadonly.value === true) return
97
+ drag.enabled = DraggableController.enabled
98
+ if (DraggableController.enabled === false || props.draggable === false) return
99
+ drag.draggable = DraggableController.enter({ key: props.dragkey, value: currentValue.value }, props.draggable)
100
+ }
101
+ const mouseleave = (e: MouseEvent) => {
102
+ if (composition.value === true) return
103
+ leaveInput()
104
+ drag.enabled = false
105
+ if (DraggableController.enabled === false || props.draggable === false) return
106
+ drag.draggable = false
107
+ }
108
+ const mouseup = (e: MouseEvent) => {
109
+ if (curReadonly.value === true) return
110
+ drag.enabled = false
111
+ if (DraggableController.enabled === false || props.draggable === false) return
112
+ DraggableController.end({ key: props.dragkey, value: currentValue.value }, props.draggable, 'insert')
113
+ drag.draggable = false
114
+ }
115
+
116
+ const expose = {
117
+ isFocus,
118
+ focus() {
119
+ if (!refInput.value) return
120
+ refInput.value.focus()
121
+ },
122
+ blur() {
123
+ if (!refInput.value) return
124
+ refInput.value.blur()
125
+ },
126
+ setValue(str: string) {
127
+ if (!refInput.value) return
128
+ refInput.value.value = str
129
+ currentValue.value = str
130
+ }
131
+ }
132
+ defineExpose(expose)
133
+ </script>
134
+
135
+ <style lang="less" scoped>
136
+ @import '../theme/global.less';
137
+
138
+ .vyr-input {
139
+ .vyr-font-family;
140
+ color: var(--vyr-font-color);
141
+ font-size: var(--vyr-font-size);
142
+ position: relative;
143
+ left: 0;
144
+ top: 0;
145
+ overflow-x: hidden;
146
+ overflow-y: hidden;
147
+ display: inline-flex;
148
+ flex-wrap: nowrap;
149
+ flex-direction: row;
150
+
151
+ .input-wrapper {
152
+ .vyr-font-family;
153
+ width: 100%;
154
+ height: var(--vyr-input-height);
155
+ line-height: var(--vyr-input-height);
156
+ box-sizing: border-box;
157
+ padding: 0 var(--vyr-input-l-r-padding);
158
+ border-radius: var(--vyr-input-radius);
159
+ font-size: var(--vyr-input-font-size);
160
+ color: var(--vyr-input-font-color);
161
+ background-color: var(--vyr-input-background-color);
162
+ border: var(--vyr-input-border-size) solid var(--vyr-input-border-color);
163
+ user-select: none;
164
+ outline: none;
165
+ transition: border var(--vyr-animation-time);
166
+ }
167
+
168
+ .input-wrapper[type="password"]::-ms-reveal {
169
+ display: none;
170
+ }
171
+
172
+ .input-wrapper:focus {
173
+ border: var(--vyr-border-size) solid var(--vyr-active-topic-color);
174
+ }
175
+
176
+ .input-wrapper::placeholder {
177
+ color: var(--vyr-input-placeholder-color);
178
+ font-size: var(--vyr-font-size);
179
+ }
180
+
181
+ .input-wrapper.readonly {
182
+ caret-color: transparent;
183
+ }
184
+
185
+ .input-wrapper.draggable {
186
+ border: var(--vyr-border-size) dashed var(--vyr-draggable-color);
187
+ animation: input-draggable 1s infinite;
188
+ }
189
+
190
+ .icon-wrapper {
191
+ @height: calc(var(--vyr-input-border-size) * 2);
192
+ width: var(--vyr-input-icon-size);
193
+ height: calc(~'100% - @{height}');
194
+ position: absolute;
195
+ right: 0;
196
+ top: 50%;
197
+ transform: translate(-2px, -50%);
198
+ z-index: 1;
199
+ display: flex;
200
+ flex-wrap: nowrap;
201
+ flex-direction: row;
202
+ justify-content: center;
203
+ align-items: center;
204
+ align-content: center;
205
+ transition: all var(--vyr-animation-time);
206
+ padding: 0 2px;
207
+ box-sizing: border-box;
208
+ pointer-events: none;
209
+ cursor: pointer;
210
+
211
+ .vyr-shanchu {
212
+ font-size: 18px;
213
+ pointer-events: auto;
214
+ }
215
+
216
+ .vyr-shanchu:hover {
217
+ color: var(--vyr-active-topic-color);
218
+ }
219
+ }
220
+ }
221
+
222
+ .vyr-input.clearable,
223
+ .vyr-input.icon {
224
+ .input-wrapper {
225
+ padding-right: var(--vyr-input-icon-size);
226
+ }
227
+ }
228
+
229
+ .vyr-input.modify {
230
+ .input-wrapper {
231
+ padding-left: 4px;
232
+ }
233
+ }
234
+
235
+ .vyr-drag-mouse {
236
+ .vyr-input {
237
+ .input-wrapper {
238
+ cursor: move;
239
+ }
240
+ }
241
+ }
242
+
243
+ @keyframes input-draggable {
244
+
245
+ 0%,
246
+ 100% {
247
+ border-color: var(--vyr-input-border-color);
248
+ }
249
+
250
+ 50% {
251
+ border-color: var(--vyr-draggable-color);
252
+ }
253
+ }
254
+ </style>
@@ -0,0 +1,96 @@
1
+ <template>
2
+ <div class="vyr-input-number" :style="`width:${curInputWidth};`">
3
+ <vyr-input ref="refInput" :model-value="state.input" :placeholder="placeholder" :autofocus="autofocus"
4
+ :readonly="curReadonly" :clearable="curClearable" :width="curInputWidth" @update:model-value="inputValue"
5
+ @blur="blurValue" @clear="clear" />
6
+ </div>
7
+ </template>
8
+
9
+ <script lang="ts" setup>
10
+ import { ref, useTemplateRef, watch } from 'vue'
11
+ import { inputNumberReExp } from './utils';
12
+ import { useCommonProps, useInputCommonProps } from './composables/useDefaultProps'
13
+ import { commonDefaultProps, inputCommonDefaultProps, inputDefaultProps } from './composables/useDefaultProps'
14
+ import VyrInput from './Input.vue'
15
+
16
+ const props = defineProps({
17
+ ...commonDefaultProps,
18
+ ...inputCommonDefaultProps,
19
+ ...inputDefaultProps,
20
+ autofocus: { default: false },
21
+ step: { default: 'auto' as 'auto' | number },
22
+ min: { default: null as null | number },
23
+ max: { default: null as null | number },
24
+ allowNull: { default: true },
25
+ defaultValue: { default: 0 },
26
+ })
27
+
28
+ const refInput = useTemplateRef('refInput')
29
+ const state = ref({
30
+ input: '' as string | number,
31
+ })
32
+
33
+ const emit = defineEmits(['update:modelValue', 'blur'])
34
+ const { curReadonly, curClearable } = useCommonProps(props)
35
+ const { curInputWidth } = useInputCommonProps(props)
36
+
37
+ const formatData = (str: string) => {
38
+ const parse = str.match(inputNumberReExp)
39
+ return parse === null ? '' : parse[0]
40
+ }
41
+ const toNumber = (value: string) => {
42
+ const number = parseFloat(value)
43
+ return isNaN(number) ? 0 : number
44
+ }
45
+
46
+ const watchModelValue = () => {
47
+ if (props.modelValue === '') {
48
+ state.value.input = ''
49
+ } else {
50
+ const value = props.modelValue ?? ''
51
+ state.value.input = toNumber(formatData(value.toString()))
52
+ emit('update:modelValue', state.value.input)
53
+ }
54
+ }
55
+ watch(() => props.modelValue, watchModelValue, { immediate: true })
56
+
57
+ const inputValue = (str: string) => {
58
+ const value = formatData(str)
59
+ refInput.value?.setValue(value)
60
+ state.value.input = value
61
+ }
62
+ const updateBlurValue = (value: number | string) => {
63
+ emit('update:modelValue', value)
64
+ emit('blur', value)
65
+ }
66
+ const blurValue = () => {
67
+ if (state.value.input === '') {
68
+ if (props.allowNull === true) return updateBlurValue('')
69
+ state.value.input = props.defaultValue
70
+ }
71
+
72
+ let output = toNumber(state.value.input.toString())
73
+ if (props.step !== 'auto') {
74
+ const count = Math.round(output / props.step)
75
+ output = count * props.step
76
+ }
77
+ if (props.max !== null) output = Math.min(props.max, output)
78
+ if (props.min !== null) output = Math.max(props.min, output)
79
+ refInput.value?.setValue(output.toString())
80
+ updateBlurValue(output)
81
+ }
82
+ const clear = () => {
83
+ emit('update:modelValue', '')
84
+ }
85
+ </script>
86
+
87
+ <style lang="less" scoped>
88
+ @import '../theme/global.less';
89
+
90
+ .vyr-input-number {
91
+ .vyr-font-family;
92
+ display: inline-flex;
93
+ flex-wrap: nowrap;
94
+ flex-direction: row;
95
+ }
96
+ </style>
@@ -0,0 +1,116 @@
1
+ <template>
2
+ <div class="vyr-label">
3
+ <div class="label-header" v-if="width !== '0%'" :class="align" :style="`width:${width};`">
4
+ <i class="vyrfont vyr-bitian" v-if="formProvider.rules.length && formProvider.options.icon"
5
+ :style="`opacity:${rule && formProvider.options.icon ? '1' : '0'}`">
6
+ </i>
7
+ {{ label }}
8
+ </div>
9
+ <div class="label-body" :class="{ 'error': errorStatus }"
10
+ :style="`width:calc(100% - ${width});${verticalAlign === 'center' ? 'display:flex;' : ''}`">
11
+ <slot></slot>
12
+ <transition name="vyr-transition">
13
+ <div class="label-error" v-if="errorStatus && formProvider.options.tips">{{ error }}</div>
14
+ </transition>
15
+ </div>
16
+ </div>
17
+ </template>
18
+
19
+ <script lang="ts" setup>
20
+ import { computed, watch, ref } from 'vue'
21
+ import { useValidateProvider, useProvider, updateValidateItemProvider } from './composables/useProvider'
22
+ import { labelCommonDefaultProps } from './composables/useDefaultProps'
23
+
24
+ const props = defineProps({
25
+ ...labelCommonDefaultProps,
26
+ label: { default: '' },
27
+ rule: { default: '' },
28
+ verticalAlign: { default: '' }
29
+ })
30
+ const provider = useProvider()
31
+ const width = computed(() => {
32
+ const width = props.width === null ? provider.value.label.width : props.width
33
+ return width > 1 ? `${width}px` : `${width * 100}%`
34
+ })
35
+ const align = computed(() => {
36
+ return props.align === null ? provider.value.label.align : props.align
37
+ })
38
+
39
+ const formProvider = useValidateProvider()
40
+ const watchRule = (cur: string, old: string | undefined) => {
41
+ if (old !== undefined) formProvider.value.removeRule(old)
42
+ if (cur !== '') formProvider.value.addRule(cur)
43
+ }
44
+ watch(() => props.rule, watchRule, { immediate: true })
45
+ const error = computed(() => {
46
+ const message = formProvider.value.validateCollection[props.rule]
47
+ return message === undefined ? false : message
48
+ })
49
+ const errorStatus = computed(() => {
50
+ return error.value === false ? false : true
51
+ })
52
+
53
+ const validate = (value: any) => {
54
+ if (props.rule === '') return
55
+ formProvider.value.validateItem(props.rule, value)
56
+ }
57
+ updateValidateItemProvider(ref({ validate }))
58
+ </script>
59
+
60
+ <style lang="less" scoped>
61
+ @import '../theme/global.less';
62
+
63
+ .vyr-label {
64
+ .vyr-font-family;
65
+ color: var(--vyr-font-color);
66
+ width: 100%;
67
+ font-size: var(--vyr-font-size);
68
+ display: flex;
69
+ flex-wrap: nowrap;
70
+ flex-direction: row;
71
+
72
+ .label-header {
73
+ height: var(--vyr-input-height);
74
+ line-height: var(--vyr-input-height);
75
+ overflow: hidden;
76
+ word-break: break-all;
77
+ white-space: nowrap;
78
+ text-overflow: ellipsis;
79
+ padding: 0 10px 0 0;
80
+ box-sizing: border-box;
81
+
82
+ .vyrfont {
83
+ font-size: 12px;
84
+ color: var(--vyr-red-color);
85
+ }
86
+ }
87
+
88
+ .label-body {
89
+ min-height: var(--vyr-input-height);
90
+ position: relative;
91
+ left: 0;
92
+ top: 0;
93
+
94
+ .label-error {
95
+ width: 100%;
96
+ position: absolute;
97
+ left: 0;
98
+ top: 100%;
99
+ padding: 6px 0 0 0;
100
+ font-size: 12px;
101
+ color: var(--vyr-red-color);
102
+ line-height: 1em;
103
+ }
104
+ }
105
+
106
+ .label-body.error {
107
+ :deep(.vyr-input) {
108
+ color: var(--vyr-red-color);
109
+
110
+ .input-wrapper {
111
+ border-color: var(--vyr-red-color);
112
+ }
113
+ }
114
+ }
115
+ }
116
+ </style>
@@ -0,0 +1,196 @@
1
+ <template>
2
+ <teleport to="body">
3
+ <Transition :duration="state.duration" @before-enter="onBeforeEnter" @enter="onEnter" @after-enter="onAfterEnter"
4
+ @enter-cancelled="onEnterCancelled" @before-leave="onBeforeLeave" @leave="onLeave" @after-leave="onAfterLeave"
5
+ @leave-cancelled="onLeaveCancelled">
6
+ <div class="vyr-loading" v-show="state.visible" :style="`opacity:${state.opacity};`">
7
+ <div class="loading">
8
+ <div class="loading-inspector">
9
+ <div class="loading-inspector-line">
10
+ <span v-for="index of 10" :key="index" :style="'animation-delay:' + index * 0.1 + 's;'"></span>
11
+ </div>
12
+ </div>
13
+ <div class="loading-text">Loading...</div>
14
+ </div>
15
+ </div>
16
+ </Transition>
17
+ </teleport>
18
+ </template>
19
+
20
+ <script lang="ts" setup>
21
+ import { ref } from 'vue'
22
+ import { LoadingVue } from './types'
23
+
24
+ const state = ref({
25
+ visible: false,
26
+ duration: 500,
27
+ opacityMax: 0.2,
28
+ opacity: 0,
29
+ playing: false,
30
+ step: 0,
31
+ runId: 0,
32
+ })
33
+ const setVisible = (v: boolean) => {
34
+ state.value.visible = v
35
+ }
36
+
37
+ defineExpose<LoadingVue>({ setVisible })
38
+
39
+ const computeStep = () => {
40
+ const count = (state.value.duration / 1000) * 60
41
+ state.value.step = state.value.opacityMax / count
42
+ }
43
+ const runEnter = () => {
44
+ state.value.runId = requestAnimationFrame(runEnter)
45
+ state.value.opacity += state.value.step
46
+ }
47
+ const runLeave = () => {
48
+ state.value.runId = requestAnimationFrame(runLeave)
49
+ state.value.opacity -= state.value.step
50
+ }
51
+ const stop = () => {
52
+ cancelAnimationFrame(state.value.runId)
53
+ }
54
+
55
+ const onBeforeEnter = () => {
56
+ if (state.value.playing === false) state.value.opacity = 0
57
+ computeStep()
58
+ }
59
+
60
+ const onEnter = () => {
61
+ state.value.playing = true
62
+ runEnter()
63
+ }
64
+
65
+ const onAfterEnter = () => {
66
+ state.value.playing = false
67
+ stop()
68
+ }
69
+
70
+ const onEnterCancelled = () => {
71
+ stop()
72
+ }
73
+
74
+ const onBeforeLeave = () => {
75
+ if (state.value.playing === false) state.value.opacity = state.value.opacityMax
76
+ computeStep()
77
+ }
78
+
79
+ const onLeave = () => {
80
+ state.value.playing = true
81
+ runLeave()
82
+ }
83
+
84
+ const onAfterLeave = () => {
85
+ state.value.playing = false
86
+ stop()
87
+ }
88
+
89
+ const onLeaveCancelled = () => {
90
+ stop()
91
+ }
92
+
93
+ </script>
94
+
95
+ <style lang="less" scoped>
96
+ @import '../theme/global.less';
97
+
98
+ @loading-font-size: 24px;
99
+
100
+ .vyr-loading {
101
+ .vyr-font-family;
102
+ color: var(--vyr-font-color);
103
+ font-size: var(--vyr-font-size);
104
+ position: fixed;
105
+ left: 0;
106
+ top: 0;
107
+ width: 100%;
108
+ height: 100%;
109
+ z-index: var(--vyr-z-index);
110
+ color: var(--vyr-black-color);
111
+ background-color: var(--vyr-black-color);
112
+
113
+ .loading {
114
+ width: 50%;
115
+ position: absolute;
116
+ left: 50%;
117
+ top: 50%;
118
+ transform: translate(-50%, -50%);
119
+ display: flex;
120
+ flex-wrap: nowrap;
121
+ flex-direction: column;
122
+ justify-content: center;
123
+ align-items: center;
124
+ align-content: center;
125
+ }
126
+
127
+ .loading-inspector {
128
+ width: 100%;
129
+ display: flex;
130
+ flex-wrap: nowrap;
131
+ flex-direction: row;
132
+ justify-content: center;
133
+ align-items: center;
134
+ align-content: center;
135
+
136
+ div {
137
+ height: 60px;
138
+ display: flex;
139
+ flex-wrap: nowrap;
140
+ flex-direction: row;
141
+ justify-content: center;
142
+ align-items: center;
143
+ align-content: center;
144
+ }
145
+
146
+ div>span {
147
+ width: 4px;
148
+ height: 100%;
149
+ margin: 0 4px;
150
+ border-radius: var(--vyr-radius-size);
151
+ background-color: var(--vyr-white-color);
152
+ display: inline-block;
153
+ opacity: 0;
154
+ animation: loading_inspector 0.8s infinite;
155
+ }
156
+ }
157
+
158
+ .loading-text {
159
+ font-size: @loading-font-size;
160
+ color: var(--vyr-white-color);
161
+ font-weight: bold;
162
+ letter-spacing: 2px;
163
+ animation: loading 4s infinite;
164
+ }
165
+
166
+ //loading动画
167
+ @keyframes loading_inspector {
168
+
169
+ 0%,
170
+ 100% {
171
+ transform: scale(100%, 0);
172
+ opacity: 1;
173
+ }
174
+
175
+ 50% {
176
+ transform: scale(100%, 100%);
177
+ }
178
+ }
179
+
180
+ @keyframes loading {
181
+
182
+ 0%,
183
+ 100% {
184
+ color: var(--vyr-blue-color);
185
+ }
186
+
187
+ 33.33% {
188
+ color: var(--vyr-yellow-color);
189
+ }
190
+
191
+ 66.66% {
192
+ color: var(--vyr-red-color);
193
+ }
194
+ }
195
+ }
196
+ </style>
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <teleport to="body">
3
+ <transition name="vyr-transition" @before-enter="addFloatLayer(maskId)" @after-leave="hide">
4
+ <template v-if="visible">
5
+ <div v-if="mask" class="vyr-mask" :style="layerStyle" @contextmenu.prevent.stop>
6
+ <slot :layer="layerStyle"></slot>
7
+ </div>
8
+ <slot v-else :layer="layerStyle"></slot>
9
+ </template>
10
+ </transition>
11
+ </teleport>
12
+ </template>
13
+
14
+ <script lang="ts" setup>
15
+ import { computed } from 'vue';
16
+ import { maskCommonDefaultProps } from './composables/useDefaultProps'
17
+ import { addFloatLayer, removeFloatLayer } from './utils/FloatLayer';
18
+
19
+ const props = defineProps({
20
+ maskId: {} as { default: number },
21
+ layer: { default: -1 },
22
+ ...maskCommonDefaultProps,
23
+ })
24
+
25
+ const layerStyle = computed(() => {
26
+ return props.layer === -1 ? '' : `z-index:${props.layer};`
27
+ })
28
+
29
+ const emit = defineEmits(['close'])
30
+ const hide = () => {
31
+ removeFloatLayer(props.maskId)
32
+ emit('close')
33
+ }
34
+ </script>
35
+
36
+ <style lang="less" scoped>
37
+ @import '../theme/global.less';
38
+
39
+ .vyr-mask {
40
+ .vyr-font-family;
41
+ width: 100%;
42
+ height: 100%;
43
+ position: fixed;
44
+ left: 0;
45
+ top: 0;
46
+ }
47
+ </style>