@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,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 }