@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.
- package/package.json +16 -0
- package/src/components/Button.vue +64 -0
- package/src/components/Card.vue +203 -0
- package/src/components/Cascader.vue +171 -0
- package/src/components/Checked.vue +124 -0
- package/src/components/CheckedGroup.vue +51 -0
- package/src/components/Col.vue +52 -0
- package/src/components/ColorPicker.vue +331 -0
- package/src/components/Confirm.vue +86 -0
- package/src/components/Dialog.vue +220 -0
- package/src/components/Divider.vue +40 -0
- package/src/components/Draggable.vue +50 -0
- package/src/components/Dropdown.vue +175 -0
- package/src/components/DynamicDialog.vue +113 -0
- package/src/components/DynamicLayouter.vue +235 -0
- package/src/components/Form.vue +88 -0
- package/src/components/Input.vue +254 -0
- package/src/components/InputNumber.vue +96 -0
- package/src/components/Label.vue +116 -0
- package/src/components/Loading.vue +196 -0
- package/src/components/Mask.vue +47 -0
- package/src/components/Notify.vue +130 -0
- package/src/components/Option.vue +159 -0
- package/src/components/Options.vue +202 -0
- package/src/components/Popover.vue +271 -0
- package/src/components/Provider.vue +12 -0
- package/src/components/RightMenu.vue +127 -0
- package/src/components/Row.vue +50 -0
- package/src/components/Scroll.vue +99 -0
- package/src/components/Select.vue +223 -0
- package/src/components/Slot.vue +23 -0
- package/src/components/SubTree.vue +262 -0
- package/src/components/Tree.vue +129 -0
- package/src/components/common/DraggableController.ts +113 -0
- package/src/components/common/ResizeListener.ts +49 -0
- package/src/components/composables/useDefaultProps.ts +179 -0
- package/src/components/composables/useDraggable.ts +65 -0
- package/src/components/composables/useGetter.ts +15 -0
- package/src/components/composables/useMarginStyle.ts +45 -0
- package/src/components/composables/usePopover.ts +33 -0
- package/src/components/composables/useProvider.ts +186 -0
- package/src/components/composables/useScroll.ts +46 -0
- package/src/components/composables/useSearch.ts +97 -0
- package/src/components/composables/useTimer.ts +5 -0
- package/src/components/index.ts +1 -0
- package/src/components/singleton/confirm.ts +25 -0
- package/src/components/singleton/dialog.ts +25 -0
- package/src/components/singleton/index.ts +5 -0
- package/src/components/singleton/loading.ts +36 -0
- package/src/components/singleton/notify.ts +36 -0
- package/src/components/types/index.ts +82 -0
- package/src/components/utils/Cascader.ts +52 -0
- package/src/components/utils/Confirm.ts +41 -0
- package/src/components/utils/Dialog.ts +38 -0
- package/src/components/utils/DynamicDialog.ts +41 -0
- package/src/components/utils/DynamicLayouter.ts +5 -0
- package/src/components/utils/FloatLayer.ts +40 -0
- package/src/components/utils/InputNumber.ts +3 -0
- package/src/components/utils/Notify.ts +25 -0
- package/src/components/utils/Popover.ts +58 -0
- package/src/components/utils/RightMenu.ts +21 -0
- package/src/components/utils/Scroll.ts +4 -0
- package/src/components/utils/Slot.ts +73 -0
- package/src/components/utils/index.ts +12 -0
- package/src/font/demo.css +539 -0
- package/src/font/demo_index.html +1292 -0
- package/src/font/iconfont.css +207 -0
- package/src/font/iconfont.js +1 -0
- package/src/font/iconfont.json +345 -0
- package/src/font/iconfont.ttf +0 -0
- package/src/font/iconfont.woff +0 -0
- package/src/font/iconfont.woff2 +0 -0
- package/src/index.ts +68 -0
- package/src/locale/Language.ts +10 -0
- package/src/locale/LanguageProvider.ts +38 -0
- package/src/locale/index.ts +2 -0
- package/src/theme/global.less +91 -0
- package/src/theme/index.ts +155 -0
- package/src/tool/ArrayUtils.ts +38 -0
- package/src/tool/Color.ts +7 -0
- package/src/tool/Draggable.ts +36 -0
- package/src/tool/Listener.ts +59 -0
- package/src/tool/index.ts +4 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<vyr-slot v-if="trigger === 'click'" @slot-change="changeTrigger" @click="click" @contextmenu="rightClick">
|
|
3
|
+
<slot name="trigger"></slot>
|
|
4
|
+
</vyr-slot>
|
|
5
|
+
<vyr-slot v-else @slot-change="changeTrigger" @mouseenter="mouseenter" @mouseleave="mouseleave"
|
|
6
|
+
@mousemove="delayDispatch">
|
|
7
|
+
<slot name="trigger"></slot>
|
|
8
|
+
</vyr-slot>
|
|
9
|
+
<teleport :to="tooltip.wrapper" :disabled="popoverProvider.appendToTooltip === false">
|
|
10
|
+
<div class="vyr-popover" ref="refPopover" data-vyr-popper-hidden :class="{
|
|
11
|
+
'card': popoverCard,
|
|
12
|
+
[popoverClass]: true
|
|
13
|
+
}" :style="{ width: popoverWidth, zIndex: layerStyle }" @mouseenter="state.needClose = false"
|
|
14
|
+
@mouseleave="mouseleave" @contextmenu.prevent.stop @transitionend="animationEnd">
|
|
15
|
+
<div class="popover-arrow" data-popper-arrow :style="`opacity:${arrow ? 1 : 0}`"></div>
|
|
16
|
+
<div class="popover-wrapper" :class="{ 'flex': popoverProvider.useFlexLayout }">
|
|
17
|
+
<slot></slot>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</teleport>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script lang="ts" setup>
|
|
24
|
+
import { Instance } from '@popperjs/core';
|
|
25
|
+
import { watch, ref, onBeforeUnmount, computed, useTemplateRef } from 'vue'
|
|
26
|
+
import { popoverCommonDefaultProps } from './composables/useDefaultProps'
|
|
27
|
+
import { usePopoverProvider, useFlotaLayerProvider } from './composables/useProvider'
|
|
28
|
+
import { createPopper, getOptions, isContains, tooltip } from './utils';
|
|
29
|
+
import { PopoverExpose } from './composables/usePopover';
|
|
30
|
+
import VyrSlot from './Slot.vue'
|
|
31
|
+
|
|
32
|
+
const props = defineProps({
|
|
33
|
+
...popoverCommonDefaultProps,
|
|
34
|
+
popoverCard: { default: true },
|
|
35
|
+
popoverWidth: { default: 'auto' },
|
|
36
|
+
modelValue: { default: false },
|
|
37
|
+
trigger: { default: 'click' as 'click' | 'hover' },
|
|
38
|
+
disabled: { default: false },
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
let popper = null as unknown as Instance
|
|
42
|
+
const emit = defineEmits(['update:modelValue', 'show', 'close', 'triggerChange'])
|
|
43
|
+
const refPopover = useTemplateRef('refPopover')
|
|
44
|
+
|
|
45
|
+
const changeTrigger = (cur: Element, old: HTMLElement) => {
|
|
46
|
+
if (cur) setup(cur)
|
|
47
|
+
emit('triggerChange', cur, old)
|
|
48
|
+
}
|
|
49
|
+
const setup = (cur: Element) => {
|
|
50
|
+
if (popper) popper.destroy()
|
|
51
|
+
if (!refPopover.value) return
|
|
52
|
+
popper = createPopper(cur, refPopover.value, getOptions(props))
|
|
53
|
+
}
|
|
54
|
+
const unsetup = () => {
|
|
55
|
+
unbindTrigger()
|
|
56
|
+
popper.destroy()
|
|
57
|
+
}
|
|
58
|
+
onBeforeUnmount(unsetup)
|
|
59
|
+
const animationEnd = (event: TransitionEvent) => {
|
|
60
|
+
if (state.value.visible === true || event.target !== refPopover.value || event.propertyName !== 'opacity') return
|
|
61
|
+
popper.setOptions(getOptions(props, false))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const hideAttrbute = 'data-vyr-popper-hidden'
|
|
65
|
+
const updatePopoverOnMove = () => popper.update()
|
|
66
|
+
const closePopoverOnClick = (e: MouseEvent | KeyboardEvent) => {
|
|
67
|
+
if (state.value.visible === false || popoverProvider.value.autoClose === false) return
|
|
68
|
+
if ((e.target instanceof Node) && isContains(e.target, [refPopover.value, popper.state.elements.reference])) return
|
|
69
|
+
setVisible(false)
|
|
70
|
+
}
|
|
71
|
+
const closeOfKeydownESC = (e: KeyboardEvent) => {
|
|
72
|
+
if (e.code !== 'Escape') return
|
|
73
|
+
closePopoverOnClick(e)
|
|
74
|
+
}
|
|
75
|
+
const unbindTrigger = () => {
|
|
76
|
+
window.removeEventListener('click', closePopoverOnClick)
|
|
77
|
+
window.removeEventListener('keyup', closeOfKeydownESC)
|
|
78
|
+
if (flotaLayerProvider !== null) flotaLayerProvider.listener.unlisten('move', updatePopoverOnMove)
|
|
79
|
+
}
|
|
80
|
+
const bindTrigger = () => {
|
|
81
|
+
window.addEventListener('click', closePopoverOnClick)
|
|
82
|
+
window.addEventListener('keyup', closeOfKeydownESC)
|
|
83
|
+
if (flotaLayerProvider !== null) flotaLayerProvider.listener.listen('move', updatePopoverOnMove)
|
|
84
|
+
}
|
|
85
|
+
const setVisible = (v: boolean) => {
|
|
86
|
+
if (state.value.visible === v) return
|
|
87
|
+
emit('update:modelValue', v)
|
|
88
|
+
state.value.visible = v
|
|
89
|
+
const options = getOptions(props, v)
|
|
90
|
+
if (v) {
|
|
91
|
+
bindTrigger()
|
|
92
|
+
popper.setOptions(options)
|
|
93
|
+
refPopover.value?.removeAttribute(hideAttrbute)
|
|
94
|
+
emit('show')
|
|
95
|
+
} else {
|
|
96
|
+
unbindTrigger()
|
|
97
|
+
refPopover.value?.setAttribute(hideAttrbute, '')
|
|
98
|
+
emit('close')
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const popoverProvider = usePopoverProvider()
|
|
103
|
+
const flotaLayerProvider = useFlotaLayerProvider()
|
|
104
|
+
const layerStyle = computed(() => {
|
|
105
|
+
const unit = 999
|
|
106
|
+
return flotaLayerProvider === null ? unit : (flotaLayerProvider.layer.value ?? 0) + 1
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const state = ref({
|
|
110
|
+
visible: false,
|
|
111
|
+
needClose: false,
|
|
112
|
+
delayCount: 0,
|
|
113
|
+
needOpen: false,
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
const click = () => {
|
|
117
|
+
if (props.disabled === true) return
|
|
118
|
+
if (props.trigger !== 'click') return
|
|
119
|
+
setVisible(!state.value.visible)
|
|
120
|
+
}
|
|
121
|
+
const show = () => {
|
|
122
|
+
if (state.value.needClose === true) return
|
|
123
|
+
setVisible(true)
|
|
124
|
+
}
|
|
125
|
+
const delayShow = () => {
|
|
126
|
+
state.value.delayCount--
|
|
127
|
+
if (state.value.delayCount === 0 && state.value.needOpen === true) show()
|
|
128
|
+
}
|
|
129
|
+
const delayDispatch = () => {
|
|
130
|
+
if (props.disabled === true || props.trigger !== 'hover' || state.value.needOpen === false) return
|
|
131
|
+
state.value.delayCount++
|
|
132
|
+
setTimeout(delayShow, 200)
|
|
133
|
+
}
|
|
134
|
+
const mouseenter = () => {
|
|
135
|
+
if (props.disabled === true || props.trigger !== 'hover') return
|
|
136
|
+
state.value.needOpen = true
|
|
137
|
+
delayDispatch()
|
|
138
|
+
}
|
|
139
|
+
const close = () => {
|
|
140
|
+
if (state.value.needClose === false) return
|
|
141
|
+
state.value.needClose = false
|
|
142
|
+
setVisible(false)
|
|
143
|
+
}
|
|
144
|
+
const mouseleave = () => {
|
|
145
|
+
if (props.disabled === true || props.trigger !== 'hover') return
|
|
146
|
+
state.value.needOpen = false
|
|
147
|
+
if (state.value.needClose === true) return
|
|
148
|
+
state.value.needClose = true
|
|
149
|
+
setTimeout(close, 300)
|
|
150
|
+
}
|
|
151
|
+
const rightClick = () => {
|
|
152
|
+
state.value.needOpen = false
|
|
153
|
+
mouseleave()
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
watch(() => props.modelValue, setVisible)
|
|
157
|
+
watch(() => [props.placement, props.arrow], () => popper.setOptions(getOptions(props)))
|
|
158
|
+
|
|
159
|
+
const expose: PopoverExpose = {
|
|
160
|
+
update: () => popper.update(),
|
|
161
|
+
position: () => popper.state.placement.split('-'),
|
|
162
|
+
}
|
|
163
|
+
defineExpose(expose)
|
|
164
|
+
</script>
|
|
165
|
+
|
|
166
|
+
<style lang="less" scoped>
|
|
167
|
+
@import '../theme/global.less';
|
|
168
|
+
|
|
169
|
+
@popover-pad: 20px;
|
|
170
|
+
@popover-pad2: @popover-pad * 2;
|
|
171
|
+
@popover-max-width: calc(100% - @popover-pad2);
|
|
172
|
+
@popover-max-height: calc(100% - @popover-pad2);
|
|
173
|
+
|
|
174
|
+
.vyr-popover-location {
|
|
175
|
+
.vyr-font-family;
|
|
176
|
+
display: none;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.vyr-popover {
|
|
180
|
+
.vyr-font-family;
|
|
181
|
+
max-width: @popover-max-width;
|
|
182
|
+
max-height: @popover-max-width;
|
|
183
|
+
color: var(--vyr-font-color);
|
|
184
|
+
font-size: var(--vyr-font-size);
|
|
185
|
+
box-sizing: border-box;
|
|
186
|
+
transition: opacity var(--vyr-animation-time);
|
|
187
|
+
|
|
188
|
+
.popover-wrapper {
|
|
189
|
+
background-color: var(--vyr-popover-background-color);
|
|
190
|
+
position: relative;
|
|
191
|
+
left: 0;
|
|
192
|
+
top: 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.popover-wrapper.flex {
|
|
196
|
+
display: flex;
|
|
197
|
+
flex-wrap: nowrap;
|
|
198
|
+
flex-direction: row;
|
|
199
|
+
justify-content: flex-start;
|
|
200
|
+
align-items: flex-start;
|
|
201
|
+
align-content: flex-start;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.popover-arrow,
|
|
205
|
+
.popover-arrow::before {
|
|
206
|
+
position: absolute;
|
|
207
|
+
width: 6px;
|
|
208
|
+
height: 6px;
|
|
209
|
+
background: inherit;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.popover-arrow {
|
|
213
|
+
visibility: hidden;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.popover-arrow::before {
|
|
217
|
+
border: 1px solid var(--vyr-border-color);
|
|
218
|
+
content: '';
|
|
219
|
+
visibility: visible;
|
|
220
|
+
transform: rotate(45deg);
|
|
221
|
+
background-color: var(--vyr-topic-color);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.vyr-popover.dialog {
|
|
226
|
+
z-index: var(--vyr-popover-dialog-z-index);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.vyr-popover.dialog.active {
|
|
230
|
+
z-index: var(--vyr-popover-dialog-active-z-index);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.vyr-popover.card {
|
|
234
|
+
background-color: var(--vyr-popover-background-color);
|
|
235
|
+
border: 1px solid var(--vyr-border-color);
|
|
236
|
+
box-sizing: border-box;
|
|
237
|
+
|
|
238
|
+
.popover-wrapper {
|
|
239
|
+
width: 100%;
|
|
240
|
+
height: 100%;
|
|
241
|
+
padding: 10px;
|
|
242
|
+
box-sizing: border-box;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.vyr-popover[data-popper-placement^='top']>.popover-arrow {
|
|
247
|
+
bottom: -3px;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.vyr-popover[data-popper-placement^='bottom']>.popover-arrow {
|
|
251
|
+
top: -3px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.vyr-popover[data-popper-placement^='left']>.popover-arrow {
|
|
255
|
+
right: -3px;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.vyr-popover[data-popper-placement^='right']>.popover-arrow {
|
|
259
|
+
left: -3px;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.vyr-popover[data-vyr-popper-hidden],
|
|
263
|
+
.vyr-popover[data-popper-escaped] {
|
|
264
|
+
opacity: 0;
|
|
265
|
+
pointer-events: none;
|
|
266
|
+
|
|
267
|
+
.popover-arrow {
|
|
268
|
+
opacity: 0;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<slot></slot>
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script lang="ts" setup>
|
|
6
|
+
import { computed } from 'vue';
|
|
7
|
+
import { providerDefaultProps } from './composables/useDefaultProps';
|
|
8
|
+
import { updateProvider } from './composables/useProvider';
|
|
9
|
+
|
|
10
|
+
const props = defineProps(providerDefaultProps)
|
|
11
|
+
updateProvider(computed(() => props) as any)
|
|
12
|
+
</script>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<teleport to="body">
|
|
3
|
+
<transition v-if="state.enabled" name="vyr-transition" @before-enter="state.transform = true"
|
|
4
|
+
@after-enter="state.transform = false">
|
|
5
|
+
<div class="vyr-right-menu" :class="{ 'transform': state.transform }" :style="wrapperStyle"
|
|
6
|
+
v-show="setting.visible" @contextmenu.prevent.stop @click.prevent.stop="cancel">
|
|
7
|
+
<vyr-cascader ref="refCascader" placement="bottom-start" :data="setting.group" :max-count="state.maxCount"
|
|
8
|
+
:min-count="state.maxCount" :arrow="false" :visible="visible" :popover-width="`${state.width}px`"
|
|
9
|
+
@change="change" @click.stop @close="setting.visible = false">
|
|
10
|
+
<template #trigger>
|
|
11
|
+
<span :style="style" @click.stop></span>
|
|
12
|
+
</template>
|
|
13
|
+
</vyr-cascader>
|
|
14
|
+
</div>
|
|
15
|
+
</transition>
|
|
16
|
+
</teleport>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
<script lang="ts" setup>
|
|
21
|
+
import { watch, ref, computed, onMounted, onBeforeUnmount, useTemplateRef } from 'vue'
|
|
22
|
+
import { computedFloatLayer, generateFloatLayer, isActiveLayer, RightMenuSetting } from "./utils"
|
|
23
|
+
import { updatePopoverProvider, popoverProviderDefault, FlotaLayerProvider, updateFlotaLayerProvider } from './composables/useProvider';
|
|
24
|
+
import { Listener } from '../tool';
|
|
25
|
+
import { Theme } from '../theme';
|
|
26
|
+
import { Option, RightMenuVue } from './types'
|
|
27
|
+
import VyrCascader from './Cascader.vue';
|
|
28
|
+
|
|
29
|
+
updatePopoverProvider(ref({ ...popoverProviderDefault.value, appendToTooltip: false, autoClose: true }))
|
|
30
|
+
|
|
31
|
+
const refCascader = useTemplateRef('refCascader')
|
|
32
|
+
|
|
33
|
+
const setting = ref(new RightMenuSetting(0, 0, []))
|
|
34
|
+
const style = computed(() => `position:absolute;left:${setting.value.position.x}px;top:${setting.value.position.y}px;`)
|
|
35
|
+
|
|
36
|
+
const state = ref({
|
|
37
|
+
id: generateFloatLayer(),
|
|
38
|
+
width: 240,
|
|
39
|
+
maxCount: 5,
|
|
40
|
+
enabled: true,
|
|
41
|
+
transform: false,
|
|
42
|
+
})
|
|
43
|
+
const getGroupMaxCount = (Options: Option[]) => {
|
|
44
|
+
let count = 0
|
|
45
|
+
for (const Option of Options) {
|
|
46
|
+
if (visible(Option) === true) count++
|
|
47
|
+
}
|
|
48
|
+
return count
|
|
49
|
+
}
|
|
50
|
+
const watchVisible = () => {
|
|
51
|
+
if (setting.value.visible === false || !refCascader.value) return
|
|
52
|
+
const groupMaxCount = getGroupMaxCount(setting.value.group)
|
|
53
|
+
const height = Theme.config.inputHeight.value + Theme.config.optionsScrollMargin.value * 2
|
|
54
|
+
const maxHeight = window.innerHeight * 0.75
|
|
55
|
+
const count = Math.min(Math.floor(maxHeight / height), 10)
|
|
56
|
+
state.value.maxCount = groupMaxCount > count ? count : groupMaxCount
|
|
57
|
+
refCascader.value.show()
|
|
58
|
+
}
|
|
59
|
+
watch(() => setting.value.visible, watchVisible, {})
|
|
60
|
+
|
|
61
|
+
const active = computed(() => isActiveLayer(state.value.id))
|
|
62
|
+
const layer = computed(() => computedFloatLayer(state.value.id, active.value))
|
|
63
|
+
const flotaLayerProvider: FlotaLayerProvider = { listener: new Listener(), layer }
|
|
64
|
+
updateFlotaLayerProvider(flotaLayerProvider)
|
|
65
|
+
const wrapperStyle = computed(() => {
|
|
66
|
+
return layer.value === -1 ? '' : `z-index${layer.value};`
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const visible = (item: any) => {
|
|
70
|
+
return item.show
|
|
71
|
+
}
|
|
72
|
+
const change = (item: Option) => {
|
|
73
|
+
if (state.value.transform === true) return
|
|
74
|
+
refCascader.value?.close()
|
|
75
|
+
setting.value.change(item)
|
|
76
|
+
}
|
|
77
|
+
const cancel = () => {
|
|
78
|
+
if (state.value.transform === true) return
|
|
79
|
+
refCascader.value?.close()
|
|
80
|
+
setting.value.cancel()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
onMounted(() => window.addEventListener('resize', close))
|
|
84
|
+
onBeforeUnmount(() => window.removeEventListener('resize', close))
|
|
85
|
+
|
|
86
|
+
const autoClose = () => {
|
|
87
|
+
close()
|
|
88
|
+
state.value.enabled = false
|
|
89
|
+
requestAnimationFrame(() => state.value.enabled = true)
|
|
90
|
+
|
|
91
|
+
}
|
|
92
|
+
onMounted(() => window.addEventListener('resize', autoClose))
|
|
93
|
+
onBeforeUnmount(() => window.addEventListener('resize', autoClose))
|
|
94
|
+
|
|
95
|
+
const show = (set: RightMenuSetting) => {
|
|
96
|
+
setting.value = set
|
|
97
|
+
}
|
|
98
|
+
const close = () => {
|
|
99
|
+
setting.value.visible = false
|
|
100
|
+
}
|
|
101
|
+
defineExpose<RightMenuVue>({ show, close })
|
|
102
|
+
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
<style lang="less" scoped>
|
|
106
|
+
@import '../theme/global.less';
|
|
107
|
+
|
|
108
|
+
.vyr-right-menu {
|
|
109
|
+
.vyr-font-family;
|
|
110
|
+
width: 100%;
|
|
111
|
+
height: 100%;
|
|
112
|
+
color: var(--vyr-font-color);
|
|
113
|
+
font-size: var(--vyr-font-size);
|
|
114
|
+
position: fixed;
|
|
115
|
+
left: 0;
|
|
116
|
+
top: 0;
|
|
117
|
+
z-index: 99999;
|
|
118
|
+
|
|
119
|
+
:deep(.vyr-options) {
|
|
120
|
+
box-shadow: 0 0 2px var(--vyr-input-border-color);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.vyr-right-menu.transform {
|
|
125
|
+
pointer-events: none;
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="vyr-row" :style="style">
|
|
3
|
+
<slot></slot>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { computed, ref } from 'vue'
|
|
9
|
+
import { updateRowProvider, useProvider } from './composables/useProvider'
|
|
10
|
+
import { joinMarginStyle, compileMarginStyle } from './composables/useMarginStyle'
|
|
11
|
+
import { rowCommonDefaultProps } from './composables/useDefaultProps'
|
|
12
|
+
|
|
13
|
+
const props = defineProps(rowCommonDefaultProps)
|
|
14
|
+
|
|
15
|
+
const provider = useProvider()
|
|
16
|
+
const curGutter = computed(() => props.gutter === null ? provider.value.row.gutter : props.gutter)
|
|
17
|
+
const rowProvider = ref({ gutter: curGutter, count: 0 })
|
|
18
|
+
updateRowProvider(rowProvider)
|
|
19
|
+
|
|
20
|
+
const style = computed(() => {
|
|
21
|
+
const curMargin = props.margin === null ? provider.value.row.margin : props.margin
|
|
22
|
+
const margin = compileMarginStyle(curMargin)
|
|
23
|
+
const gutter = rowProvider.value.count === 0 ? 0 : -curGutter.value
|
|
24
|
+
margin[1] = gutter
|
|
25
|
+
margin[3] = gutter
|
|
26
|
+
return joinMarginStyle(margin, 'margin')
|
|
27
|
+
})
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<style lang="less" scoped>
|
|
31
|
+
@import '../theme/global.less';
|
|
32
|
+
|
|
33
|
+
.vyr-row {
|
|
34
|
+
.vyr-font-family;
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-wrap: nowrap;
|
|
37
|
+
flex-direction: row;
|
|
38
|
+
box-sizing: border-box;
|
|
39
|
+
|
|
40
|
+
&:before,
|
|
41
|
+
&:after {
|
|
42
|
+
display: table;
|
|
43
|
+
content: "";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&:after {
|
|
47
|
+
clear: both;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
</style>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="vyr-scroll" :style="`${marginStyle}`" @wheel.passive="layout" @mousemove="move" @mouseleave="leave">
|
|
3
|
+
<div class="scroll-wrapper scrollbar" ref="refWrapper">
|
|
4
|
+
<div class="scroll-body" :style="`${paddingStyle}`" ref="refBody">
|
|
5
|
+
<slot></slot>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="scroll-bar"
|
|
9
|
+
:style="`display:${state.hide ? 'none' : 'display'};opacity:${opacity};top:${state.top}%;height:${state.height}%;`">
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script lang="ts" setup>
|
|
15
|
+
import { ref, onMounted, onBeforeUnmount, Ref, useTemplateRef } from 'vue'
|
|
16
|
+
import { scrollCommonDefaultProps } from './composables/useDefaultProps'
|
|
17
|
+
import { useMarginStyle } from './composables/useMarginStyle'
|
|
18
|
+
import { useScroll } from './composables/useScroll';
|
|
19
|
+
import { observer } from './utils/Scroll';
|
|
20
|
+
import { language } from '../locale'
|
|
21
|
+
|
|
22
|
+
const props = defineProps(scrollCommonDefaultProps)
|
|
23
|
+
const { marginStyle, paddingStyle } = useMarginStyle(props)
|
|
24
|
+
|
|
25
|
+
const emit = defineEmits(['resize'])
|
|
26
|
+
const refWrapper = useTemplateRef('refWrapper')
|
|
27
|
+
const refBody = useTemplateRef('refBody')
|
|
28
|
+
const state = ref({
|
|
29
|
+
hide: true,
|
|
30
|
+
top: 0,
|
|
31
|
+
height: 0,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const rect = { wrapper: 0, body: 0, }
|
|
35
|
+
const computeTop = () => {
|
|
36
|
+
if (refWrapper.value) {
|
|
37
|
+
state.value.top = (refWrapper.value.scrollTop / rect.body) * 100
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const computeLayout = () => {
|
|
41
|
+
rect.wrapper = Math.floor(refWrapper.value?.getBoundingClientRect().height ?? 0)
|
|
42
|
+
rect.body = refBody.value?.scrollHeight ?? 0
|
|
43
|
+
state.value.height = (rect.wrapper / rect.body) * 100
|
|
44
|
+
state.value.hide = rect.body - rect.wrapper > 1 ? false : true
|
|
45
|
+
computeTop()
|
|
46
|
+
emit('resize')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const listen = () => {
|
|
50
|
+
if (!refBody.value || !refWrapper.value) throw language.get('scroll.listen.error')
|
|
51
|
+
observer.listen(refWrapper.value, computeLayout)
|
|
52
|
+
observer.listen(refBody.value, computeLayout)
|
|
53
|
+
}
|
|
54
|
+
const unlisten = () => {
|
|
55
|
+
observer.unlisten(refWrapper.value as Element)
|
|
56
|
+
observer.unlisten(refBody.value as Element)
|
|
57
|
+
}
|
|
58
|
+
onMounted(listen)
|
|
59
|
+
onBeforeUnmount(unlisten)
|
|
60
|
+
|
|
61
|
+
const { opacity, layout, move, leave } = useScroll(computeTop, refWrapper as Ref<HTMLElement>)
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<style lang="less" scoped>
|
|
65
|
+
@import '../theme/global.less';
|
|
66
|
+
|
|
67
|
+
.vyr-scroll {
|
|
68
|
+
.vyr-font-family;
|
|
69
|
+
width: 100%;
|
|
70
|
+
height: 100%;
|
|
71
|
+
color: var(--vyr-font-color);
|
|
72
|
+
font-size: var(--vyr-font-size);
|
|
73
|
+
position: relative;
|
|
74
|
+
left: 0;
|
|
75
|
+
top: 0;
|
|
76
|
+
box-sizing: border-box;
|
|
77
|
+
|
|
78
|
+
.scroll-wrapper {
|
|
79
|
+
width: 100%;
|
|
80
|
+
height: 100%;
|
|
81
|
+
overflow-x: hidden;
|
|
82
|
+
overflow-y: scroll;
|
|
83
|
+
|
|
84
|
+
.scroll-body {
|
|
85
|
+
width: 100%;
|
|
86
|
+
box-sizing: border-box;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.scroll-bar {
|
|
91
|
+
width: 4px;
|
|
92
|
+
border-radius: var(--vyr-radius-size);
|
|
93
|
+
background-color: var(--vyr-scroll-bar-color);
|
|
94
|
+
position: absolute;
|
|
95
|
+
right: 2px;
|
|
96
|
+
transition: opacity var(--vyr-animation-time);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
</style>
|