@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,113 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
import { AdditionalData, DraggableEndType, Draggable } from '../../tool'
|
|
3
|
+
import { DraggableVue } from '../types'
|
|
4
|
+
import SnowDraggable from '../Draggable.vue'
|
|
5
|
+
|
|
6
|
+
const SnowDraggableApp = createApp(SnowDraggable)
|
|
7
|
+
const viewer = SnowDraggableApp.mount(document.createElement('div'))
|
|
8
|
+
document.body.appendChild(viewer.$el)
|
|
9
|
+
|
|
10
|
+
type DraggableTick = (e: MouseEvent) => void
|
|
11
|
+
|
|
12
|
+
class DraggableController {
|
|
13
|
+
static label = ''
|
|
14
|
+
static id = ''
|
|
15
|
+
static needMove = false
|
|
16
|
+
static enabled = false
|
|
17
|
+
static executed = false
|
|
18
|
+
static dragData: AdditionalData | null = null
|
|
19
|
+
static viewer = viewer as unknown as DraggableVue
|
|
20
|
+
static mouse = { x: 0, y: 0 }
|
|
21
|
+
static mouseStartDistance = 2
|
|
22
|
+
static tick?: DraggableTick
|
|
23
|
+
|
|
24
|
+
/**启动托拽功能 */
|
|
25
|
+
static start = <T extends AdditionalData = AdditionalData>(dragData: T, group: Draggable, label: string, e: MouseEvent) => {
|
|
26
|
+
if (group.starter(dragData) === false) return
|
|
27
|
+
window.addEventListener('mousemove', this.move)
|
|
28
|
+
window.addEventListener('mouseup', this.cancel)
|
|
29
|
+
|
|
30
|
+
this.needMove = true
|
|
31
|
+
this.mouse.x = e.clientX
|
|
32
|
+
this.mouse.y = e.clientY
|
|
33
|
+
this.dragData = dragData
|
|
34
|
+
this.label = label
|
|
35
|
+
this.id = group.id
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**进入目标对象时触发
|
|
39
|
+
*
|
|
40
|
+
* @param targetData 进入的目标对象
|
|
41
|
+
* @param group 托拽功能使用的拖拽组
|
|
42
|
+
* @returns 返回值决定了托拽对象能否被放置在目标对象
|
|
43
|
+
*/
|
|
44
|
+
static enter = <T extends AdditionalData = AdditionalData>(targetData: T, group: Draggable, tick?: DraggableTick, e?: MouseEvent) => {
|
|
45
|
+
if (this.enabled === false || this.dragData === null) return false
|
|
46
|
+
if (tick !== undefined) {
|
|
47
|
+
this.tick = tick
|
|
48
|
+
if (e !== undefined) tick(e)
|
|
49
|
+
}
|
|
50
|
+
return group.validator({ id: this.id, data: this.dragData }, { id: group.id, data: targetData })
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**离开目标对象时触发 */
|
|
54
|
+
static leave = <T extends AdditionalData = AdditionalData>(targetData: T, group: Draggable) => {
|
|
55
|
+
if (this.enabled === false || this.dragData === null) return
|
|
56
|
+
this.tick = undefined
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**托拽功能启动后鼠标移动时触发 */
|
|
60
|
+
static move = (e: MouseEvent) => {
|
|
61
|
+
if (this.executed === true) return
|
|
62
|
+
this.executed = true
|
|
63
|
+
requestAnimationFrame(() => this.executed = false)
|
|
64
|
+
|
|
65
|
+
if (this.needMove === true) {
|
|
66
|
+
const dx = Math.abs(e.clientX - this.mouse.x)
|
|
67
|
+
const dy = Math.abs(e.clientY - this.mouse.y)
|
|
68
|
+
const min = Math.min(dx, dy, this.mouseStartDistance)
|
|
69
|
+
if (min < this.mouseStartDistance) return
|
|
70
|
+
this.needMove = false
|
|
71
|
+
this.enabled = true
|
|
72
|
+
this.viewer.show(this.label)
|
|
73
|
+
}
|
|
74
|
+
if (this.tick !== undefined) this.tick(e)
|
|
75
|
+
this.viewer.update(e.clientX, e.clientY)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**托拽功能结束后触发,若成功完成托拽则会触发拖拽组的`finished`方法 */
|
|
79
|
+
static end = <T extends AdditionalData = AdditionalData>(targetData: T, group: Draggable, type: DraggableEndType = 'insert') => {
|
|
80
|
+
if (this.enabled === true && this.dragData !== null) {
|
|
81
|
+
const drag = { id: this.id, data: this.dragData }
|
|
82
|
+
const target = { id: group.id, data: targetData }
|
|
83
|
+
if (group.validator(drag, target) === true) group.finished(drag, target, type)
|
|
84
|
+
}
|
|
85
|
+
this.cancel()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**对本次的托拽类型进行格式化验证 */
|
|
89
|
+
static limit = <T extends AdditionalData = AdditionalData>(targetData: T, group: Draggable, type: DraggableEndType = 'insert') => {
|
|
90
|
+
if (this.enabled === true && this.dragData !== null) {
|
|
91
|
+
const drag = { id: this.id, data: this.dragData }
|
|
92
|
+
const target = { id: group.id, data: targetData }
|
|
93
|
+
return group.limit(drag, target, type)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return type
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static cancel = () => {
|
|
100
|
+
window.removeEventListener('mouseup', this.cancel)
|
|
101
|
+
window.removeEventListener('mousemove', this.move)
|
|
102
|
+
|
|
103
|
+
this.id = ''
|
|
104
|
+
this.needMove = false
|
|
105
|
+
this.enabled = false
|
|
106
|
+
this.executed = false
|
|
107
|
+
this.dragData = null
|
|
108
|
+
this.tick = undefined
|
|
109
|
+
this.viewer.hide()
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export { DraggableController }
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
interface ResizeEntryObject {
|
|
2
|
+
rect: DOMRect,
|
|
3
|
+
target: Element
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
class ResizeListener {
|
|
7
|
+
private registry = new WeakMap<Element, (obj: ResizeEntryObject) => void>()
|
|
8
|
+
private debounce = false
|
|
9
|
+
readonly observer
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
this.observer = new ResizeObserver(this.handler)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private handler = (entrys: ResizeObserverEntry[]) => {
|
|
16
|
+
//防止回调形成无限循环
|
|
17
|
+
if (this.debounce === true) return
|
|
18
|
+
this.debounce = true
|
|
19
|
+
setTimeout(() => this.callback(entrys), 0)
|
|
20
|
+
}
|
|
21
|
+
private callback = (entrys: ResizeObserverEntry[]) => {
|
|
22
|
+
this.debounce = false
|
|
23
|
+
for (const entry of entrys) this.trigger(entry.target)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
trigger(el: Element) {
|
|
27
|
+
const listener = this.registry.get(el)
|
|
28
|
+
if (listener === undefined) return
|
|
29
|
+
const reo: ResizeEntryObject = { rect: el.getBoundingClientRect(), target: el }
|
|
30
|
+
listener(reo)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
listen(el: Element, listener: (obj: ResizeEntryObject) => void) {
|
|
34
|
+
this.registry.set(el, listener)
|
|
35
|
+
this.observer.observe(el)
|
|
36
|
+
|
|
37
|
+
return () => this.trigger(el)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
unlisten(el: Element) {
|
|
41
|
+
this.registry.delete(el)
|
|
42
|
+
this.observer.unobserve(el)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
dispose() {
|
|
46
|
+
this.observer.disconnect()
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export { ResizeEntryObject, ResizeListener }
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { computed, ref } from "vue"
|
|
2
|
+
import { Placement } from "@popperjs/core/lib"
|
|
3
|
+
import { DataGetter, DefineToDefaultProps, GetPropValue, ToPartialObject, TreeOption, TreeOptions } from '../types'
|
|
4
|
+
import { InputCommonProvider, useProvider } from "./useProvider"
|
|
5
|
+
import { CommonProvider, Provider } from "./useProvider"
|
|
6
|
+
import { MarginStyle } from "./useMarginStyle"
|
|
7
|
+
import { Draggable } from "../../tool"
|
|
8
|
+
import { language } from "../../locale"
|
|
9
|
+
|
|
10
|
+
const getterCommonDefaultProps = {
|
|
11
|
+
getter: { default: () => { return {} as Partial<DataGetter> } }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface CheckedCommonProps {
|
|
15
|
+
modelValue: GetPropValue<string | number | boolean>,
|
|
16
|
+
value: string | number | boolean
|
|
17
|
+
}
|
|
18
|
+
const checkedCommonDefaultProps: DefineToDefaultProps<CheckedCommonProps> = {
|
|
19
|
+
modelValue: { default: false },
|
|
20
|
+
value: { default: true },
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const commonDefaultProps: DefineToDefaultProps<Omit<Provider, 'row' | 'label' | 'input'>> = {
|
|
24
|
+
clearable: { default: null },
|
|
25
|
+
readonly: { default: null },
|
|
26
|
+
readonlyClearable: { default: null },
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const rowCommonDefaultProps: DefineToDefaultProps<Provider['row']> = {
|
|
30
|
+
gutter: { default: null },
|
|
31
|
+
margin: { default: null },
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const labelCommonDefaultProps: DefineToDefaultProps<Provider['label']> = {
|
|
35
|
+
width: { default: null },
|
|
36
|
+
align: { default: null },
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const inputCommonDefaultProps: DefineToDefaultProps<Provider['input']> = {
|
|
40
|
+
width: { default: null },
|
|
41
|
+
draggable: { default: false },
|
|
42
|
+
/** 拖拽属性的路径,支持以下写法
|
|
43
|
+
* - property 普通对象的属性
|
|
44
|
+
* - propertyA.property 嵌套对象的属性
|
|
45
|
+
* - property[0].property 数组对象的属性
|
|
46
|
+
*/
|
|
47
|
+
dragkey: { default: '' },
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const inputDefaultProps = {
|
|
51
|
+
modelValue: { default: '' } as { default: any },
|
|
52
|
+
placeholder: { default: language.get('input.placeholder') },
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const selectCommonDefaultProps = {
|
|
56
|
+
modelValue: { default: '' } as { default: any },
|
|
57
|
+
placeholder: { default: language.get('select.placeholder') },
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const treeCommonDefaultProps = {
|
|
61
|
+
/**树结构的数据 */
|
|
62
|
+
data: { default() { return [] as TreeOptions } },
|
|
63
|
+
/**树的修改模式
|
|
64
|
+
*
|
|
65
|
+
* close: 关闭模式
|
|
66
|
+
*
|
|
67
|
+
* edit: 编辑模式
|
|
68
|
+
*
|
|
69
|
+
* add: 新增模式
|
|
70
|
+
*
|
|
71
|
+
*/
|
|
72
|
+
modify: { default: 'close' },
|
|
73
|
+
/**开启修改模式后需要操作的项 */
|
|
74
|
+
modifyValue: { default: '' },
|
|
75
|
+
/**拖拽功能所需的拖拽组 */
|
|
76
|
+
draggable: { default: false as false | Draggable },
|
|
77
|
+
/**节点的可见性 */
|
|
78
|
+
visible: { default() { return (item: TreeOption): boolean => { return true } } },
|
|
79
|
+
/**节点是否需要警告 */
|
|
80
|
+
warning: { default() { return (item: TreeOption): boolean => { return false } } },
|
|
81
|
+
multiple: { default: false }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const scrollCommonDefaultProps = {
|
|
85
|
+
margin: { default: 0 as MarginStyle },
|
|
86
|
+
padding: { default: 0 as MarginStyle },
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const maskCommonDefaultProps = {
|
|
90
|
+
mask: { default: true },
|
|
91
|
+
visible: { default: false },
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const dialogCommonDefaultProps = {
|
|
95
|
+
/**模态框 */
|
|
96
|
+
mask: { default: false },
|
|
97
|
+
header: { default: 60 },
|
|
98
|
+
footer: { default: 55 },
|
|
99
|
+
width: { default: '860px' },
|
|
100
|
+
height: { default: 'auto' },
|
|
101
|
+
maxHeight: { default: '60%' },
|
|
102
|
+
margin: { default: 10 as MarginStyle },
|
|
103
|
+
padding: { default: 10 as MarginStyle },
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const popoverCommonDefaultProps = {
|
|
107
|
+
placement: { default: 'bottom' as Placement },
|
|
108
|
+
popoverClass: { default: '' },
|
|
109
|
+
arrow: { default: true },
|
|
110
|
+
offset: { default: 6 },
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface ProviderProps extends DefineToDefaultProps<ToPartialObject<Provider>> { }
|
|
114
|
+
const providerDefaultProps: ProviderProps = {
|
|
115
|
+
...commonDefaultProps,
|
|
116
|
+
input: { default: null },
|
|
117
|
+
label: { default: null },
|
|
118
|
+
row: { default: null },
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const showClear = (clearable: boolean, readonly: boolean, readonlyClearable: boolean, value?: any) => {
|
|
122
|
+
if (value === undefined || value === null || value === '') return false
|
|
123
|
+
|
|
124
|
+
if (readonly === false) return clearable
|
|
125
|
+
|
|
126
|
+
return readonlyClearable ? clearable : false
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const useCommonProps = (props: CommonProvider) => {
|
|
130
|
+
const provider = useProvider()
|
|
131
|
+
const curReadonly = computed(() => props.readonly === null ? provider.value.readonly : props.readonly)
|
|
132
|
+
const curClearable = computed(() => props.clearable === null ? provider.value.clearable : props.clearable)
|
|
133
|
+
const curReadonlyClearable = computed(() => props.readonlyClearable === null ? provider.value.readonlyClearable : props.readonlyClearable)
|
|
134
|
+
|
|
135
|
+
return { curReadonly, curClearable, curReadonlyClearable, showClear }
|
|
136
|
+
}
|
|
137
|
+
const useCommonPropsOnInput = (props: CommonProvider) => {
|
|
138
|
+
const provider = useProvider()
|
|
139
|
+
const state = ref({ mouseInInput: false })
|
|
140
|
+
|
|
141
|
+
const enterInput = () => state.value.mouseInInput = true
|
|
142
|
+
|
|
143
|
+
const leaveInput = () => state.value.mouseInInput = false
|
|
144
|
+
|
|
145
|
+
const curReadonly = computed(() => props.readonly === null ? provider.value.readonly : props.readonly)
|
|
146
|
+
const curClearable = computed(() => {
|
|
147
|
+
if (state.value.mouseInInput === false) return false
|
|
148
|
+
|
|
149
|
+
return props.clearable === null ? provider.value.clearable : props.clearable
|
|
150
|
+
})
|
|
151
|
+
const curReadonlyClearable = computed(() => props.readonlyClearable === null ? provider.value.readonlyClearable : props.readonlyClearable)
|
|
152
|
+
|
|
153
|
+
return { curReadonly, curClearable, curReadonlyClearable, enterInput, leaveInput, showClear }
|
|
154
|
+
}
|
|
155
|
+
const useInputCommonProps = (props: InputCommonProvider) => {
|
|
156
|
+
const provider = useProvider()
|
|
157
|
+
const curInputWidth = computed(() => props.width === null ? provider.value.input.width : props.width)
|
|
158
|
+
return { curInputWidth }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export {
|
|
162
|
+
commonDefaultProps,
|
|
163
|
+
getterCommonDefaultProps,
|
|
164
|
+
inputDefaultProps,
|
|
165
|
+
inputCommonDefaultProps,
|
|
166
|
+
labelCommonDefaultProps,
|
|
167
|
+
rowCommonDefaultProps,
|
|
168
|
+
selectCommonDefaultProps,
|
|
169
|
+
checkedCommonDefaultProps,
|
|
170
|
+
treeCommonDefaultProps,
|
|
171
|
+
scrollCommonDefaultProps,
|
|
172
|
+
maskCommonDefaultProps,
|
|
173
|
+
dialogCommonDefaultProps,
|
|
174
|
+
popoverCommonDefaultProps,
|
|
175
|
+
providerDefaultProps,
|
|
176
|
+
useCommonProps,
|
|
177
|
+
useCommonPropsOnInput,
|
|
178
|
+
useInputCommonProps,
|
|
179
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Ref, ref } from "vue"
|
|
2
|
+
import { TreeOption, DataGetter } from "../types"
|
|
3
|
+
import { TreeProvider } from './useProvider'
|
|
4
|
+
import { DraggableController } from "../common/DraggableController"
|
|
5
|
+
import { useTimer } from "./useTimer"
|
|
6
|
+
import { Draggable, DraggableEndType } from "../../tool"
|
|
7
|
+
|
|
8
|
+
const useDraggable = (props: { draggable: false | Draggable, getter: DataGetter }, treeProvider: Ref<TreeProvider>) => {
|
|
9
|
+
const drag = ref({
|
|
10
|
+
id: 0,
|
|
11
|
+
value: '',
|
|
12
|
+
type: 'insert' as DraggableEndType,
|
|
13
|
+
})
|
|
14
|
+
const resetDraggable = () => {
|
|
15
|
+
drag.value.value = ''
|
|
16
|
+
drag.value.type = 'insert'
|
|
17
|
+
}
|
|
18
|
+
const mousedown = (item: TreeOption, e: MouseEvent) => {
|
|
19
|
+
if (props.draggable === false || e.button !== 0) return
|
|
20
|
+
DraggableController.start(item, props.draggable, props.getter.label(item), e)
|
|
21
|
+
}
|
|
22
|
+
const mouseup = (item: TreeOption, e: MouseEvent) => {
|
|
23
|
+
if (DraggableController.enabled === false || props.draggable === false) return
|
|
24
|
+
clearTimeout(drag.value.id)
|
|
25
|
+
|
|
26
|
+
DraggableController.end(item, props.draggable, drag.value.type)
|
|
27
|
+
resetDraggable()
|
|
28
|
+
}
|
|
29
|
+
const mouseenter = (item: TreeOption, e: MouseEvent) => {
|
|
30
|
+
if (DraggableController.enabled === false || props.draggable === false) return
|
|
31
|
+
drag.value.id = useTimer(() => treeProvider.value.handleExpand(item), 1000);
|
|
32
|
+
|
|
33
|
+
const draggable = props.draggable
|
|
34
|
+
const tick = (move: MouseEvent) => {
|
|
35
|
+
if (!(e.target instanceof Element) || !DraggableController.dragData) return
|
|
36
|
+
const rect = e.target.getBoundingClientRect()
|
|
37
|
+
const y = move.clientY - rect.top
|
|
38
|
+
const radio = y / rect.height
|
|
39
|
+
|
|
40
|
+
const adjacencies = treeProvider.value.getAdjacencies(DraggableController.dragData, item) ?? 0
|
|
41
|
+
|
|
42
|
+
if (radio < 0.3) {
|
|
43
|
+
drag.value.type = adjacencies === 1 ? 'insert' : 'insertBefore'
|
|
44
|
+
} else if (radio > 0.7) {
|
|
45
|
+
drag.value.type = adjacencies === -1 ? 'insert' : 'insertAfter'
|
|
46
|
+
} else {
|
|
47
|
+
drag.value.type = 'insert'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
drag.value.type = DraggableController.limit(item, draggable, drag.value.type)
|
|
51
|
+
}
|
|
52
|
+
drag.value.value = DraggableController.enter(item, draggable, tick, e) ? props.getter.value(item) : ''
|
|
53
|
+
}
|
|
54
|
+
const mouseleave = (item: TreeOption, e: MouseEvent) => {
|
|
55
|
+
if (DraggableController.enabled === false || props.draggable === false) return
|
|
56
|
+
clearTimeout(drag.value.id)
|
|
57
|
+
|
|
58
|
+
DraggableController.leave(item, props.draggable)
|
|
59
|
+
resetDraggable()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return { drag, mousedown, mouseup, mouseenter, mouseleave }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { useDraggable }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DataGetter } from '../types'
|
|
2
|
+
|
|
3
|
+
const defaultGetter: DataGetter = {
|
|
4
|
+
label(item) { return item.label },
|
|
5
|
+
value(item) { return item.value },
|
|
6
|
+
disabled(item) { return item.disabled },
|
|
7
|
+
children(item) { return item.children ?? [] },
|
|
8
|
+
arrow(item) { return true },
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const useGetter = (props?: { getter: Partial<DataGetter> }) => {
|
|
12
|
+
return props === undefined ? defaultGetter : Object.assign({}, defaultGetter, props.getter)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { defaultGetter, useGetter }
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { computed } from "vue"
|
|
2
|
+
|
|
3
|
+
type MarginStyle = number | string
|
|
4
|
+
|
|
5
|
+
const parseMarginStyleArray = (style: string) => {
|
|
6
|
+
const clips = style.split(',')
|
|
7
|
+
const margin: number[] = []
|
|
8
|
+
for (const num of clips) {
|
|
9
|
+
const value = parseInt(num)
|
|
10
|
+
if (isNaN(value)) continue
|
|
11
|
+
margin.push(value)
|
|
12
|
+
}
|
|
13
|
+
if (margin.length === 0) {
|
|
14
|
+
return [0, 0, 0, 0]
|
|
15
|
+
} else if (margin.length === 1) {
|
|
16
|
+
const size = margin[0]
|
|
17
|
+
return [size, size, size, size]
|
|
18
|
+
} else if (margin.length === 2) {
|
|
19
|
+
const top = margin[0]
|
|
20
|
+
const left = margin[1]
|
|
21
|
+
return [top, left, top, left]
|
|
22
|
+
} else if (margin.length === 3) {
|
|
23
|
+
const left = margin[1]
|
|
24
|
+
return [margin[0], left, margin[2], left]
|
|
25
|
+
} else {
|
|
26
|
+
return [margin[0], margin[1], margin[2], margin[3]]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const joinMarginStyle = (padding: number[], type: 'padding' | 'margin' = 'padding') => {
|
|
31
|
+
return `${type}:${padding[0]}px ${padding[1]}px ${padding[2]}px ${padding[3]}px;`
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const compileMarginStyle = (style: MarginStyle) => {
|
|
35
|
+
return typeof style === 'string' ? parseMarginStyleArray(style) : [style, style, style, style]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const useMarginStyle = (props: { margin: MarginStyle, padding: MarginStyle }) => {
|
|
39
|
+
const marginStyle = computed(() => joinMarginStyle(compileMarginStyle(props.margin)))
|
|
40
|
+
const paddingStyle = computed(() => joinMarginStyle(compileMarginStyle(props.padding)))
|
|
41
|
+
|
|
42
|
+
return { marginStyle, paddingStyle }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { MarginStyle, compileMarginStyle, joinMarginStyle, useMarginStyle }
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { State } from "@popperjs/core";
|
|
2
|
+
import { computed, Ref, ref } from "vue"
|
|
3
|
+
import { ResizeListener, ResizeEntryObject } from '../common/ResizeListener';
|
|
4
|
+
import { useCascaderProvider } from "./useProvider";
|
|
5
|
+
|
|
6
|
+
interface PopoverExpose {
|
|
7
|
+
update: () => Promise<Partial<State>>
|
|
8
|
+
position: () => string[]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const observer = new ResizeListener()
|
|
12
|
+
const usePopover = (props: { popoverWidth: string }, refPopover: Ref<PopoverExpose | null>) => {
|
|
13
|
+
const cascaderProvider = useCascaderProvider()
|
|
14
|
+
const state = ref({ visible: false, width: 'auto' })
|
|
15
|
+
const slotWidth = computed(() => props.popoverWidth === 'auto' ? state.value.width : props.popoverWidth)
|
|
16
|
+
|
|
17
|
+
const resize = (entry: ResizeEntryObject) => {
|
|
18
|
+
if (!refPopover.value) return
|
|
19
|
+
|
|
20
|
+
if (props.popoverWidth === 'auto') {
|
|
21
|
+
state.value.width = entry.rect.width + 'px'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
refPopover.value.update().then(() => {
|
|
25
|
+
const position = refPopover.value?.position() ?? ['bottom', 'start']
|
|
26
|
+
cascaderProvider.value.getPopoverLayout({ position, width: slotWidth.value })
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return { state, slotWidth, cascaderProvider, resize }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { PopoverExpose, usePopover, observer }
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { computed, ComputedRef, DefineProps, inject, provide, ref, Ref } from "vue"
|
|
2
|
+
import { DataGetter, Options, SelectPopoverLayout, ValidateCollection, TreeOption, TreeOptions } from '../types'
|
|
3
|
+
import { MarginStyle } from "./useMarginStyle"
|
|
4
|
+
import { Listener, Draggable } from "../../tool"
|
|
5
|
+
|
|
6
|
+
interface CommonProvider {
|
|
7
|
+
/**开启组件的清空功能 */
|
|
8
|
+
clearable: boolean
|
|
9
|
+
/**将组件设为只读 */
|
|
10
|
+
readonly: boolean
|
|
11
|
+
/**组件为只读时是否清空 */
|
|
12
|
+
readonlyClearable: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface InputCommonProvider {
|
|
16
|
+
/**输入框的宽度 */
|
|
17
|
+
width: string
|
|
18
|
+
draggable: false | Draggable
|
|
19
|
+
/** 拖拽属性的路径,支持以下写法
|
|
20
|
+
* - property 普通对象的属性
|
|
21
|
+
* - propertyA.property 嵌套对象的属性
|
|
22
|
+
* - property[0].property 数组对象的属性
|
|
23
|
+
*/
|
|
24
|
+
dragkey: string,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface LabelCommonProvider {
|
|
28
|
+
/**标签的宽度 */
|
|
29
|
+
width: number
|
|
30
|
+
/**标签的对齐方式 */
|
|
31
|
+
align: 'left' | 'center' | 'right'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface RowCommonProvider {
|
|
35
|
+
/**行组件的外边距 */
|
|
36
|
+
margin: MarginStyle
|
|
37
|
+
/**行组件内每一列的间隔 */
|
|
38
|
+
gutter: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface Provider extends CommonProvider {
|
|
42
|
+
/**input组件的属性 */
|
|
43
|
+
input: InputCommonProvider
|
|
44
|
+
/**label组件的属性 */
|
|
45
|
+
label: LabelCommonProvider
|
|
46
|
+
/**row组件的属性 */
|
|
47
|
+
row: RowCommonProvider
|
|
48
|
+
}
|
|
49
|
+
const provider = Symbol()
|
|
50
|
+
const providerDefault: Ref<Provider> = ref({
|
|
51
|
+
clearable: false,
|
|
52
|
+
readonly: false,
|
|
53
|
+
readonlyClearable: false,
|
|
54
|
+
disabled: false,
|
|
55
|
+
input: { width: '100%', draggable: false, dragkey: '' },
|
|
56
|
+
label: { width: 60, align: 'left' },
|
|
57
|
+
row: { gutter: 10, margin: '0,0,24,0' },
|
|
58
|
+
card: { margin: '0,0,0,0' },
|
|
59
|
+
})
|
|
60
|
+
const useProvider = () => inject(provider, providerDefault)
|
|
61
|
+
const traverseMerge = <T extends { [k: string | symbol]: any } = {}>(target: T, source: { [k: string | symbol]: any }) => {
|
|
62
|
+
const mergeData = { ...target }
|
|
63
|
+
const keys = Object.keys(source) as Array<keyof T>
|
|
64
|
+
|
|
65
|
+
for (const key of keys) {
|
|
66
|
+
let value = source[key]
|
|
67
|
+
|
|
68
|
+
if (value === null || value === undefined) continue
|
|
69
|
+
|
|
70
|
+
mergeData[key] = typeof value === 'object' ? traverseMerge(target[key], value) : value
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return mergeData
|
|
74
|
+
}
|
|
75
|
+
const updateProvider = (props: Ref<DefineProps<Provider, keyof Provider>>) => {
|
|
76
|
+
const providerData = inject(provider, providerDefault)
|
|
77
|
+
|
|
78
|
+
const merginProvider = computed(() => {
|
|
79
|
+
return traverseMerge(providerData.value, props.value)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
provide(provider, merginProvider)
|
|
83
|
+
}
|
|
84
|
+
export { CommonProvider, Provider, InputCommonProvider, providerDefault, useProvider, updateProvider }
|
|
85
|
+
|
|
86
|
+
const rowProvider = Symbol()
|
|
87
|
+
const rowProviderDefault = ref({ gutter: 10, count: 0 })
|
|
88
|
+
const updateRowProvider = (provider: typeof rowProviderDefault) => provide(rowProvider, provider)
|
|
89
|
+
const useRowProvider = () => inject(rowProvider, rowProviderDefault)
|
|
90
|
+
export { updateRowProvider, useRowProvider }
|
|
91
|
+
|
|
92
|
+
interface CheckedGroupProvider {
|
|
93
|
+
change: (value: any) => void,
|
|
94
|
+
checked: (value: any) => boolean
|
|
95
|
+
}
|
|
96
|
+
const checkedGroupProvider = Symbol()
|
|
97
|
+
const updateCheckedGroupProvider = (provider: Ref<CheckedGroupProvider>) => provide(checkedGroupProvider, provider)
|
|
98
|
+
const useCheckedGroupProvider = () => inject<Ref<CheckedGroupProvider> | null>(checkedGroupProvider, null)
|
|
99
|
+
export { updateCheckedGroupProvider, useCheckedGroupProvider }
|
|
100
|
+
|
|
101
|
+
const cascaderProvider = Symbol()
|
|
102
|
+
const cascaderProviderDefault = ref({
|
|
103
|
+
getPopoverLayout(layout: SelectPopoverLayout) { },
|
|
104
|
+
getInputValue(value: string, options: Options, getter: DataGetter) {
|
|
105
|
+
for (const option of options) {
|
|
106
|
+
if (getter.value(option) === value) return getter.label(option)
|
|
107
|
+
}
|
|
108
|
+
return value
|
|
109
|
+
},
|
|
110
|
+
searchOptions: [] as Options,
|
|
111
|
+
getSearchOptions(value: string, options: Options, getter: DataGetter) {
|
|
112
|
+
const filterOptions: Options = []
|
|
113
|
+
for (const option of options) {
|
|
114
|
+
if (getter.disabled(option) === true) continue
|
|
115
|
+
if (getter.label(option).indexOf(value) === -1) continue
|
|
116
|
+
filterOptions.push(option)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return filterOptions
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
const updateCascaderProvider = (provider: typeof cascaderProviderDefault) => provide(cascaderProvider, provider)
|
|
123
|
+
const useCascaderProvider = () => inject(cascaderProvider, ref({ ...cascaderProviderDefault.value, searchOptions: [] }))
|
|
124
|
+
export { cascaderProviderDefault, updateCascaderProvider, useCascaderProvider }
|
|
125
|
+
|
|
126
|
+
interface TreeProvider {
|
|
127
|
+
handleClick(item: TreeOption, e: MouseEvent): void
|
|
128
|
+
handleModify(v: string, item: TreeOption): void
|
|
129
|
+
handleRightClick(item: TreeOption, e: MouseEvent): void
|
|
130
|
+
handleChange(items: TreeOption[]): void
|
|
131
|
+
handleExpand(item: TreeOption): void
|
|
132
|
+
/**获取`location`节点相对`item`节点的邻接关系`(-1 1 0)` */
|
|
133
|
+
getAdjacencies(location: TreeOption, item: TreeOption, tree?: TreeOptions): number | null
|
|
134
|
+
}
|
|
135
|
+
const treeProvider = Symbol()
|
|
136
|
+
const treeProviderDefault: Ref<TreeProvider> = ref({
|
|
137
|
+
handleClick(item, e) { },
|
|
138
|
+
handleModify(v, item) { },
|
|
139
|
+
handleRightClick(item, e) { },
|
|
140
|
+
handleChange() { },
|
|
141
|
+
handleExpand(item) { },
|
|
142
|
+
getAdjacencies(location, item, tree) { return 0 },
|
|
143
|
+
})
|
|
144
|
+
const updateTreeProvider = (provider: Ref<TreeProvider>) => provide(treeProvider, provider)
|
|
145
|
+
const useTreeProvider = () => inject(treeProvider, treeProviderDefault)
|
|
146
|
+
export { TreeProvider, updateTreeProvider, useTreeProvider }
|
|
147
|
+
|
|
148
|
+
const popoverProvider = Symbol()
|
|
149
|
+
const popoverProviderDefault = ref({
|
|
150
|
+
autoClose: true,
|
|
151
|
+
useFlexLayout: false,
|
|
152
|
+
appendToTooltip: true,
|
|
153
|
+
})
|
|
154
|
+
const updatePopoverProvider = (provider: typeof popoverProviderDefault) => provide(popoverProvider, provider)
|
|
155
|
+
const usePopoverProvider = () => inject(popoverProvider, popoverProviderDefault)
|
|
156
|
+
export { popoverProviderDefault, updatePopoverProvider, usePopoverProvider }
|
|
157
|
+
|
|
158
|
+
interface FlotaLayerProvider {
|
|
159
|
+
listener: Listener<{ move(): void }>
|
|
160
|
+
layer: ComputedRef<number>
|
|
161
|
+
}
|
|
162
|
+
const flotaLayerProvider = Symbol()
|
|
163
|
+
const updateFlotaLayerProvider = (provider: FlotaLayerProvider) => provide(flotaLayerProvider, provider)
|
|
164
|
+
const useFlotaLayerProvider = () => inject<FlotaLayerProvider | null>(flotaLayerProvider, null)
|
|
165
|
+
export { FlotaLayerProvider, updateFlotaLayerProvider, useFlotaLayerProvider }
|
|
166
|
+
|
|
167
|
+
const validateProvider = Symbol()
|
|
168
|
+
const validateProviderDefault = ref({
|
|
169
|
+
options: { tips: true, icon: true },
|
|
170
|
+
rules: [] as string[],
|
|
171
|
+
validateCollection: {} as ValidateCollection,
|
|
172
|
+
addRule(rule: string) { },
|
|
173
|
+
removeRule(rule: string) { },
|
|
174
|
+
validateItem(rule: string, value: any) { }
|
|
175
|
+
})
|
|
176
|
+
const updateValidateProvider = (provider: typeof validateProviderDefault) => provide(validateProvider, provider)
|
|
177
|
+
const useValidateProvider = () => inject(validateProvider, validateProviderDefault)
|
|
178
|
+
export { updateValidateProvider, useValidateProvider }
|
|
179
|
+
|
|
180
|
+
const validateItemProvider = Symbol()
|
|
181
|
+
const validateItemProviderDefault = ref({
|
|
182
|
+
validate(value: any) { }
|
|
183
|
+
})
|
|
184
|
+
const updateValidateItemProvider = (provider: typeof validateItemProviderDefault) => provide(validateItemProvider, provider)
|
|
185
|
+
const useValidateItemProvider = () => inject(validateItemProvider, validateItemProviderDefault)
|
|
186
|
+
export { updateValidateItemProvider, useValidateItemProvider }
|