@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,223 @@
1
+ <template>
2
+ <div class="vyr-select" :style="`width:${curInputWidth};`">
3
+ <vyr-popover ref="refPopover" :model-value="state.visible" :placement="placement"
4
+ :popover-class="`vyr-select-popover ${popoverClass}`" :disabled="curReadonly" :popover-card="popoverCard"
5
+ :arrow="arrow" :offset="offset" @update:model-value="popoverVisibleChange" @trigger-change="changeTrigger">
6
+ <template #trigger>
7
+ <slot name="trigger">
8
+ <div class="select-wrapper">
9
+ <vyr-input :model-value="curInputValue" :readonly="curReadonly || searchable === false"
10
+ :clearable="curClearable" :readonly-clearable="curReadonlyClearable" :placeholder="curPlaceholder"
11
+ :width="`100%`" :draggable :dragkey @focus="startSearch" @blur="clearSearch"
12
+ @update:model-value="updateSearch" @click="stopClosePopover" @clear.stop="clear">
13
+ <template #icon="icon">
14
+ <i v-if="showClear(icon.clearable, curReadonly, curReadonlyClearable, curInputValue)"
15
+ class="vyrfont vyr-shanchu vyr-input-icon" @click.stop="clear"></i>
16
+ <i v-else class="vyrfont vyr-arrow-down-bold vyr-input-icon" :class="{ 'active': state.visible }">
17
+ </i>
18
+ </template>
19
+ </vyr-input>
20
+ </div>
21
+ </slot>
22
+ </template>
23
+ <slot name="default" :width="slotWidth" :forced-prompt="searchState.forcedPrompt">
24
+ <vyr-options :data="renderOptions" :getter="curGetter" :addable="addable" :removable="removable"
25
+ :editable="editable" :forced-prompt="searchState.forcedPrompt" :checked="[modelValue]" :width="slotWidth"
26
+ @click="change" @add="triggerAdd" @remove="triggerRemove" @edit="triggerEdit"></vyr-options>
27
+ </slot>
28
+ </vyr-popover>
29
+ </div>
30
+ </template>
31
+
32
+ <script lang="ts" setup>
33
+ import { ref, computed, useTemplateRef } from 'vue'
34
+ import { Option, Options } from './types';
35
+ import { inputCommonDefaultProps, useCommonProps, useInputCommonProps } from './composables/useDefaultProps';
36
+ import { commonDefaultProps, selectCommonDefaultProps, popoverCommonDefaultProps, getterCommonDefaultProps } from './composables/useDefaultProps';
37
+ import { updateValidateItemProvider, useValidateItemProvider } from './composables/useProvider';
38
+ import { searchDefaultProps, useSearch } from './composables/useSearch'
39
+ import { observer, usePopover } from './composables/usePopover';
40
+ import { useGetter } from './composables/useGetter';
41
+ import VyrPopover from './Popover.vue';
42
+ import VyrInput from './Input.vue'
43
+ import VyrOptions from './Options.vue'
44
+
45
+ const validateProvider = useValidateItemProvider()
46
+ updateValidateItemProvider(ref({ validate() { } }))
47
+
48
+ const refPopover = useTemplateRef('refPopover')
49
+ const emit = defineEmits(['update:modelValue', 'change', 'show', 'close', 'clear', 'add', 'remove', 'edit'])
50
+
51
+ const props = defineProps({
52
+ ...commonDefaultProps,
53
+ ...selectCommonDefaultProps,
54
+ ...popoverCommonDefaultProps,
55
+ ...inputCommonDefaultProps,
56
+ ...searchDefaultProps,
57
+ ...getterCommonDefaultProps,
58
+ addable: { default: false },
59
+ removable: { default: false },
60
+ editable: { default: false },
61
+ popoverCard: { default: false },
62
+ popoverWidth: { default: 'auto' },
63
+ data: { default(): Options { return [] } },
64
+ })
65
+
66
+ const curGetter = useGetter(props)
67
+ const { curInputWidth } = useInputCommonProps(props)
68
+ const { state, slotWidth, resize, cascaderProvider } = usePopover(props, refPopover)
69
+ const { curReadonly, curClearable, curReadonlyClearable, showClear } = useCommonProps(props)
70
+ const { searchState, startSearch, updateSearch, clearSearch } = useSearch(props, cascaderProvider, curGetter)
71
+
72
+ const popoverState = {
73
+ bind: false,
74
+ cur: null as Element | null,
75
+ triggerResize: () => { },
76
+
77
+ }
78
+ const changeTrigger = (cur: Element) => {
79
+ if (popoverState.bind) {
80
+ unbindResizePopover()
81
+ popoverState.cur = cur
82
+ bindResizePopover()
83
+ } else {
84
+ popoverState.cur = cur
85
+ }
86
+ }
87
+ const bindResizePopover = () => {
88
+ popoverState.bind = true
89
+ if (popoverState.cur) popoverState.triggerResize = observer.listen(popoverState.cur, resize)
90
+ }
91
+ const unbindResizePopover = () => {
92
+ popoverState.bind = false
93
+ if (popoverState.cur) observer.unlisten(popoverState.cur)
94
+ popoverState.triggerResize = () => { }
95
+ }
96
+ const popoverVisibleChange = (visible: boolean) => {
97
+ state.value.visible = visible
98
+ if (visible) {
99
+ emit('show')
100
+ bindResizePopover()
101
+ } else {
102
+ unbindResizePopover()
103
+ emit('close')
104
+ }
105
+ validateProvider.value.validate(props.modelValue)
106
+ }
107
+ const stopClosePopover = (e: MouseEvent) => { if (state.value.visible === true) e.stopPropagation() }
108
+
109
+ const curSelectValue = computed(() => cascaderProvider.value.getInputValue(props.modelValue, props.data, curGetter))
110
+ const renderOptions = computed(() => {
111
+ if (props.searchable === false) return props.data
112
+ return cascaderProvider.value.searchOptions.length === 0 ? props.data : cascaderProvider.value.searchOptions
113
+ })
114
+ const curInputValue = computed(() => {
115
+ if (props.searchable === false) return curSelectValue.value
116
+ return [0].includes(searchState.value.status) ? curSelectValue.value : searchState.value.content
117
+ })
118
+ const curPlaceholder = computed(() => {
119
+ if (props.searchable === false) return props.placeholder
120
+ return searchState.value.status === 0 || curSelectValue.value === '' ? props.placeholder : curSelectValue.value
121
+ })
122
+
123
+ const triggerAdd = (...args: any[]) => {
124
+ emit('add', ...args)
125
+ }
126
+ const triggerEdit = (...args: any[]) => {
127
+ emit('edit', ...args)
128
+ }
129
+ const triggerRemove = (...args: any[]) => {
130
+ emit('remove', ...args)
131
+ }
132
+
133
+ const show = () => {
134
+ if (curReadonly.value === true) return state.value.visible = false
135
+ state.value.visible = true
136
+ }
137
+ const close = () => {
138
+ state.value.visible = false
139
+ }
140
+ const change = (item: Option, e: MouseEvent) => {
141
+ const value = curGetter.value(item)
142
+ if (props.modelValue !== value) {
143
+ emit('update:modelValue', value)
144
+ emit('change', value)
145
+ }
146
+ e.stopPropagation()
147
+ close()
148
+ }
149
+ const clear = () => {
150
+ emit('update:modelValue', '')
151
+ emit('change', '')
152
+ emit('clear', '')
153
+ close()
154
+ if (state.value.visible === false) validateProvider.value.validate('')
155
+ }
156
+
157
+ defineExpose({ show, close, resize: () => popoverState.triggerResize() })
158
+ </script>
159
+
160
+ <style lang="less" scoped>
161
+ @import '../theme/global.less';
162
+
163
+ .vyr-select {
164
+ .vyr-font-family;
165
+ color: var(--vyr-font-color);
166
+ font-size: var(--vyr-font-size);
167
+
168
+ .select-wrapper {
169
+ position: relative;
170
+ left: 0;
171
+ top: 0;
172
+ width: 100%;
173
+ height: var(--vyr-input-height);
174
+
175
+ :deep(.input-wrapper) {
176
+ cursor: pointer;
177
+ padding-right: var(--vyr-input-icon-size);
178
+ }
179
+
180
+ :deep(.vyr-input-icon).active,
181
+ .vyr-input-icon.active,
182
+ .vyr-input-icon:hover {
183
+ color: var(--vyr-active-topic-color);
184
+ }
185
+
186
+ :deep(.vyr-input-icon).active,
187
+ .vyr-input-icon.active {
188
+ transform: rotate(180deg);
189
+ }
190
+
191
+ .vyr-shanchu {
192
+ font-size: 18px;
193
+ pointer-events: auto;
194
+ }
195
+ }
196
+ }
197
+
198
+ .vyr-select-popover {
199
+
200
+ .vyr-remove {
201
+ color: var(--vyr-helper-color);
202
+ transition: all var(--vyr-animation-time);
203
+ }
204
+
205
+ .vyr-options {
206
+ border-radius: 0;
207
+ }
208
+
209
+ .vyr-options:not(:first-child) {
210
+ border-left-color: transparent;
211
+ }
212
+
213
+ .vyr-options:first-child {
214
+ border-top-left-radius: var(--vyr-radius-size);
215
+ border-bottom-left-radius: var(--vyr-radius-size);
216
+ }
217
+
218
+ .vyr-options:last-child {
219
+ border-top-right-radius: var(--vyr-radius-size);
220
+ border-bottom-right-radius: var(--vyr-radius-size);
221
+ }
222
+ }
223
+ </style>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <WrapperSlots></WrapperSlots>
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ import { VNode, useAttrs } from 'vue';
7
+ import { getDirective, getFirstVNode, getOnlyNode } from './utils';
8
+
9
+ const attrs = useAttrs() as any
10
+ const emit = defineEmits(['slotChange'])
11
+ const slots = defineSlots<{ default(): VNode[] }>()
12
+ const directive = getDirective(emit)
13
+
14
+ const WrapperSlots = () => {
15
+ const slotQueue = slots.default?.() ?? []
16
+
17
+ const root = getFirstVNode(slotQueue)
18
+
19
+ const trigger = getOnlyNode(root, attrs, directive)
20
+
21
+ return trigger
22
+ }
23
+ </script>
@@ -0,0 +1,262 @@
1
+ <template>
2
+ <div v-for="(item, i) in renderQueue" :key="i" class="vyr-sub-tree">
3
+ <vyr-option v-if="item" :data-vyr-tree="getter.value(item)" :class="className(item)" :label="getter.label(item)"
4
+ :value="getter.value(item)" :disabled="getter.disabled(item)" :warning="warning(item)"
5
+ :checked="checked.includes(getter.value(item))" @click="e => handleClick(item, e)"
6
+ @mousedown="e => mousedown(item, e)" @mouseup="e => mouseup(item, e)" @mouseenter="e => mouseenter(item, e)"
7
+ @mouseleave="e => mouseleave(item, e)" @right-click="e => treeProvider.handleRightClick(item, e)">
8
+ <div class="sub-tree-item" :style="`padding-left:${layer * 10}px;`">
9
+ <div class="tree-arrow" :class="{ 'active': expand.includes(getter.value(item)) }">
10
+ <i class="vyrfont" :class="`${icon}`" v-if="getter.arrow(item)"></i>
11
+ </div>
12
+ <div class="tree-label" v-if="modifyEditState(item)">
13
+ <vyr-input class="modify" :model-value="getter.label(item)" :autofocus="true"
14
+ @blur="(v) => treeProvider.handleModify(v, item)"></vyr-input>
15
+ </div>
16
+ <div class="tree-label" v-else>
17
+ <slot :item="item" :active="expand.includes(getter.value(item))">
18
+ <div class="label-text">{{ getter.label(item) }}</div>
19
+ </slot>
20
+ </div>
21
+ </div>
22
+ </vyr-option>
23
+ <vyr-option v-if="modifyAddState(item)" class="modify-tree-item" :data-vyr-tree="getter.value(item)">
24
+ <div class="sub-tree-item" :style="`padding-left:${(layer + 1) * 10}px;`">
25
+ <div class="tree-arrow" :class="{ 'active': expand.includes(getter.value(item)) }"></div>
26
+ <div class="tree-label">
27
+ <vyr-input class="modify" :autofocus="true" @blur="(v) => treeProvider.handleModify(v, item)"></vyr-input>
28
+ </div>
29
+ </div>
30
+ </vyr-option>
31
+ <sub-tree v-if="show(item)" :data="getter.children(item)" :multiple="multiple" :getter="getter" :layer="layer + 1"
32
+ :expand="expand" :draggable="draggable" :modify="modify" :modify-value="modifyValue" :checked="checked"
33
+ :line="checked.includes(getter.value(item))" :visible="visible" :warning="warning">
34
+ <template #default="{ item, active }">
35
+ <slot :item="item" :active="active"></slot>
36
+ </template>
37
+ </sub-tree>
38
+ </div>
39
+ </template>
40
+
41
+ <script lang="ts" setup>
42
+ import { computed } from 'vue';
43
+ import { SubTreeSlots, TreeOption } from './types';
44
+ import { useDraggable } from './composables/useDraggable'
45
+ import { defaultGetter } from './composables/useGetter';
46
+ import { treeCommonDefaultProps } from './composables/useDefaultProps'
47
+ import { useTreeProvider } from './composables/useProvider';
48
+ import VyrOption from './Option.vue';
49
+ import VyrInput from './Input.vue';
50
+
51
+ defineSlots<SubTreeSlots>()
52
+
53
+ const treeProvider = useTreeProvider()
54
+ const props = defineProps({
55
+ layer: { default: 0 },
56
+ line: { default: false },
57
+ expand: { default() { return [] as string[] } },
58
+ checked: { default() { return [] as any[] } },
59
+ icon: { default: 'vyr-arrow-down-bold' },
60
+ getter: { default: () => defaultGetter },
61
+ ...treeCommonDefaultProps,
62
+ })
63
+
64
+ const renderQueue = computed(() => {
65
+ const queue: TreeOption[] = []
66
+
67
+ for (const item of props.data) {
68
+ if (props.visible(item)) queue.push(item)
69
+ }
70
+
71
+ return queue
72
+ })
73
+
74
+ const { drag, mousedown, mouseup, mouseenter, mouseleave } = useDraggable(props, treeProvider)
75
+
76
+ const className = (item: TreeOption) => {
77
+ const obj = {
78
+ 'modify-tree-item': modifyEditState(item),
79
+ 'draggable': drag.value.value === props.getter.value(item),
80
+ 'after-draggable': drag.value.type === 'insertAfter',
81
+ 'before-draggable': drag.value.type === 'insertBefore',
82
+ }
83
+ return obj
84
+ }
85
+ const show = (item: TreeOption) => {
86
+ if (props.visible(item) === false) return false
87
+
88
+ if (props.modify !== 'close' && props.modifyValue === props.getter.value(item)) return true
89
+
90
+ if (props.expand.includes(props.getter.value(item)) && props.getter.children(item).length > 0) return true
91
+
92
+
93
+ return false
94
+ }
95
+
96
+ const modifyEditState = (item: TreeOption) => {
97
+ if (props.modify !== 'edit') return false
98
+
99
+ if (props.modifyValue !== props.getter.value(item)) return false
100
+
101
+ return true
102
+ }
103
+ const modifyAddState = (item: TreeOption) => {
104
+ if (props.modify !== 'add') return false
105
+
106
+ if (props.modifyValue !== props.getter.value(item)) return false
107
+
108
+ return true
109
+ }
110
+
111
+ const handleClick = (item: TreeOption, e: MouseEvent) => {
112
+ if (props.multiple === true) {
113
+ if (e.shiftKey === true && props.checked.length > 0) {
114
+ const currentValue = props.checked[0]
115
+ let current = renderQueue.value.find(item => props.getter.value(item) === currentValue)
116
+ if (current) {
117
+
118
+ const currentIndex = renderQueue.value.indexOf(current)
119
+ const selectionIndex = renderQueue.value.indexOf(item)
120
+ const start = Math.min(currentIndex, selectionIndex)
121
+ const end = Math.max(currentIndex, selectionIndex)
122
+
123
+ const items: TreeOption[] = []
124
+ for (let i = start; i <= end; i++) {
125
+ items.push(renderQueue.value[i])
126
+ }
127
+ treeProvider.value.handleChange(items)
128
+
129
+ return
130
+ }
131
+ }
132
+ }
133
+
134
+ treeProvider.value.handleClick(item, e)
135
+ }
136
+ </script>
137
+
138
+ <style lang="less">
139
+ @import '../theme/global.less';
140
+
141
+ @icon-size: 28px;
142
+
143
+ .vyr-sub-tree {
144
+ .vyr-font-family;
145
+ width: 100%;
146
+ color: var(--vyr-font-color);
147
+ font-size: var(--vyr-font-size);
148
+ position: relative;
149
+ left: 0;
150
+ top: 0;
151
+ display: flex;
152
+ flex-wrap: wrap;
153
+ flex-direction: row;
154
+ justify-content: flex-end;
155
+ align-items: center;
156
+ align-content: center;
157
+
158
+ .sub-tree-item {
159
+ width: 100%;
160
+ height: 100%;
161
+ display: flex;
162
+ flex-wrap: nowrap;
163
+ flex-direction: row;
164
+ justify-content: flex-start;
165
+ align-items: center;
166
+ align-content: center;
167
+ user-select: none;
168
+
169
+ .tree-arrow {
170
+ width: @icon-size;
171
+ height: 100%;
172
+ display: flex;
173
+ flex-wrap: nowrap;
174
+ flex-direction: row;
175
+ justify-content: center;
176
+ align-items: center;
177
+ align-content: center;
178
+ transform: rotate(-90deg);
179
+ }
180
+
181
+ .tree-label {
182
+ width: calc(~'100% - @{icon-size}');
183
+ height: 100%;
184
+ display: flex;
185
+ flex-wrap: nowrap;
186
+ flex-direction: row;
187
+ justify-content: flex-start;
188
+ align-items: center;
189
+ align-content: center;
190
+
191
+ .label-text {
192
+ width: 100%;
193
+ text-align: left;
194
+ overflow: hidden;
195
+ word-break: break-all;
196
+ white-space: nowrap;
197
+ text-overflow: ellipsis;
198
+ }
199
+ }
200
+
201
+ .tree-arrow.active {
202
+ transform: rotate(0);
203
+ }
204
+ }
205
+
206
+ .vyr-option {
207
+ margin: var(--vyr-option-margin) 0;
208
+ padding-left: 0px;
209
+ }
210
+
211
+ .vyr-option.draggable {
212
+ background-color: var(--vyr-draggable-color);
213
+ }
214
+
215
+ .draggable.after-draggable::before,
216
+ .draggable.before-draggable::after {
217
+ content: '';
218
+ width: 100%;
219
+ height: 4px;
220
+ background-color: var(--vyr-flashing-draggable-color);
221
+ animation: tree-draggable 1s infinite;
222
+ pointer-events: none;
223
+ }
224
+
225
+
226
+ .draggable.before-draggable {
227
+ position: relative;
228
+ left: 0;
229
+ top: 0;
230
+
231
+ &::after {
232
+ position: absolute;
233
+ left: 0;
234
+ top: 0;
235
+ }
236
+ }
237
+
238
+ .draggable.after-draggable {
239
+ position: relative;
240
+ left: 0;
241
+ top: 0;
242
+
243
+ &::before {
244
+ position: absolute;
245
+ left: 0;
246
+ bottom: 0;
247
+ }
248
+ }
249
+ }
250
+
251
+ @keyframes tree-draggable {
252
+
253
+ 0%,
254
+ 100% {
255
+ opacity: 0.2;
256
+ }
257
+
258
+ 50% {
259
+ opacity: 1;
260
+ }
261
+ }
262
+ </style>
@@ -0,0 +1,129 @@
1
+ <template>
2
+ <div class="vyr-tree" :class="{ 'modify-tree': modify !== 'close' }">
3
+ <vyr-sub-tree :data="data" :getter="curGetter" :expand="state.expand" :checked="state.checked"
4
+ :draggable="draggable" :modify="modify" :multiple="multiple" :modify-value="modifyValue" :visible="visible"
5
+ :warning="warning">
6
+ <template #default="content">
7
+ <slot v-bind="content"></slot>
8
+ </template>
9
+ </vyr-sub-tree>
10
+ </div>
11
+ </template>
12
+
13
+ <script lang="ts" setup>
14
+ import { ref, watch } from 'vue'
15
+ import { TreeOption, DataGetter } from './types'
16
+ import { useGetter, defaultGetter } from "./composables/useGetter"
17
+ import { treeCommonDefaultProps } from './composables/useDefaultProps'
18
+ import { updateTreeProvider } from './composables/useProvider'
19
+ import { ArrayUtils } from '../tool'
20
+ import VyrSubTree from './SubTree.vue'
21
+
22
+ const props = defineProps({
23
+ ...treeCommonDefaultProps,
24
+ getter: { default: () => defaultGetter as Partial<DataGetter> },
25
+ defaultChecked: { default: () => [] as Array<TreeOption | null> },
26
+ })
27
+ const state = ref({
28
+ expand: [] as string[],
29
+ checked: [] as string[],
30
+ })
31
+ const curGetter = useGetter(props)
32
+ const emit = defineEmits(['change', 'rightClick', 'modify'])
33
+ const handleModify = (v: string, item: TreeOption) => {
34
+ emit('modify', props.modify, v, item)
35
+ state.value.checked = [curGetter.value(item)]
36
+ emit('change', [item])
37
+ }
38
+ const handleTrace = (tree: TreeOption[], item: TreeOption, expand: string[] = []) => {
39
+ for (const sub of tree) {
40
+ const value = curGetter.value(sub)
41
+ if (curGetter.value(sub) === curGetter.value(item)) {
42
+ expand.push('__')
43
+ return expand
44
+ }
45
+ if (Array.isArray(sub.children) === false) continue
46
+ handleTrace(sub.children, item, expand)
47
+ if (expand.length > 0) {
48
+ expand.push(value)
49
+ return expand
50
+ }
51
+ }
52
+ return expand
53
+ }
54
+ const handleChange = (items: TreeOption[]) => {
55
+ if (state.value.checked.length === 0 && items.length === 0) return
56
+ state.value.checked = items.map(item => curGetter.value(item))
57
+ emit('change', items)
58
+ }
59
+ const handleClick = (item: TreeOption, e: MouseEvent) => {
60
+ handleChange([item])
61
+ handleExpand(item)
62
+ }
63
+ const handleExpand = (item: TreeOption, type?: boolean) => {
64
+ if (type === true) {
65
+ ArrayUtils.insert(state.value.expand, curGetter.value(item))
66
+ } else if (type === false) {
67
+ ArrayUtils.remove(state.value.expand, curGetter.value(item))
68
+ } else {
69
+ ArrayUtils.auto(state.value.expand, curGetter.value(item))
70
+ }
71
+ }
72
+ const handleRightClick = (item: TreeOption, e: MouseEvent) => {
73
+ emit('rightClick', item, e)
74
+ }
75
+
76
+ const getAdjacencies = (location: TreeOption, item: TreeOption, tree = props.data): number | null => {
77
+ for (let i = 0; i < tree.length; i++) {
78
+ const sub = tree[i]
79
+ if (curGetter.value(sub) === curGetter.value(location)) {
80
+ const i2 = tree.indexOf(item)
81
+ if (i2 === -1) return 0
82
+ const iv = i2 - i
83
+ return Math.abs(iv) === 1 ? iv : 0
84
+ }
85
+
86
+ const adjacencies = getAdjacencies(location, item, curGetter.children(sub))
87
+ if (adjacencies !== null) return adjacencies
88
+ }
89
+
90
+ return null
91
+ }
92
+ updateTreeProvider(ref({ handleClick, handleChange, handleModify, handleRightClick, handleExpand, getAdjacencies }))
93
+
94
+ const watchDefaultChecked = (cur?: Array<TreeOption | null>) => {
95
+ if (!cur || cur.length === 0) {
96
+ state.value.expand = []
97
+ state.value.checked = []
98
+ return
99
+ }
100
+ for (const item of cur) {
101
+ if (!item) continue
102
+ const value = curGetter.value(item)
103
+ state.value.checked = [value]
104
+ const expands = handleTrace(props.data, item)
105
+ for (const item of expands) ArrayUtils.insert(state.value.expand, item)
106
+ }
107
+ }
108
+ watch(() => props.defaultChecked, watchDefaultChecked, { immediate: true })
109
+
110
+ defineExpose({
111
+ change: handleChange,
112
+ expand: handleExpand,
113
+ })
114
+ </script>
115
+
116
+ <style lang="less" scoped>
117
+ @import '../theme/global.less';
118
+
119
+ .modify-tree {
120
+ .vyr-font-family;
121
+ width: 100%;
122
+
123
+ :deep(.modify-tree-item) {
124
+ background-color: transparent !important;
125
+ transition: none;
126
+ padding-right: 0;
127
+ }
128
+ }
129
+ </style>