@teammodlr/ui-kit 2.1.5 → 2.1.7
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/lib/call.d.ts +7 -0
- package/lib/components/confirm/Confirm.vue.d.ts +46 -0
- package/lib/components/{dialog/DialogProvider.vue.d.ts → confirm/ConfirmProvider.vue.d.ts} +5 -5
- package/lib/components/{dialog → confirm}/props.d.ts +2 -2
- package/lib/components/confirm/types.d.ts +27 -0
- package/lib/components/confirm/useConfirm.d.ts +2 -0
- package/lib/components/dialog/Dialog.vue.d.ts +90 -41
- package/lib/components/dialog/style/Dialog.css.d.ts +11 -0
- package/lib/components/dialog/style/index.d.ts +1 -0
- package/lib/components/dialog/types.d.ts +0 -27
- package/lib/components/index.d.ts +3 -1
- package/lib/components/tree/Tree.vue.d.ts +108 -0
- package/lib/components/tree/TreeNode.vue.d.ts +22 -0
- package/lib/components/tree/TreeNodeToggle.vue.d.ts +26 -0
- package/lib/components/tree/props.d.ts +72 -0
- package/lib/components/tree/types.d.ts +58 -0
- package/lib/composables/index.d.ts +1 -1
- package/lib/composables/useMergedState.d.ts +2 -0
- package/lib/index.cjs.js +18 -2
- package/lib/index.es.js +4804 -2847
- package/lib/style.css +1 -1
- package/lib/utils/injection.d.ts +2 -0
- package/package.json +6 -4
- package/src/call.ts +34 -0
- package/src/components/confirm/Confirm.vue +60 -0
- package/src/components/{dialog/DialogProvider.vue → confirm/ConfirmProvider.vue} +18 -18
- package/src/components/confirm/examples/basic.vue +48 -0
- package/src/components/confirm/examples/index.stories.ts +29 -0
- package/src/components/confirm/examples/index.ts +1 -0
- package/src/components/{dialog → confirm}/props.ts +2 -2
- package/src/components/confirm/types.ts +34 -0
- package/src/components/confirm/useConfirm.ts +12 -0
- package/src/components/dialog/Dialog.vue +102 -44
- package/src/components/dialog/examples/basic.vue +8 -40
- package/src/components/dialog/examples/index.stories.ts +11 -22
- package/src/components/dialog/examples/index.ts +1 -1
- package/src/components/dialog/style/Dialog.css.ts +99 -0
- package/src/components/dialog/style/index.ts +1 -0
- package/src/components/dialog/types.ts +0 -34
- package/src/components/index.ts +3 -1
- package/src/components/select/Select.vue +4 -0
- package/src/components/tree/Tree.vue +137 -0
- package/src/components/tree/TreeNode.vue +103 -0
- package/src/components/tree/TreeNodeToggle.vue +36 -0
- package/src/components/tree/examples/basic.vue +13 -0
- package/src/components/tree/examples/index.stories.ts +16 -0
- package/src/components/tree/examples/index.ts +1 -0
- package/src/components/tree/props.ts +95 -0
- package/src/components/tree/types.ts +104 -0
- package/src/composables/index.ts +1 -1
- package/src/composables/useMergedState.ts +18 -0
- package/src/utils/injection.ts +5 -0
- package/lib/components/dialog/useDialog.d.ts +0 -2
- package/src/components/dialog/useDialog.ts +0 -12
- /package/lib/components/{dialog → confirm}/providerProps.d.ts +0 -0
- /package/src/components/{dialog → confirm}/examples/wrapper.vue +0 -0
- /package/src/components/{dialog → confirm}/providerProps.ts +0 -0
|
@@ -1,60 +1,118 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
{{ content }}
|
|
6
|
-
</template>
|
|
7
|
-
|
|
8
|
-
<template #footer>
|
|
9
|
-
<div style="display: flex; flex-grow: 1; justify-content: end;">
|
|
10
|
-
<MButton :variant="okVariant" @click="handleOk">
|
|
11
|
-
{{ okText ?? 'Okay' }}
|
|
12
|
-
</MButton>
|
|
13
|
-
<MButton style="margin-left: 8px;" @click="handleCancel">
|
|
14
|
-
{{ cancelText ?? 'Cancel' }}
|
|
15
|
-
</MButton>
|
|
2
|
+
<Teleport to="body">
|
|
3
|
+
<div :class="style.root">
|
|
4
|
+
<div :class="backdropClasses">
|
|
16
5
|
</div>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
<div ref="wrapper" :class="style.wrapper">
|
|
7
|
+
<div ref="dialog" :class="style.dialog" :style="{
|
|
8
|
+
// top: y + 'px',
|
|
9
|
+
// left: x + 'px',
|
|
10
|
+
zIndex: zIndex,
|
|
11
|
+
width: width
|
|
12
|
+
}">
|
|
13
|
+
<div tabindex="0" aria-hidden="true" style="width: 0px; height: 0px; overflow: hidden; outline: none;"></div>
|
|
14
|
+
<div :class="style.content">
|
|
15
|
+
<button role="button" :class="style.close">x</button>
|
|
16
|
+
<div :class="style.header" ref="handle">
|
|
17
|
+
<div :class="style.title">
|
|
18
|
+
<slot name="title">
|
|
19
|
+
Title
|
|
20
|
+
</slot>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
<div>
|
|
24
|
+
<slot></slot>
|
|
25
|
+
</div>
|
|
26
|
+
<div :class="style.footer">
|
|
27
|
+
<slot name="footer"></slot>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
<div tabindex="0" aria-hidden="true" style="width: 0px; height: 0px; overflow: hidden; outline: none;"></div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
21
34
|
|
|
35
|
+
</Teleport>
|
|
36
|
+
</template>
|
|
22
37
|
<script lang="ts">
|
|
23
|
-
import { defineComponent,
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import
|
|
38
|
+
import {computed, defineComponent, type PropType, ref} from "vue";
|
|
39
|
+
import {useZIndex} from "../../composables/useZIndex";
|
|
40
|
+
import {useDraggable} from "@vueuse/core";
|
|
41
|
+
import * as style from "./style";
|
|
27
42
|
|
|
28
43
|
export default defineComponent({
|
|
29
44
|
name: "Dialog",
|
|
30
|
-
props:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
props: {
|
|
46
|
+
title: {
|
|
47
|
+
type: String,
|
|
48
|
+
default: ""
|
|
49
|
+
},
|
|
50
|
+
draggable: {
|
|
51
|
+
type: Boolean,
|
|
52
|
+
default: false
|
|
53
|
+
},
|
|
54
|
+
backdrop: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: false,
|
|
57
|
+
},
|
|
58
|
+
onClose: {
|
|
59
|
+
type: Function as PropType<() => void>,
|
|
60
|
+
default: () => {
|
|
40
61
|
}
|
|
62
|
+
},
|
|
63
|
+
zIndex: {
|
|
64
|
+
type: Number
|
|
65
|
+
},
|
|
66
|
+
width: {
|
|
67
|
+
type: [Number, String],
|
|
68
|
+
default: "500px"
|
|
69
|
+
},
|
|
70
|
+
transformOrigin: {
|
|
71
|
+
type: String as PropType<'center' | 'mouse'>,
|
|
72
|
+
default: 'mouse'
|
|
73
|
+
},
|
|
74
|
+
focusTrap: {
|
|
75
|
+
type: Boolean,
|
|
76
|
+
default: true
|
|
41
77
|
}
|
|
78
|
+
},
|
|
79
|
+
emits: ['onOpen', 'onClose'],
|
|
80
|
+
setup(props, {slots}) {
|
|
81
|
+
const wrapper = ref<HTMLElement | null>(null);
|
|
82
|
+
const dialog = ref<HTMLElement | null>(null);
|
|
83
|
+
const handle = ref<HTMLElement | null>(null);
|
|
84
|
+
const {x, y} = useDraggable(dialog, {
|
|
85
|
+
handle: handle,
|
|
86
|
+
preventDefault: true,
|
|
87
|
+
// containerElement: wrapper,
|
|
88
|
+
});
|
|
89
|
+
const {nextZIndex} = useZIndex();
|
|
42
90
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
props.
|
|
91
|
+
const backdropClasses = computed(() => {
|
|
92
|
+
return {
|
|
93
|
+
[style.backdrop]: true,
|
|
94
|
+
[style.backdropColor]: props.backdrop === true
|
|
47
95
|
}
|
|
48
|
-
}
|
|
49
|
-
onMounted(() => {
|
|
50
|
-
modal.value?.open(null);
|
|
51
96
|
});
|
|
97
|
+
|
|
98
|
+
const width = computed(() => {
|
|
99
|
+
return typeof props.width === "number" ? props.width + "px" : props.width;
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const zIndex = ref(props.zIndex ?? nextZIndex());
|
|
52
103
|
return {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
104
|
+
slots,
|
|
105
|
+
wrapper,
|
|
106
|
+
dialog,
|
|
107
|
+
handle,
|
|
108
|
+
zIndex,
|
|
109
|
+
width,
|
|
110
|
+
x,
|
|
111
|
+
y,
|
|
112
|
+
style,
|
|
113
|
+
backdropClasses,
|
|
114
|
+
nextZIndex
|
|
56
115
|
};
|
|
57
|
-
}
|
|
58
|
-
components: { MModal }
|
|
116
|
+
}
|
|
59
117
|
});
|
|
60
118
|
</script>
|
|
@@ -1,48 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
<MDialog>
|
|
4
|
+
<input type="text" />
|
|
5
|
+
<input type="text" />
|
|
6
|
+
<template #footer>
|
|
7
|
+
Bootom
|
|
8
|
+
</template>
|
|
9
|
+
</MDialog>
|
|
9
10
|
</div>
|
|
10
11
|
</template>
|
|
11
12
|
|
|
12
13
|
<script lang="ts" setup>
|
|
13
|
-
import { ref } from 'vue'
|
|
14
|
-
import { useDialog } from '../useDialog';
|
|
15
|
-
|
|
16
|
-
const dialog = useDialog();
|
|
17
|
-
|
|
18
|
-
async function showBasicDialog() {
|
|
19
|
-
const result = dialog.create({
|
|
20
|
-
title: 'Hello World',
|
|
21
|
-
content: 'This is a dialog',
|
|
22
|
-
okText: 'OK',
|
|
23
|
-
cancelText: 'Cancel',
|
|
24
|
-
onOk: () => {
|
|
25
|
-
console.log('OK');
|
|
26
|
-
},
|
|
27
|
-
onCancel: () => {
|
|
28
|
-
console.log('Cancel');
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
14
|
+
import { ref } from 'vue'
|
|
32
15
|
|
|
33
|
-
async function showDangerDialog() {
|
|
34
|
-
const result = dialog.create({
|
|
35
|
-
title: 'Hello World',
|
|
36
|
-
content: 'This is a dialog',
|
|
37
|
-
okText: 'Continue',
|
|
38
|
-
okVariant: 'error',
|
|
39
|
-
cancelText: 'Cancel',
|
|
40
|
-
onOk: () => {
|
|
41
|
-
showBasicDialog()
|
|
42
|
-
},
|
|
43
|
-
onCancel: () => {
|
|
44
|
-
console.log('Cancel');
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
16
|
</script>
|
|
@@ -1,29 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import MDialog from "../Dialog.vue";
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
MDialogBasic
|
|
4
4
|
} from "./index";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
MDialogProviderBasic
|
|
10
|
-
},
|
|
11
|
-
setup() {
|
|
12
|
-
|
|
13
|
-
return {
|
|
14
|
-
args,
|
|
15
|
-
};
|
|
16
|
-
},
|
|
17
|
-
template: `
|
|
18
|
-
<m-dialog-provider v-bind="args">
|
|
19
|
-
<MDialogProviderBasic />
|
|
20
|
-
</m-dialog-provider>
|
|
21
|
-
`
|
|
22
|
-
})
|
|
6
|
+
import {
|
|
7
|
+
createStory, sizeArgType
|
|
8
|
+
} from "../../../__storybook__";
|
|
23
9
|
|
|
24
10
|
export default {
|
|
25
|
-
component:
|
|
26
|
-
title: 'Components/Dialog'
|
|
11
|
+
component: MDialog,
|
|
12
|
+
title: 'Components/Dialog',
|
|
13
|
+
argTypes: {
|
|
14
|
+
...sizeArgType(),
|
|
15
|
+
}
|
|
27
16
|
}
|
|
28
17
|
|
|
29
|
-
export const
|
|
18
|
+
export const Basic = createStory(MDialogBasic);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as
|
|
1
|
+
export { default as MDialogBasic } from './basic.vue';
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {createVar, globalKeyframes, style, styleVariants} from "@vanilla-extract/css";
|
|
2
|
+
import {themeVars} from "../../../styles/theme.css";
|
|
3
|
+
|
|
4
|
+
export const vars = {
|
|
5
|
+
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const root = style({
|
|
9
|
+
|
|
10
|
+
});
|
|
11
|
+
export const backdrop = style({
|
|
12
|
+
position: "fixed",
|
|
13
|
+
inset: 0,
|
|
14
|
+
top: 0,
|
|
15
|
+
bottom: 0,
|
|
16
|
+
left: 0,
|
|
17
|
+
right: 0,
|
|
18
|
+
display: "flex",
|
|
19
|
+
justifyContent: "center",
|
|
20
|
+
alignItems: "center",
|
|
21
|
+
pointerEvents: "none",
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export const backdropColor = style({
|
|
25
|
+
backgroundColor: 'rgba(0,0,0,.45)',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const wrapper = style({
|
|
29
|
+
position: "fixed",
|
|
30
|
+
inset: 0,
|
|
31
|
+
top: 0,
|
|
32
|
+
left: 0,
|
|
33
|
+
right: 0,
|
|
34
|
+
bottom: 0,
|
|
35
|
+
outline: 0,
|
|
36
|
+
overflow: "auto",
|
|
37
|
+
boxSizing: "border-box",
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const dialog = style({
|
|
41
|
+
boxSizing: "border-box",
|
|
42
|
+
margin: "0 auto",
|
|
43
|
+
padding: 0,
|
|
44
|
+
position: "relative",
|
|
45
|
+
top: "100px",
|
|
46
|
+
width: "auto",
|
|
47
|
+
maxWidth: `calc(100vw - 32px)`,
|
|
48
|
+
paddingBottom: "24px",
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export const content = style({
|
|
52
|
+
position: "relative",
|
|
53
|
+
backgroundColor: "#FFF",
|
|
54
|
+
backgroundClip: "padding-box",
|
|
55
|
+
border: 0,
|
|
56
|
+
borderRadius: themeVars.rounded.default,
|
|
57
|
+
pointerEvents: "auto",
|
|
58
|
+
padding: `20px 24px`,
|
|
59
|
+
boxShadow: `0 6px 16px 0 rgba(0,0,0,.08), 0 3px 6px -4px rgba(0,0,0,.12), 0 9px 28px 8px rgba(0,0,0,.05)`
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
export const header = style({
|
|
63
|
+
color: themeVars.color.font.default,
|
|
64
|
+
backgroundColor: "#FFF",
|
|
65
|
+
marginBottom: themeVars.space[2],
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const footer = style({
|
|
69
|
+
textAlign: "end",
|
|
70
|
+
background: `0 0`,
|
|
71
|
+
marginTop: themeVars.space[2],
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
export const title = style({
|
|
75
|
+
margin: 0,
|
|
76
|
+
color: themeVars.color.font.default,
|
|
77
|
+
fontWeight: 600,
|
|
78
|
+
lineHeight: 1.5,
|
|
79
|
+
wordWrap: "break-word",
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export const close = style({
|
|
83
|
+
position: "absolute",
|
|
84
|
+
top: `17px`,
|
|
85
|
+
insetInlineEnd: `17px`,
|
|
86
|
+
padding: 0,
|
|
87
|
+
background: `0 0`,
|
|
88
|
+
borderRadius: themeVars.rounded.small,
|
|
89
|
+
width: `22px`,
|
|
90
|
+
height: `22px`,
|
|
91
|
+
border: 0,
|
|
92
|
+
outline: 0,
|
|
93
|
+
cursor: `pointer`,
|
|
94
|
+
selectors: {
|
|
95
|
+
'&:hover': {
|
|
96
|
+
backgroundColor: `hsla(0,0%,45.1%,0.1)`,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Dialog.css';
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { Variant } from '../../types/props';
|
|
2
|
-
import type { VNodeChild } from 'vue';
|
|
3
|
-
|
|
4
|
-
export type DialogContentType = string;
|
|
5
|
-
|
|
6
|
-
export type DialogContentRender = (props: any) => VNodeChild;
|
|
7
|
-
|
|
8
|
-
export interface DialogOptions {
|
|
9
|
-
title?: string,
|
|
10
|
-
render?: DialogContentRender,
|
|
11
|
-
content: DialogContentType,
|
|
12
|
-
onClose?: () => void,
|
|
13
|
-
onOpen?: () => void,
|
|
14
|
-
onOk?: () => void,
|
|
15
|
-
onCancel?: () => void,
|
|
16
|
-
okVariant?: Variant,
|
|
17
|
-
okText?: DialogContentType,
|
|
18
|
-
cancelText?: DialogContentType,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface DialogResponse {
|
|
22
|
-
result: boolean,
|
|
23
|
-
data: any
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface DialogApiInjection {
|
|
27
|
-
create: (options: DialogOptions) => Dialog
|
|
28
|
-
destroyAll: () => void
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
export interface Dialog extends DialogOptions {
|
|
33
|
-
destroy: () => void
|
|
34
|
-
}
|
package/src/components/index.ts
CHANGED
|
@@ -40,5 +40,7 @@ export { default as MTextarea } from './textarea/Textarea.vue';
|
|
|
40
40
|
export { default as MTooltip } from './tooltip/Tooltip.vue';
|
|
41
41
|
export { default as MTransfer } from './transfer/Transfer.vue';
|
|
42
42
|
export { default as MVirtualScroll } from './virtualscroll/VirtualScroll.vue';
|
|
43
|
+
export { default as MConfirm } from './confirm/Confirm.vue';
|
|
44
|
+
export { default as MConfirmProvider } from './confirm/ConfirmProvider.vue';
|
|
43
45
|
export { default as MDialog } from './dialog/Dialog.vue';
|
|
44
|
-
export { default as
|
|
46
|
+
export { default as MTree } from './tree/Tree.vue';
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div style="height: 200px;" ref="selfElRef">
|
|
3
|
+
<VVirtualList
|
|
4
|
+
ref="virtualListInstRef"
|
|
5
|
+
:items="nodesRef"
|
|
6
|
+
itemResizable
|
|
7
|
+
:itemSize="20"
|
|
8
|
+
>
|
|
9
|
+
<template v-slot:default="{ item }">
|
|
10
|
+
<TreeNode :node="item"/>
|
|
11
|
+
</template>
|
|
12
|
+
</VVirtualList>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script lang="ts">
|
|
17
|
+
import {type VirtualListInst, VVirtualList} from 'vueuc'
|
|
18
|
+
import {computed, defineComponent, provide, ref, toRef} from 'vue'
|
|
19
|
+
import {createTreeMateOptions, treeProps} from "./props";
|
|
20
|
+
import type {Key, TmNode, TreeOption} from "./types";
|
|
21
|
+
import {
|
|
22
|
+
createTreeMate,
|
|
23
|
+
} from 'treemate'
|
|
24
|
+
import TreeNode from "./TreeNode.vue";
|
|
25
|
+
import {treeInjectionKey} from "./types";
|
|
26
|
+
import {call} from "../../call";
|
|
27
|
+
import useMergedState from "../../composables/useMergedState";
|
|
28
|
+
|
|
29
|
+
export default defineComponent({
|
|
30
|
+
components: {TreeNode, VVirtualList},
|
|
31
|
+
name: 'Tree',
|
|
32
|
+
props: treeProps,
|
|
33
|
+
emits: ['update:expandedKeys', 'dblclick'],
|
|
34
|
+
setup: function (props, {emit}) {
|
|
35
|
+
const selfElRef = ref<HTMLDivElement | null>(null);
|
|
36
|
+
const virtualListInstRef = ref<VirtualListInst | null>(null)
|
|
37
|
+
|
|
38
|
+
function getScrollContainer(): HTMLElement | null | undefined {
|
|
39
|
+
return virtualListInstRef.value?.listElRef
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getScrollContent(): HTMLElement | null | undefined {
|
|
43
|
+
return virtualListInstRef.value?.itemsElRef
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const displayTreeMateRef = computed(() => {
|
|
47
|
+
return createTreeMate<TreeOption>(
|
|
48
|
+
props.data,
|
|
49
|
+
createTreeMateOptions(
|
|
50
|
+
props.keyField,
|
|
51
|
+
props.childrenField,
|
|
52
|
+
'disabled',
|
|
53
|
+
props.getChildren
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const dataTreeMateRef = displayTreeMateRef;
|
|
59
|
+
const controlledExpandedKeysRef = toRef(props, 'expandedKeys')
|
|
60
|
+
const uncontrolledExpandedKeysRef = ref<Key[]>([])
|
|
61
|
+
const mergedExpandedKeysRef = useMergedState(
|
|
62
|
+
controlledExpandedKeysRef,
|
|
63
|
+
uncontrolledExpandedKeysRef
|
|
64
|
+
)
|
|
65
|
+
const nodesRef = computed(() => {
|
|
66
|
+
return displayTreeMateRef.value.getFlattenedNodes(mergedExpandedKeysRef.value);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
provide(treeInjectionKey, {
|
|
70
|
+
mergedExpandedKeysRef,
|
|
71
|
+
indentRef: toRef(props, 'indent'),
|
|
72
|
+
expandOnClickRef: toRef(props, 'expandOnClick'),
|
|
73
|
+
nodePropsRef: toRef(props, 'nodeProps'),
|
|
74
|
+
labelFieldRef: toRef(props, 'labelField'),
|
|
75
|
+
keyFieldRef: toRef(props, 'keyField'),
|
|
76
|
+
handleDoubleClick,
|
|
77
|
+
handleToggleClick
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// const { watchProps } = props;
|
|
81
|
+
//
|
|
82
|
+
// watchEffect(() => {
|
|
83
|
+
// initUncontrolledExpandedKeys(undefined);
|
|
84
|
+
// })
|
|
85
|
+
|
|
86
|
+
function handleToggleClick(node: TmNode): void {
|
|
87
|
+
|
|
88
|
+
toggleExpand(node);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function handleDoubleClick(node: TreeOption): void {
|
|
92
|
+
emit('dblclick', node);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function toggleExpand(node: TmNode): void {
|
|
96
|
+
const {key} = node;
|
|
97
|
+
const {value: mergedExpandedKeys} = mergedExpandedKeysRef
|
|
98
|
+
const index = mergedExpandedKeys.findIndex(
|
|
99
|
+
(expandedNodeId) => expandedNodeId === key
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if (~index) {
|
|
103
|
+
const expandedKeysAfterChange = Array.from(mergedExpandedKeys);
|
|
104
|
+
expandedKeysAfterChange.splice(index, 1);
|
|
105
|
+
doUpdateExpandedKeys(expandedKeysAfterChange);
|
|
106
|
+
} else {
|
|
107
|
+
const nodeToBeExpanded = displayTreeMateRef.value.getNode(key);
|
|
108
|
+
if (!nodeToBeExpanded || nodeToBeExpanded.isLeaf) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
let nextKeys: Key[] = mergedExpandedKeys.concat(key);
|
|
113
|
+
|
|
114
|
+
doUpdateExpandedKeys(nextKeys)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function getOptionsByKeys(keys: Key[]): Array<TreeOption | null> {
|
|
119
|
+
const {getNode} = dataTreeMateRef.value;
|
|
120
|
+
return keys.map((key) => getNode(key)?.rawNode || null);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function doUpdateExpandedKeys(
|
|
124
|
+
value: Key[],
|
|
125
|
+
): void {
|
|
126
|
+
uncontrolledExpandedKeysRef.value = value;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
nodesRef,
|
|
131
|
+
displayTreeMateRef,
|
|
132
|
+
selfElRef
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
</script>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
@dblclick="doDoubleClick"
|
|
4
|
+
style="display: flex;"
|
|
5
|
+
>
|
|
6
|
+
<template v-if="indentCount > 0">
|
|
7
|
+
<div v-for="i in indentCount" style="flex-grow: 0; flex-shrink: 0; height: 0;">
|
|
8
|
+
<div :key="i" style="width: 16px;"></div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
<TreeNodeToggle
|
|
12
|
+
:hide="node.isLeaf"
|
|
13
|
+
:node="node"
|
|
14
|
+
:expanded="expanded"
|
|
15
|
+
@click="handleToggleClick"
|
|
16
|
+
/>
|
|
17
|
+
{{ labelField }}
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script lang="ts">
|
|
22
|
+
import {ref, defineComponent, type PropType, inject, computed} from "vue";
|
|
23
|
+
import type {TmNode, TreeOption} from "./types";
|
|
24
|
+
import {treeInjectionKey} from "./types";
|
|
25
|
+
import TreeNodeToggle from "@/components/tree/TreeNodeToggle.vue";
|
|
26
|
+
import type {TreeNode} from "treemate";
|
|
27
|
+
|
|
28
|
+
export default defineComponent({
|
|
29
|
+
name: 'TreeNode',
|
|
30
|
+
components: {TreeNodeToggle},
|
|
31
|
+
props: {
|
|
32
|
+
node: {
|
|
33
|
+
type: Object as PropType<TmNode>,
|
|
34
|
+
required: true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
setup(props) {
|
|
38
|
+
const NTree = inject(treeInjectionKey)!;
|
|
39
|
+
const {
|
|
40
|
+
nodePropsRef,
|
|
41
|
+
labelFieldRef,
|
|
42
|
+
keyFieldRef,
|
|
43
|
+
indentRef,
|
|
44
|
+
handleToggleClick: handleToggleClickTree,
|
|
45
|
+
handleDoubleClick
|
|
46
|
+
} = NTree;
|
|
47
|
+
|
|
48
|
+
const selfElRef = ref<HTMLDivElement | null>(null);
|
|
49
|
+
|
|
50
|
+
function _handleClick(e: MouseEvent): void {
|
|
51
|
+
const {value: expandOnClick} = NTree.expandOnClickRef;
|
|
52
|
+
const {node} = props
|
|
53
|
+
if (!expandOnClick && !node.isLeaf) {
|
|
54
|
+
handleToggleClick();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function handleToggleClick(): void {
|
|
59
|
+
const {node} = props;
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if (!node.isLastChild && !node.shallowLoaded) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
handleToggleClickTree(node)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function doDoubleClick(e: MouseEvent) {
|
|
70
|
+
// get only id and name from node
|
|
71
|
+
let node = props.node;
|
|
72
|
+
let nodeData = {
|
|
73
|
+
[keyFieldRef.value]: node.rawNode[keyFieldRef.value],
|
|
74
|
+
[labelFieldRef.value]: node.rawNode[labelFieldRef.value]
|
|
75
|
+
} as TreeOption;
|
|
76
|
+
handleDoubleClick(nodeData);
|
|
77
|
+
}
|
|
78
|
+
const indentCount = computed(() => {
|
|
79
|
+
return props.node.level;
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
function handleLineClick(e: MouseEvent) {
|
|
83
|
+
_handleClick(e);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const labelField = computed(() => {
|
|
87
|
+
return props.node.rawNode[labelFieldRef.value];
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const expanded = computed(() => NTree.mergedExpandedKeysRef.value.includes(props.node.key));
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
selfElRef,
|
|
94
|
+
handleLineClick,
|
|
95
|
+
indentCount,
|
|
96
|
+
labelField,
|
|
97
|
+
expanded: expanded,
|
|
98
|
+
handleToggleClick,
|
|
99
|
+
doDoubleClick
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
</script>
|