@veritree/ui 0.2.0 → 0.3.0
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/index.js +30 -0
- package/package.json +1 -1
- package/src/Dialog/VTDialog.vue +118 -0
- package/src/Dialog/VTDialogClose.vue +46 -0
- package/src/Dialog/VTDialogContent.vue +72 -0
- package/src/Dialog/VTDialogFooter.vue +30 -0
- package/src/Dialog/VTDialogHeader.vue +56 -0
- package/src/Dialog/VTDialogMain.vue +49 -0
- package/src/Dialog/VTDialogOverlay.vue +52 -0
- package/src/Drawer/VTDrawer.vue +113 -0
- package/src/Drawer/VTDrawerClose.vue +50 -0
- package/src/Drawer/VTDrawerContent.vue +97 -0
- package/src/Drawer/VTDrawerFooter.vue +30 -0
- package/src/Drawer/VTDrawerHeader.vue +56 -0
- package/src/Drawer/VTDrawerMain.vue +53 -0
- package/src/Drawer/VTDrawerOverlay.vue +50 -0
package/index.js
CHANGED
|
@@ -30,6 +30,22 @@ import VTTabList from './src/Tabs/VTTabList.vue';
|
|
|
30
30
|
import VTTabPanel from './src/Tabs/VTTabPanel.vue';
|
|
31
31
|
import VTTabPanels from './src/Tabs/VTTabPanels.vue';
|
|
32
32
|
|
|
33
|
+
import VTDialog from './src/Dialog/VTDialog.vue';
|
|
34
|
+
import VTDialogClose from './src/Dialog/VTDialogClose.vue';
|
|
35
|
+
import VTDialogContent from './src/Dialog/VTDialogContent.vue';
|
|
36
|
+
import VTDialogFooter from './src/Dialog/VTDialogFooter.vue';
|
|
37
|
+
import VTDialogHeader from './src/Dialog/VTDialogHeader.vue';
|
|
38
|
+
import VTDialogMain from './src/Dialog/VTDialogMain.vue';
|
|
39
|
+
import VTDialogOverlay from './src/Dialog/VTDialogOverlay.vue';
|
|
40
|
+
|
|
41
|
+
import VTDrawer from './src/Drawer/VTDrawer.vue';
|
|
42
|
+
import VTDrawerClose from './src/Drawer/VTDrawerClose.vue';
|
|
43
|
+
import VTDrawerContent from './src/Drawer/VTDrawerContent.vue';
|
|
44
|
+
import VTDrawerFooter from './src/Drawer/VTDrawerFooter.vue';
|
|
45
|
+
import VTDrawerHeader from './src/Drawer/VTDrawerHeader.vue';
|
|
46
|
+
import VTDrawerMain from './src/Drawer/VTDrawerMain.vue';
|
|
47
|
+
import VTDrawerOverlay from './src/Drawer/VTDrawerOverlay.vue';
|
|
48
|
+
|
|
33
49
|
export {
|
|
34
50
|
VTAlert,
|
|
35
51
|
// VTSpinner,
|
|
@@ -54,5 +70,19 @@ export {
|
|
|
54
70
|
VTTabList,
|
|
55
71
|
VTTabPanel,
|
|
56
72
|
VTTabPanels,
|
|
73
|
+
VTDrawer,
|
|
74
|
+
VTDrawerClose,
|
|
75
|
+
VTDrawerContent,
|
|
76
|
+
VTDrawerFooter,
|
|
77
|
+
VTDrawerHeader,
|
|
78
|
+
VTDrawerMain,
|
|
79
|
+
VTDrawerOverlay,
|
|
80
|
+
VTDialog,
|
|
81
|
+
VTDialogClose,
|
|
82
|
+
VTDialogContent,
|
|
83
|
+
VTDialogFooter,
|
|
84
|
+
VTDialogHeader,
|
|
85
|
+
VTDialogMain,
|
|
86
|
+
VTDialogOverlay,
|
|
57
87
|
}
|
|
58
88
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
v-if="visible"
|
|
4
|
+
:id="id"
|
|
5
|
+
:class="{
|
|
6
|
+
Dialog: headless,
|
|
7
|
+
'fixed inset-0 z-50 grid grid-cols-1 grid-rows-1 p-4 md:p-8': !headless,
|
|
8
|
+
}"
|
|
9
|
+
aria-modal="true"
|
|
10
|
+
@click="hide"
|
|
11
|
+
>
|
|
12
|
+
<slot></slot>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script>
|
|
17
|
+
import { genId } from '~/utils/ids';
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
name: 'VTDialog',
|
|
21
|
+
|
|
22
|
+
provide() {
|
|
23
|
+
return {
|
|
24
|
+
api: () => {
|
|
25
|
+
const id = this.id;
|
|
26
|
+
const isDark = this.dark;
|
|
27
|
+
const isHeadless = this.headless;
|
|
28
|
+
|
|
29
|
+
const registerContent = (content) => {
|
|
30
|
+
if (!content) return;
|
|
31
|
+
this.content = content;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const registerOverlay = (overlay) => {
|
|
35
|
+
if (!overlay) return;
|
|
36
|
+
this.overlay = overlay;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const hide = () => this.hide();
|
|
40
|
+
|
|
41
|
+
const emit = () => this.emit();
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
id,
|
|
45
|
+
isDark,
|
|
46
|
+
isHeadless,
|
|
47
|
+
hide,
|
|
48
|
+
emit,
|
|
49
|
+
registerContent,
|
|
50
|
+
registerOverlay,
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
model: {
|
|
57
|
+
prop: 'visible',
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
props: {
|
|
61
|
+
visible: {
|
|
62
|
+
type: Boolean,
|
|
63
|
+
default: false,
|
|
64
|
+
},
|
|
65
|
+
headless: {
|
|
66
|
+
type: Boolean,
|
|
67
|
+
default: false,
|
|
68
|
+
},
|
|
69
|
+
dark: {
|
|
70
|
+
type: Boolean,
|
|
71
|
+
default: false,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
data() {
|
|
76
|
+
return {
|
|
77
|
+
id: `dialog-${genId()}`,
|
|
78
|
+
content: null,
|
|
79
|
+
overlay: null,
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
computed: {
|
|
84
|
+
hasContent() {
|
|
85
|
+
return this.content !== null;
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
hasOverlay() {
|
|
89
|
+
return this.overlay !== null;
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
watch: {
|
|
94
|
+
visible(isVisible) {
|
|
95
|
+
if (!isVisible) this.hide();
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
mounted() {
|
|
100
|
+
if (this.hasContent) this.content.show();
|
|
101
|
+
if (this.hasOverlay) this.overlay.show();
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
methods: {
|
|
105
|
+
hide() {
|
|
106
|
+
if (this.hasOverlay) this.overlay.hide();
|
|
107
|
+
if (this.hasContent) this.content.hide();
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
emit() {
|
|
111
|
+
this.$nextTick(() => {
|
|
112
|
+
this.$emit('input', false);
|
|
113
|
+
this.$emit('hidden');
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
</script>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VTButton
|
|
3
|
+
variant="icon"
|
|
4
|
+
:class="{
|
|
5
|
+
'Dialog-close': headless,
|
|
6
|
+
'absolute right-4 top-4': !headless,
|
|
7
|
+
}"
|
|
8
|
+
:theme="theme"
|
|
9
|
+
@click.prevent="hide"
|
|
10
|
+
><slot><IconClose class="h-5 w-5" /></slot
|
|
11
|
+
></VTButton>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
import { IconClose } from '@veritree/icons';
|
|
16
|
+
import VTButton from '~/components/Button/VTButton.vue';
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
name: 'VTDialogClose',
|
|
20
|
+
|
|
21
|
+
components: { IconClose, VTButton },
|
|
22
|
+
|
|
23
|
+
inject: ['api'],
|
|
24
|
+
|
|
25
|
+
computed: {
|
|
26
|
+
dark() {
|
|
27
|
+
return this.api().isDark;
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
headless() {
|
|
31
|
+
return this.api().isHeadless;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
// temporary till button theme is implemented
|
|
35
|
+
theme() {
|
|
36
|
+
return this.dark ? 'dark' : null;
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
methods: {
|
|
41
|
+
hide() {
|
|
42
|
+
this.api().hide();
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
</script>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<transition
|
|
3
|
+
enter-active-class="duration-300 ease-out"
|
|
4
|
+
enter-class="translate-y-[50px] opacity-0"
|
|
5
|
+
enter-to-class="translate-y-0 opacity-100"
|
|
6
|
+
leave-active-class="duration-300 ease-out"
|
|
7
|
+
leave-class="translate-y-0 opacity-100"
|
|
8
|
+
leave-to-class="translate-y-[50px] opacity-0"
|
|
9
|
+
@after-leave="hideDialog"
|
|
10
|
+
>
|
|
11
|
+
<div
|
|
12
|
+
v-show="visible"
|
|
13
|
+
:class="{
|
|
14
|
+
'Dialog-content': headless,
|
|
15
|
+
'relative m-auto max-h-full max-w-full overflow-auto rounded p-6 focus:outline-none sm:p-10':
|
|
16
|
+
!headless,
|
|
17
|
+
'bg-white': !dark,
|
|
18
|
+
'bg-fd-600': dark,
|
|
19
|
+
}"
|
|
20
|
+
tabindex="-1"
|
|
21
|
+
@keyup.esc="hide"
|
|
22
|
+
@click.stop
|
|
23
|
+
>
|
|
24
|
+
<slot></slot>
|
|
25
|
+
</div>
|
|
26
|
+
</transition>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script>
|
|
30
|
+
export default {
|
|
31
|
+
name: 'VTDialogContent',
|
|
32
|
+
|
|
33
|
+
inject: ['api'],
|
|
34
|
+
|
|
35
|
+
data() {
|
|
36
|
+
return {
|
|
37
|
+
visible: false,
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
computed: {
|
|
42
|
+
dark() {
|
|
43
|
+
return this.api().isDark;
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
headless() {
|
|
47
|
+
return this.api().isHeadless;
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
mounted() {
|
|
52
|
+
this.api().registerContent(this);
|
|
53
|
+
this.show();
|
|
54
|
+
|
|
55
|
+
this.$nextTick(() => this.$el.focus());
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
methods: {
|
|
59
|
+
show() {
|
|
60
|
+
this.visible = true;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
hide() {
|
|
64
|
+
this.visible = false;
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
hideDialog() {
|
|
68
|
+
this.api().emit();
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
</script>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component :is="as" :class="{ 'Dialog-footer': headless }">
|
|
3
|
+
<slot></slot>
|
|
4
|
+
</component>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
name: 'VTDialogFooter',
|
|
10
|
+
|
|
11
|
+
inject: ['api'],
|
|
12
|
+
|
|
13
|
+
props: {
|
|
14
|
+
as: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: 'footer',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
computed: {
|
|
21
|
+
dark() {
|
|
22
|
+
return this.api().isDark;
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
headless() {
|
|
26
|
+
return this.api().isHeadless;
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
</script>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="as"
|
|
4
|
+
:id="id"
|
|
5
|
+
:class="{
|
|
6
|
+
'Dialog-header': headless,
|
|
7
|
+
'mb-8 text-2xl font-semibold': !headless,
|
|
8
|
+
}"
|
|
9
|
+
>
|
|
10
|
+
<slot></slot>
|
|
11
|
+
</component>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
export default {
|
|
16
|
+
name: 'VTDialogHeader',
|
|
17
|
+
|
|
18
|
+
inject: ['api'],
|
|
19
|
+
|
|
20
|
+
props: {
|
|
21
|
+
as: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: 'header',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
computed: {
|
|
28
|
+
dark() {
|
|
29
|
+
return this.api().isDark;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
headless() {
|
|
33
|
+
return this.api().isHeadless;
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
id() {
|
|
37
|
+
return `${this.api().id}-header`;
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
mounted() {
|
|
42
|
+
this.setDialogLabelledby();
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
methods: {
|
|
46
|
+
// In here because if there is no header, the dialog will not be labelled by
|
|
47
|
+
setDialogLabelledby() {
|
|
48
|
+
const dialog = document.getElementById(this.api().id);
|
|
49
|
+
|
|
50
|
+
if (dialog) {
|
|
51
|
+
dialog.setAttribute('aria-labelledby', this.id);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
</script>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component :is="as" :id="id" :class="{ 'Dialog-body': headless }">
|
|
3
|
+
<slot></slot>
|
|
4
|
+
</component>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
name: 'VTDialogMain',
|
|
10
|
+
|
|
11
|
+
inject: ['api'],
|
|
12
|
+
|
|
13
|
+
props: {
|
|
14
|
+
as: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: 'main',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
computed: {
|
|
21
|
+
dark() {
|
|
22
|
+
return this.api().isDark;
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
headless() {
|
|
26
|
+
return this.api().isHeadless;
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
id() {
|
|
30
|
+
return `${this.api().id}-desc`;
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
mounted() {
|
|
35
|
+
this.setDialogDescribedby();
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
methods: {
|
|
39
|
+
// In here because if there is no body, the dialog will not be described by
|
|
40
|
+
setDialogDescribedby() {
|
|
41
|
+
const dialog = document.getElementById(this.api().id);
|
|
42
|
+
|
|
43
|
+
if (dialog) {
|
|
44
|
+
dialog.setAttribute('aria-describedby', this.id);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
</script>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FadeInOut>
|
|
3
|
+
<div
|
|
4
|
+
v-if="visible"
|
|
5
|
+
:class="{
|
|
6
|
+
'Dialog-overlay': headless,
|
|
7
|
+
'fixed inset-0 bg-fd-450/80': !headless,
|
|
8
|
+
}"
|
|
9
|
+
></div>
|
|
10
|
+
</FadeInOut>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import FadeInOut from '~/components/Transitions/FadeInOut.vue';
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
name: 'VTDialogOverlay',
|
|
18
|
+
|
|
19
|
+
components: {
|
|
20
|
+
FadeInOut,
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
inject: ['api'],
|
|
24
|
+
|
|
25
|
+
data() {
|
|
26
|
+
return {
|
|
27
|
+
visible: false,
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
computed: {
|
|
32
|
+
dark() {
|
|
33
|
+
return this.api().isDark;
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
headless() {
|
|
37
|
+
return this.api().isHeadless;
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
mounted() {
|
|
42
|
+
this.visible = true;
|
|
43
|
+
this.api().registerOverlay(this);
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
methods: {
|
|
47
|
+
hide() {
|
|
48
|
+
this.visible = false;
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
</script>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
v-if="visible"
|
|
4
|
+
:id="id"
|
|
5
|
+
:class="{ Drawer: headless, 'fixed inset-0 z-50 h-screen': !headless }"
|
|
6
|
+
aria-modal="true"
|
|
7
|
+
@click="hide"
|
|
8
|
+
>
|
|
9
|
+
<slot></slot>
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import { genId } from '~/utils/ids';
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
name: 'VTDrawer',
|
|
18
|
+
|
|
19
|
+
provide() {
|
|
20
|
+
return {
|
|
21
|
+
api: () => {
|
|
22
|
+
const id = this.id;
|
|
23
|
+
const isDark = this.dark;
|
|
24
|
+
const isHeadless = this.headless;
|
|
25
|
+
const isRight = this.right;
|
|
26
|
+
|
|
27
|
+
const registerContent = (content) => {
|
|
28
|
+
if (!content) return;
|
|
29
|
+
this.content = content;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const registerOverlay = (overlay) => {
|
|
33
|
+
if (!overlay) return;
|
|
34
|
+
this.overlay = overlay;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const hide = () => this.hide();
|
|
38
|
+
|
|
39
|
+
const emit = () => this.emit();
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
id,
|
|
43
|
+
isDark,
|
|
44
|
+
isHeadless,
|
|
45
|
+
isRight,
|
|
46
|
+
hide,
|
|
47
|
+
emit,
|
|
48
|
+
registerContent,
|
|
49
|
+
registerOverlay,
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
model: {
|
|
56
|
+
prop: 'visible',
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
props: {
|
|
60
|
+
visible: {
|
|
61
|
+
type: Boolean,
|
|
62
|
+
default: false,
|
|
63
|
+
},
|
|
64
|
+
headless: {
|
|
65
|
+
type: Boolean,
|
|
66
|
+
default: false,
|
|
67
|
+
},
|
|
68
|
+
dark: {
|
|
69
|
+
type: Boolean,
|
|
70
|
+
default: false,
|
|
71
|
+
},
|
|
72
|
+
right: {
|
|
73
|
+
type: Boolean,
|
|
74
|
+
default: false,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
data() {
|
|
79
|
+
return {
|
|
80
|
+
id: `drawer-${genId()}`,
|
|
81
|
+
content: null,
|
|
82
|
+
overlay: null,
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
watch: {
|
|
87
|
+
visible(isVisible) {
|
|
88
|
+
if (!isVisible) this.hide();
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
mounted() {
|
|
93
|
+
if (!this.content) return;
|
|
94
|
+
this.content.show();
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
methods: {
|
|
98
|
+
hide() {
|
|
99
|
+
if (!this.content) return;
|
|
100
|
+
this.content.hide();
|
|
101
|
+
if (!this.overlay) return;
|
|
102
|
+
this.overlay.hide();
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
emit() {
|
|
106
|
+
this.$nextTick(() => {
|
|
107
|
+
this.$emit('input', false);
|
|
108
|
+
this.$emit('hidden');
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
</script>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VTButton
|
|
3
|
+
variant="icon"
|
|
4
|
+
:class="{
|
|
5
|
+
'Drawer-close': headless,
|
|
6
|
+
'ml-auto mb-4 text-inherit sm:mb-8': !headless,
|
|
7
|
+
}"
|
|
8
|
+
:theme="theme"
|
|
9
|
+
@click.prevent="hide"
|
|
10
|
+
><slot><IconLeft :class="{ 'rotate-180': right }" /></slot
|
|
11
|
+
></VTButton>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
import { IconLeft } from '@veritree/icons';
|
|
16
|
+
import VTButton from '~/components/Button/VTButton.vue';
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
name: 'VTDrawerClose',
|
|
20
|
+
|
|
21
|
+
components: { IconLeft, VTButton },
|
|
22
|
+
|
|
23
|
+
inject: ['api'],
|
|
24
|
+
|
|
25
|
+
computed: {
|
|
26
|
+
dark() {
|
|
27
|
+
return this.api().isDark;
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
headless() {
|
|
31
|
+
return this.api().isHeadless;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
right() {
|
|
35
|
+
return this.api().isRight;
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
// temporary till button theme is implemented
|
|
39
|
+
theme() {
|
|
40
|
+
return this.dark ? 'dark' : null;
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
methods: {
|
|
45
|
+
hide() {
|
|
46
|
+
this.api().hide();
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
</script>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<transition
|
|
3
|
+
:enter-active-class="activeClass"
|
|
4
|
+
:enter-class="enterClass"
|
|
5
|
+
:enter-to-class="enterToClass"
|
|
6
|
+
:leave-active-class="activeClass"
|
|
7
|
+
:leave-class="leaveClass"
|
|
8
|
+
:leave-to-class="leaveToClass"
|
|
9
|
+
@after-leave="hideDrawer"
|
|
10
|
+
>
|
|
11
|
+
<div
|
|
12
|
+
v-show="visible"
|
|
13
|
+
:class="{
|
|
14
|
+
'Drawer-content': headless,
|
|
15
|
+
'absolute z-20 flex h-screen max-h-full max-w-full flex-col overflow-auto p-5 outline-0 sm:px-10 sm:py-6':
|
|
16
|
+
!headless,
|
|
17
|
+
'bg-white': !dark,
|
|
18
|
+
'bg-fd-600': dark,
|
|
19
|
+
'right-0': right,
|
|
20
|
+
}"
|
|
21
|
+
tabindex="-1"
|
|
22
|
+
@keyup.esc="hide"
|
|
23
|
+
@click.stop
|
|
24
|
+
>
|
|
25
|
+
<slot></slot>
|
|
26
|
+
</div>
|
|
27
|
+
</transition>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<script>
|
|
31
|
+
export default {
|
|
32
|
+
name: 'VTDrawerContent',
|
|
33
|
+
|
|
34
|
+
inject: ['api'],
|
|
35
|
+
|
|
36
|
+
data() {
|
|
37
|
+
return {
|
|
38
|
+
visible: false,
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
computed: {
|
|
43
|
+
dark() {
|
|
44
|
+
return this.api().isDark;
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
headless() {
|
|
48
|
+
return this.api().isHeadless;
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
right() {
|
|
52
|
+
return this.api().isRight;
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
activeClass() {
|
|
56
|
+
return 'transform transition duration-300 ease-in-out';
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
enterClass() {
|
|
60
|
+
return `opacity-0 ${this.right ? '' : '-'}translate-x-full`;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
enterToClass() {
|
|
64
|
+
return `opacity-100 ${this.right ? '-' : ''}translate-x-0`;
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
leaveClass() {
|
|
68
|
+
return `opacity-100 ${this.right ? '-' : ''}translate-x-0`;
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
leaveToClass() {
|
|
72
|
+
return `opacity-0 ${this.right ? '' : '-'}translate-x-full`;
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
mounted() {
|
|
77
|
+
this.api().registerContent(this);
|
|
78
|
+
this.show();
|
|
79
|
+
|
|
80
|
+
this.$nextTick(() => this.$el.focus());
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
methods: {
|
|
84
|
+
show() {
|
|
85
|
+
this.visible = true;
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
hide() {
|
|
89
|
+
this.visible = false;
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
hideDrawer() {
|
|
93
|
+
this.api().emit();
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
</script>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component :is="as" :class="{ 'Dialog-footer': headless }">
|
|
3
|
+
<slot></slot>
|
|
4
|
+
</component>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
name: 'VTDrawerFooter',
|
|
10
|
+
|
|
11
|
+
inject: ['api'],
|
|
12
|
+
|
|
13
|
+
props: {
|
|
14
|
+
as: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: 'footer',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
computed: {
|
|
21
|
+
dark() {
|
|
22
|
+
return this.api().isDark;
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
headless() {
|
|
26
|
+
return this.api().isHeadless;
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
</script>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="as"
|
|
4
|
+
:id="id"
|
|
5
|
+
:class="{
|
|
6
|
+
'Drawer-header': headless,
|
|
7
|
+
'mb-8 text-2xl font-semibold': !headless,
|
|
8
|
+
}"
|
|
9
|
+
>
|
|
10
|
+
<slot></slot>
|
|
11
|
+
</component>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
export default {
|
|
16
|
+
name: 'VTDrawerHeader',
|
|
17
|
+
|
|
18
|
+
inject: ['api'],
|
|
19
|
+
|
|
20
|
+
props: {
|
|
21
|
+
as: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: 'header',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
computed: {
|
|
28
|
+
dark() {
|
|
29
|
+
return this.api().isDark;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
headless() {
|
|
33
|
+
return this.api().isHeadless;
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
id() {
|
|
37
|
+
return `${this.api().id}-header`;
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
mounted() {
|
|
42
|
+
this.setDialogLabelledby();
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
methods: {
|
|
46
|
+
// In here because if there is no header, the dialog will not be labelled by
|
|
47
|
+
setDialogLabelledby() {
|
|
48
|
+
const dialog = document.getElementById(this.api().id);
|
|
49
|
+
|
|
50
|
+
if (dialog) {
|
|
51
|
+
dialog.setAttribute('aria-labelledby', this.id);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
</script>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="as"
|
|
4
|
+
:id="id"
|
|
5
|
+
:class="{ 'Drawer-body': headless, 'flex-1': !headless }"
|
|
6
|
+
>
|
|
7
|
+
<slot></slot>
|
|
8
|
+
</component>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
export default {
|
|
13
|
+
name: 'VTDrawerMain',
|
|
14
|
+
|
|
15
|
+
inject: ['api'],
|
|
16
|
+
|
|
17
|
+
props: {
|
|
18
|
+
as: {
|
|
19
|
+
type: String,
|
|
20
|
+
default: 'main',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
computed: {
|
|
25
|
+
dark() {
|
|
26
|
+
return this.api().isDark;
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
headless() {
|
|
30
|
+
return this.api().isHeadless;
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
id() {
|
|
34
|
+
return `${this.api().id}-desc`;
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
mounted() {
|
|
39
|
+
this.setDialogDescribedby();
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
methods: {
|
|
43
|
+
// In here because if there is no body, the dialog will not be described by
|
|
44
|
+
setDialogDescribedby() {
|
|
45
|
+
const dialog = document.getElementById(this.api().id);
|
|
46
|
+
|
|
47
|
+
if (dialog) {
|
|
48
|
+
dialog.setAttribute('aria-describedby', this.id);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
</script>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FadeInOut>
|
|
3
|
+
<div
|
|
4
|
+
v-if="visible"
|
|
5
|
+
:class="{
|
|
6
|
+
'Drawer-overlay': headless,
|
|
7
|
+
'fixed inset-0 z-10 bg-fd-450/80': !headless,
|
|
8
|
+
}"
|
|
9
|
+
></div>
|
|
10
|
+
</FadeInOut>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import FadeInOut from '~/components/Transitions/FadeInOut.vue';
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
components: {
|
|
18
|
+
FadeInOut,
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
inject: ['api'],
|
|
22
|
+
|
|
23
|
+
data() {
|
|
24
|
+
return {
|
|
25
|
+
visible: false,
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
computed: {
|
|
30
|
+
dark() {
|
|
31
|
+
return this.api().isDark;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
headless() {
|
|
35
|
+
return this.api().isHeadless;
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
mounted() {
|
|
40
|
+
this.visible = true;
|
|
41
|
+
this.api().registerOverlay(this);
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
methods: {
|
|
45
|
+
hide() {
|
|
46
|
+
this.visible = false;
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
</script>
|