@teammodlr/ui-kit 2.3.22 → 3.0.0-beta.2
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/components/avatar/Avatar.vue.d.ts +2 -2
- package/lib/components/badge/style/Badge.css.d.ts +2 -2
- package/lib/components/button/Button.vue.d.ts +7 -4
- package/lib/components/button/style/Button.css.d.ts +3 -3
- package/lib/components/cardcontextmenu/CardContextMenu.vue.d.ts +5 -8
- package/lib/components/cardcontextmenu/CardContextMenuItem.vue.d.ts +11 -2
- package/lib/components/cardcontextmenu/CardContextMenuTriggerProvider.vue.d.ts +2 -0
- package/lib/components/cardcontextmenu/style/Dropdown.css.d.ts +2 -1
- package/lib/components/cardcontextmenu/symbol.d.ts +1 -0
- package/lib/components/checkbox/Checkbox.vue.d.ts +15 -4
- package/lib/components/collapse/CollapseItem.vue.d.ts +3 -2
- package/lib/components/colorpicker/ColorPicker.vue.d.ts +8 -9
- package/lib/components/confirm/Confirm.vue.d.ts +9 -0
- package/lib/components/confirm/props.d.ts +4 -0
- package/lib/components/dialog/Dialog.vue.d.ts +9 -4
- package/lib/components/dialogprovider/DialogProvider.vue.d.ts +1 -0
- package/lib/components/dialogprovider/types.d.ts +1 -0
- package/lib/components/dropdown/Dropdown.vue.d.ts +3 -1
- package/lib/components/dropdown/DropdownItem.vue.d.ts +11 -1
- package/lib/components/dropdown/DropdownSeperator.vue.d.ts +1 -0
- package/lib/components/dropdown/DropdownTriggerProvider.vue.d.ts +2 -0
- package/lib/components/dropdown/style/Dropdown.css.d.ts +2 -1
- package/lib/components/dropdown/symbol.d.ts +2 -0
- package/lib/components/image/Image.vue.d.ts +1 -1
- package/lib/components/messageprovider/Message.vue.d.ts +1 -1
- package/lib/components/messageprovider/MessageProvider.vue.d.ts +22 -24
- package/lib/components/messageprovider/style/Message.css.d.ts +1 -1
- package/lib/components/messageprovider/types.d.ts +5 -0
- package/lib/components/modal/Modal.vue.d.ts +18 -6
- package/lib/components/radio/Radio.vue.d.ts +2 -0
- package/lib/components/radiobuttongroup/RadioButtonGroup.vue.d.ts +1 -0
- package/lib/components/select/Select.vue.d.ts +23 -11
- package/lib/components/select/style/Select.css.d.ts +2 -0
- package/lib/components/switch/Switch.vue.d.ts +2 -0
- package/lib/components/tab/Tab.vue.d.ts +5 -2
- package/lib/components/tab/TabGroup.vue.d.ts +8 -3
- package/lib/components/textarea/Textarea.vue.d.ts +2 -1
- package/lib/components/tooltip/Tooltip.vue.d.ts +5 -20
- package/lib/components/tooltip/TooltipTrigger.vue.d.ts +1 -10
- package/lib/components/tree/Tree.vue.d.ts +3 -3
- package/lib/components/tree/TreeNode.vue.d.ts +26 -12
- package/lib/components/tree/types.d.ts +5 -5
- package/lib/index.cjs.js +5 -14
- package/lib/index.es.js +14765 -10217
- package/lib/style.css +1 -1
- package/package.json +12 -6
- package/src/components/avatar/Avatar.vue +32 -24
- package/src/components/button/Button.vue +24 -5
- package/src/components/cardcontextmenu/CardContextMenu.vue +68 -95
- package/src/components/cardcontextmenu/CardContextMenuItem.vue +40 -50
- package/src/components/cardcontextmenu/CardContextMenuSeperator.vue +9 -7
- package/src/components/cardcontextmenu/CardContextMenuTriggerProvider.vue +15 -0
- package/src/components/cardcontextmenu/style/Dropdown.css.ts +155 -2
- package/src/components/cardcontextmenu/symbol.ts +3 -0
- package/src/components/checkbox/Checkbox.vue +37 -12
- package/src/components/checkbox/style/Checkbox.css.ts +6 -6
- package/src/components/collapse/CollapseItem.vue +46 -21
- package/src/components/collapse/style/Collapse.css.ts +5 -1
- package/src/components/colorpicker/ColorPicker.vue +76 -45
- package/src/components/confirm/Confirm.vue +15 -8
- package/src/components/confirm/props.ts +4 -0
- package/src/components/dialog/Dialog.vue +169 -36
- package/src/components/dialogprovider/types.ts +1 -0
- package/src/components/dropdown/Dropdown.vue +46 -3
- package/src/components/dropdown/DropdownItem.vue +55 -25
- package/src/components/dropdown/DropdownSeperator.vue +19 -11
- package/src/components/dropdown/DropdownTriggerProvider.vue +15 -0
- package/src/components/dropdown/examples/context.vue +2 -2
- package/src/components/dropdown/style/Dropdown.css.ts +157 -4
- package/src/components/dropdown/symbol.ts +4 -0
- package/src/components/form/examples/basic.vue +19 -8
- package/src/components/messageprovider/MessageProvider.vue +136 -90
- package/src/components/messageprovider/examples/basic.vue +3 -1
- package/src/components/messageprovider/examples/index.stories.ts +37 -1
- package/src/components/messageprovider/types.ts +10 -0
- package/src/components/modal/Modal.vue +142 -67
- package/src/components/radio/Radio.vue +31 -17
- package/src/components/radiobutton/RadioButton.vue +15 -2
- package/src/components/radiobuttongroup/RadioButtonGroup.vue +11 -4
- package/src/components/select/Select.vue +309 -148
- package/src/components/select/examples/basic.vue +1 -1
- package/src/components/select/style/Select.css.ts +15 -0
- package/src/components/slider/Slider.vue +1 -1
- package/src/components/switch/Switch.vue +30 -10
- package/src/components/switch/style/Switch.css.ts +3 -5
- package/src/components/tab/Tab.vue +29 -20
- package/src/components/tab/TabGroup.vue +29 -38
- package/src/components/textarea/Textarea.vue +8 -4
- package/src/components/tooltip/Tooltip.vue +52 -141
- package/src/components/tooltip/TooltipTrigger.vue +14 -17
- package/src/components/tooltip/style/Tooltip.css.ts +148 -29
- package/src/components/tree/Tree.vue +138 -100
- package/src/components/tree/TreeNode.vue +105 -98
- package/src/components/tree/types.ts +4 -4
- package/src/styles/transitions.css.ts +36 -16
|
@@ -1,25 +1,40 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
:enter-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
<DialogRoot :open="isOpen" :modal="modal" @update:open="handleOpenChange">
|
|
3
|
+
<DialogPortal to="body">
|
|
4
|
+
<Transition type="animation" :enter-active-class="fade.enterActive" :leave-active-class="fade.leaveActive"
|
|
5
|
+
:enter-from-class="fade.enterFrom" :leave-to-class="fade.leaveTo">
|
|
6
|
+
<DialogOverlay v-if="isOpen && modal" force-mount :class="backdropClasses" style="z-index: 10" />
|
|
7
|
+
</Transition>
|
|
8
|
+
<Transition type="animation" :enter-active-class="modalScale.enterActive" :leave-active-class="modalScale.leaveActive"
|
|
9
|
+
:enter-from-class="modalScale.enterFrom" :leave-to-class="modalScale.leaveTo">
|
|
10
|
+
|
|
11
|
+
<DialogContent
|
|
12
|
+
v-if="isOpen"
|
|
13
|
+
ref="dialog"
|
|
14
|
+
force-mount
|
|
15
|
+
:style="computedStyle"
|
|
16
|
+
:disable-outside-pointer-events="modal"
|
|
17
|
+
@open-auto-focus="handleOpenAutoFocus"
|
|
18
|
+
@escape-key-down.prevent
|
|
19
|
+
@pointer-down-outside.prevent
|
|
20
|
+
@focus-outside="handleFocusOutside"
|
|
21
|
+
@interact-outside.prevent
|
|
22
|
+
>
|
|
23
|
+
<FocusScope :trapped="focusTrap" :loop="focusTrap">
|
|
13
24
|
<slot v-if="$slots.container" name="container" :close="close"></slot>
|
|
14
25
|
<template v-else>
|
|
15
26
|
<div :class="style.content">
|
|
16
|
-
<
|
|
27
|
+
<DialogClose as-child>
|
|
28
|
+
<button ref="closeButton" role="button" :class="style.close"></button>
|
|
29
|
+
</DialogClose>
|
|
17
30
|
<div :class="headerClasses" ref="handle">
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
<DialogTitle as-child>
|
|
32
|
+
<div :class="style.title">
|
|
33
|
+
<slot name="title">
|
|
34
|
+
{{ resolvedTitle }}
|
|
35
|
+
</slot>
|
|
36
|
+
</div>
|
|
37
|
+
</DialogTitle>
|
|
23
38
|
</div>
|
|
24
39
|
<div>
|
|
25
40
|
<slot></slot>
|
|
@@ -29,35 +44,53 @@
|
|
|
29
44
|
</div>
|
|
30
45
|
</div>
|
|
31
46
|
</template>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
</div>
|
|
38
|
-
</Transition>
|
|
39
|
-
</Teleport>
|
|
47
|
+
</FocusScope>
|
|
48
|
+
</DialogContent>
|
|
49
|
+
</Transition>
|
|
50
|
+
</DialogPortal>
|
|
51
|
+
</DialogRoot>
|
|
40
52
|
</template>
|
|
41
53
|
<script lang="ts">
|
|
42
54
|
import { fade, modalScale } from '../../styles/transitions.css';
|
|
55
|
+
import {
|
|
56
|
+
DialogClose,
|
|
57
|
+
DialogContent,
|
|
58
|
+
DialogOverlay,
|
|
59
|
+
DialogPortal,
|
|
60
|
+
DialogRoot,
|
|
61
|
+
DialogTitle,
|
|
62
|
+
FocusScope,
|
|
63
|
+
} from 'reka-ui';
|
|
43
64
|
import {
|
|
44
65
|
computed,
|
|
45
66
|
defineComponent,
|
|
67
|
+
provide,
|
|
46
68
|
ref,
|
|
69
|
+
shallowRef,
|
|
47
70
|
watch,
|
|
48
71
|
nextTick,
|
|
49
72
|
isRef,
|
|
50
73
|
type CSSProperties,
|
|
74
|
+
type ComponentPublicInstance,
|
|
51
75
|
type PropType,
|
|
52
76
|
type Ref,
|
|
53
77
|
} from 'vue';
|
|
54
78
|
import type { ComputedRef } from 'vue';
|
|
55
|
-
import { useZIndex } from '../../composables/useZIndex';
|
|
79
|
+
import { useZIndex, ZINDEX } from '../../composables/useZIndex';
|
|
56
80
|
import { useDraggable, useEventListener } from '@vueuse/core';
|
|
57
81
|
import * as style from './style';
|
|
58
82
|
|
|
59
83
|
export default defineComponent({
|
|
60
84
|
name: 'Dialog',
|
|
85
|
+
components: {
|
|
86
|
+
DialogClose,
|
|
87
|
+
DialogContent,
|
|
88
|
+
DialogOverlay,
|
|
89
|
+
DialogPortal,
|
|
90
|
+
DialogRoot,
|
|
91
|
+
DialogTitle,
|
|
92
|
+
FocusScope,
|
|
93
|
+
},
|
|
61
94
|
props: {
|
|
62
95
|
title: {
|
|
63
96
|
type: [String, Object] as PropType<string | Ref<string>>,
|
|
@@ -95,14 +128,37 @@ export default defineComponent({
|
|
|
95
128
|
emits: ['onOpen', 'onClose', 'update:open', 'open'],
|
|
96
129
|
setup(props, { emit, expose }) {
|
|
97
130
|
const wrapper = ref<HTMLElement | null>(null);
|
|
98
|
-
const dialog =
|
|
131
|
+
const dialog = shallowRef<HTMLElement | ComponentPublicInstance | null>(null);
|
|
99
132
|
const handle = ref<HTMLElement | null>(null);
|
|
133
|
+
const closeButton = ref<HTMLElement | null>(null);
|
|
100
134
|
const { nextZIndex, current: maxZIndex } = useZIndex();
|
|
101
135
|
const zIndex = ref(props.zIndex ?? nextZIndex());
|
|
136
|
+
provide(ZINDEX, zIndex);
|
|
137
|
+
const hasOpened = ref(false);
|
|
102
138
|
|
|
103
139
|
const isDragging = ref<boolean>(false);
|
|
104
140
|
|
|
105
|
-
|
|
141
|
+
function resolveElement(
|
|
142
|
+
value: HTMLElement | ComponentPublicInstance | null | undefined
|
|
143
|
+
): HTMLElement | null {
|
|
144
|
+
if (!value) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (value instanceof HTMLElement) {
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if ('$el' in value && value.$el instanceof HTMLElement) {
|
|
153
|
+
return value.$el;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const dialogElement = computed(() => resolveElement(dialog.value));
|
|
160
|
+
|
|
161
|
+
const { x, y } = useDraggable(dialogElement, {
|
|
106
162
|
handle,
|
|
107
163
|
preventDefault: true,
|
|
108
164
|
containerElement: wrapper,
|
|
@@ -115,6 +171,17 @@ export default defineComponent({
|
|
|
115
171
|
isRef(props.title) ? props.title.value : props.title
|
|
116
172
|
);
|
|
117
173
|
|
|
174
|
+
const focusableSelector = [
|
|
175
|
+
'[autofocus]',
|
|
176
|
+
'input:not([type="hidden"])',
|
|
177
|
+
'textarea',
|
|
178
|
+
'select',
|
|
179
|
+
'[contenteditable="true"]',
|
|
180
|
+
'button',
|
|
181
|
+
'a[href]',
|
|
182
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
183
|
+
].join(', ');
|
|
184
|
+
|
|
118
185
|
const backdropClasses = computed(() => ({
|
|
119
186
|
[style.backdrop]: true,
|
|
120
187
|
[style.backdropColor]: props.modal === true,
|
|
@@ -131,6 +198,13 @@ export default defineComponent({
|
|
|
131
198
|
[style.notModal]: !props.modal,
|
|
132
199
|
}));
|
|
133
200
|
|
|
201
|
+
const wrapperStyle: ComputedRef<CSSProperties> = computed(() => ({
|
|
202
|
+
zIndex: zIndex.value,
|
|
203
|
+
position: 'fixed',
|
|
204
|
+
inset: '0',
|
|
205
|
+
pointerEvents: props.modal ? 'all' : 'none'
|
|
206
|
+
}));
|
|
207
|
+
|
|
134
208
|
const width = computed(() =>
|
|
135
209
|
typeof props.width === 'number' ? `${props.width}px` : props.width
|
|
136
210
|
);
|
|
@@ -144,8 +218,7 @@ export default defineComponent({
|
|
|
144
218
|
}));
|
|
145
219
|
|
|
146
220
|
function close() {
|
|
147
|
-
|
|
148
|
-
onCloseEmit();
|
|
221
|
+
handleOpenChange(false);
|
|
149
222
|
}
|
|
150
223
|
|
|
151
224
|
function onCloseEmit() {
|
|
@@ -157,9 +230,54 @@ export default defineComponent({
|
|
|
157
230
|
|
|
158
231
|
function onEnter() {
|
|
159
232
|
emit('onOpen');
|
|
233
|
+
emit('open');
|
|
160
234
|
zIndex.value = nextZIndex();
|
|
161
235
|
}
|
|
162
236
|
|
|
237
|
+
function handleFocusOutside(event: Event) {
|
|
238
|
+
if (!props.focusTrap) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
event.preventDefault();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function handleOpenAutoFocus(event: Event) {
|
|
246
|
+
const element = dialogElement.value;
|
|
247
|
+
|
|
248
|
+
if (!element) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const firstFocusableElement = Array.from(
|
|
253
|
+
element.querySelectorAll<HTMLElement>(focusableSelector)
|
|
254
|
+
).find(candidate => {
|
|
255
|
+
return candidate !== closeButton.value
|
|
256
|
+
&& !candidate.matches(':disabled')
|
|
257
|
+
&& candidate.getAttribute('aria-disabled') !== 'true'
|
|
258
|
+
&& candidate.getAttribute('aria-hidden') !== 'true'
|
|
259
|
+
&& candidate.getClientRects().length > 0;
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
if (!firstFocusableElement) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
event.preventDefault();
|
|
267
|
+
firstFocusableElement.focus();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function handleOpenChange(value: boolean) {
|
|
271
|
+
if (!value && props.open) {
|
|
272
|
+
emit('update:open', false);
|
|
273
|
+
onCloseEmit();
|
|
274
|
+
hasOpened.value = false;
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
emit('update:open', value);
|
|
279
|
+
}
|
|
280
|
+
|
|
163
281
|
function onDragStart() {
|
|
164
282
|
if (zIndex.value < maxZIndex.value) {
|
|
165
283
|
zIndex.value = nextZIndex();
|
|
@@ -172,16 +290,20 @@ export default defineComponent({
|
|
|
172
290
|
}
|
|
173
291
|
|
|
174
292
|
function centerDialog() {
|
|
175
|
-
|
|
176
|
-
|
|
293
|
+
const element = dialogElement.value;
|
|
294
|
+
|
|
295
|
+
if (element) {
|
|
296
|
+
const boundingRect = element.getBoundingClientRect();
|
|
177
297
|
x.value = (window.innerWidth - boundingRect.width) / 2;
|
|
178
298
|
y.value = (window.innerHeight - boundingRect.height) / 2;
|
|
179
299
|
}
|
|
180
300
|
}
|
|
181
301
|
|
|
182
302
|
function keepWithInBounds() {
|
|
183
|
-
|
|
184
|
-
|
|
303
|
+
const element = dialogElement.value;
|
|
304
|
+
|
|
305
|
+
if (element) {
|
|
306
|
+
const boundingRect = element.getBoundingClientRect();
|
|
185
307
|
const maxX = window.innerWidth - boundingRect.width;
|
|
186
308
|
const maxY = window.innerHeight - boundingRect.height;
|
|
187
309
|
|
|
@@ -206,7 +328,13 @@ export default defineComponent({
|
|
|
206
328
|
if (newVal) {
|
|
207
329
|
await nextTick();
|
|
208
330
|
centerDialog();
|
|
209
|
-
|
|
331
|
+
zIndex.value = props.zIndex ?? nextZIndex();
|
|
332
|
+
if (!hasOpened.value) {
|
|
333
|
+
onEnter();
|
|
334
|
+
hasOpened.value = true;
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
hasOpened.value = false;
|
|
210
338
|
}
|
|
211
339
|
},
|
|
212
340
|
{ immediate: true }
|
|
@@ -220,6 +348,7 @@ export default defineComponent({
|
|
|
220
348
|
wrapper,
|
|
221
349
|
dialog,
|
|
222
350
|
handle,
|
|
351
|
+
closeButton,
|
|
223
352
|
zIndex,
|
|
224
353
|
fade,
|
|
225
354
|
modalScale,
|
|
@@ -229,9 +358,13 @@ export default defineComponent({
|
|
|
229
358
|
backdropClasses,
|
|
230
359
|
resolvedTitle,
|
|
231
360
|
wrapperClasses,
|
|
361
|
+
wrapperStyle,
|
|
232
362
|
close,
|
|
233
363
|
onEnter,
|
|
234
|
-
|
|
364
|
+
handleOpenChange,
|
|
365
|
+
handleOpenAutoFocus,
|
|
366
|
+
handleFocusOutside,
|
|
367
|
+
isOpen: computed(() => props.open)
|
|
235
368
|
};
|
|
236
369
|
},
|
|
237
370
|
});
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<ContextMenuSub v-model:open="isOpen" v-if="isContextMenu && isSubmenu">
|
|
3
|
+
<DropdownTriggerProvider>
|
|
4
|
+
<slot />
|
|
5
|
+
</DropdownTriggerProvider>
|
|
6
|
+
<ContextMenuPortal>
|
|
7
|
+
<ContextMenuSubContent :class="menuClasses" align="start" side="right" :side-offset="2" :align-offset="-6">
|
|
8
|
+
<slot name="menu" />
|
|
9
|
+
</ContextMenuSubContent>
|
|
10
|
+
</ContextMenuPortal>
|
|
11
|
+
</ContextMenuSub>
|
|
12
|
+
<ContextMenuRoot v-else-if="isContextMenu" v-model:open="isOpen" v-bind="$attrs">
|
|
3
13
|
<ContextMenuTrigger as-child>
|
|
4
14
|
<slot />
|
|
5
15
|
</ContextMenuTrigger>
|
|
@@ -9,7 +19,17 @@
|
|
|
9
19
|
</ContextMenuContent>
|
|
10
20
|
</ContextMenuPortal>
|
|
11
21
|
</ContextMenuRoot>
|
|
12
|
-
<
|
|
22
|
+
<DropdownMenuSub v-else-if="isSubmenu" v-model:open="isOpen">
|
|
23
|
+
<DropdownTriggerProvider>
|
|
24
|
+
<slot />
|
|
25
|
+
</DropdownTriggerProvider>
|
|
26
|
+
<DropdownMenuPortal>
|
|
27
|
+
<DropdownMenuSubContent :class="menuClasses" align="start" side="right" :side-offset="2" :align-offset="-6">
|
|
28
|
+
<slot name="menu" />
|
|
29
|
+
</DropdownMenuSubContent>
|
|
30
|
+
</DropdownMenuPortal>
|
|
31
|
+
</DropdownMenuSub>
|
|
32
|
+
<DropdownMenuRoot v-else v-model:open="isOpen" :modal="modal" v-bind="$attrs">
|
|
13
33
|
<DropdownMenuTrigger as-child>
|
|
14
34
|
<slot />
|
|
15
35
|
</DropdownMenuTrigger>
|
|
@@ -53,10 +73,12 @@ import {
|
|
|
53
73
|
ContextMenuSubContent,
|
|
54
74
|
ContextMenuSubTrigger,
|
|
55
75
|
ContextMenuTrigger,
|
|
56
|
-
} from '
|
|
76
|
+
} from 'reka-ui';
|
|
57
77
|
import {
|
|
58
78
|
computed,
|
|
59
79
|
defineComponent,
|
|
80
|
+
inject,
|
|
81
|
+
provide,
|
|
60
82
|
ref,
|
|
61
83
|
watch,
|
|
62
84
|
type PropType
|
|
@@ -65,6 +87,7 @@ import { useZIndex } from '../../composables/useZIndex';
|
|
|
65
87
|
import { scale } from '../../styles/transitions.css';
|
|
66
88
|
import * as style from './style';
|
|
67
89
|
import { DROPDOWN_STATE } from './symbol';
|
|
90
|
+
import DropdownTriggerProvider from './DropdownTriggerProvider.vue';
|
|
68
91
|
|
|
69
92
|
export default defineComponent({
|
|
70
93
|
name: 'Dropdown',
|
|
@@ -99,6 +122,7 @@ export default defineComponent({
|
|
|
99
122
|
ContextMenuSubContent,
|
|
100
123
|
ContextMenuSubTrigger,
|
|
101
124
|
ContextMenuTrigger,
|
|
125
|
+
DropdownTriggerProvider,
|
|
102
126
|
},
|
|
103
127
|
props: {
|
|
104
128
|
open: {
|
|
@@ -151,6 +175,9 @@ export default defineComponent({
|
|
|
151
175
|
},
|
|
152
176
|
emits: ['update:open'],
|
|
153
177
|
setup(props, { emit }) {
|
|
178
|
+
const parentState = inject(DROPDOWN_STATE, null);
|
|
179
|
+
const isSubmenu = computed(() => !!parentState);
|
|
180
|
+
const isContextMenu = computed(() => props.contextMenu || parentState?.contextMenu || false);
|
|
154
181
|
const { nextZIndex } = useZIndex();
|
|
155
182
|
const isOpen = ref(props.open);
|
|
156
183
|
const placement = ref(props.placement);
|
|
@@ -158,6 +185,16 @@ export default defineComponent({
|
|
|
158
185
|
const referenceRef = ref<HTMLElement>();
|
|
159
186
|
const zIndex = ref(props.zIndex ?? nextZIndex());
|
|
160
187
|
|
|
188
|
+
provide(DROPDOWN_STATE, {
|
|
189
|
+
contextMenu: isContextMenu.value,
|
|
190
|
+
isOpen: isOpen.value,
|
|
191
|
+
handleSelect(labels: string[]) {
|
|
192
|
+
isOpen.value = false;
|
|
193
|
+
props.onSelect(labels);
|
|
194
|
+
parentState?.handleSelect(labels);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
161
198
|
watch(
|
|
162
199
|
() => props.open,
|
|
163
200
|
value => {
|
|
@@ -165,6 +202,10 @@ export default defineComponent({
|
|
|
165
202
|
}
|
|
166
203
|
);
|
|
167
204
|
|
|
205
|
+
watch(isOpen, value => {
|
|
206
|
+
emit('update:open', value);
|
|
207
|
+
});
|
|
208
|
+
|
|
168
209
|
function toggleDropdown() {
|
|
169
210
|
isOpen.value = !isOpen.value;
|
|
170
211
|
}
|
|
@@ -199,6 +240,8 @@ export default defineComponent({
|
|
|
199
240
|
computedReferenceClasses,
|
|
200
241
|
transitionName,
|
|
201
242
|
toggleDropdown,
|
|
243
|
+
isContextMenu,
|
|
244
|
+
isSubmenu,
|
|
202
245
|
zIndex,
|
|
203
246
|
scale
|
|
204
247
|
};
|
|
@@ -1,54 +1,50 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
<slot name="icon-left" />
|
|
5
|
-
</div>
|
|
6
|
-
<div :class="style.menuItemTextContainer">
|
|
7
|
-
<span :class="style.menuItemText"><slot /></span>
|
|
8
|
-
</div>
|
|
9
|
-
<slot name="keyboard" />
|
|
10
|
-
</DropdownMenuItem>
|
|
11
|
-
<!-- <component
|
|
12
|
-
:is="computedType"
|
|
13
|
-
:href="href"
|
|
2
|
+
<component
|
|
3
|
+
:is="itemComponent"
|
|
14
4
|
ref="wrapper"
|
|
15
5
|
:class="computedWrapperClasses"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@
|
|
19
|
-
|
|
6
|
+
:disabled="disabled"
|
|
7
|
+
v-bind="componentProps"
|
|
8
|
+
@select="!isSubmenuTrigger ? handleSelect : undefined"
|
|
9
|
+
>
|
|
20
10
|
<div v-if="hasIconLeft" :class="style.menuItemIcon">
|
|
21
11
|
<slot name="icon-left" />
|
|
22
12
|
</div>
|
|
23
13
|
<div :class="style.menuItemTextContainer">
|
|
24
14
|
<span :class="style.menuItemText"><slot /></span>
|
|
25
15
|
</div>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<kbd>{{ key }}</kbd>
|
|
29
|
-
</template>
|
|
30
|
-
</div> -->
|
|
31
|
-
<!-- <div v-if="hasIconRight" :class="style.menuItemIcon">
|
|
16
|
+
<slot name="keyboard" />
|
|
17
|
+
<div v-if="hasIconRight" :class="style.menuItemIconRight">
|
|
32
18
|
<slot name="icon-right" />
|
|
33
19
|
</div>
|
|
34
|
-
</component>
|
|
20
|
+
</component>
|
|
35
21
|
</template>
|
|
36
22
|
|
|
37
23
|
<script lang="ts">
|
|
38
24
|
import {
|
|
39
25
|
computed,
|
|
40
26
|
defineComponent,
|
|
27
|
+
inject,
|
|
41
28
|
type PropType,
|
|
42
29
|
ref
|
|
43
30
|
} from 'vue';
|
|
44
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
ContextMenuItem,
|
|
33
|
+
ContextMenuSubTrigger,
|
|
34
|
+
DropdownMenuItem,
|
|
35
|
+
DropdownMenuSubTrigger
|
|
36
|
+
} from 'reka-ui';
|
|
45
37
|
import * as style from './style';
|
|
46
38
|
import type { Variant } from '../../types/props';
|
|
39
|
+
import { DROPDOWN_STATE, DROPDOWN_TRIGGER_STATE } from './symbol';
|
|
47
40
|
|
|
48
41
|
export default defineComponent({
|
|
49
42
|
name: 'DropdownItem',
|
|
50
43
|
components: {
|
|
44
|
+
ContextMenuItem,
|
|
45
|
+
ContextMenuSubTrigger,
|
|
51
46
|
DropdownMenuItem
|
|
47
|
+
,DropdownMenuSubTrigger
|
|
52
48
|
},
|
|
53
49
|
props: {
|
|
54
50
|
label: {
|
|
@@ -86,15 +82,25 @@ export default defineComponent({
|
|
|
86
82
|
},
|
|
87
83
|
emits: [],
|
|
88
84
|
setup(props, { slots }) {
|
|
85
|
+
const dropdownState = inject(DROPDOWN_STATE, null);
|
|
86
|
+
const isSubmenuTrigger = inject(DROPDOWN_TRIGGER_STATE, false);
|
|
89
87
|
|
|
90
88
|
const hasIconLeft = computed(() => !!slots['icon-left']);
|
|
91
89
|
const hasIconRight = computed(() => !!slots['icon-right']);
|
|
92
90
|
|
|
93
|
-
const wrapper = ref(null);
|
|
91
|
+
const wrapper = ref<HTMLElement | null>(null);
|
|
94
92
|
const computedWrapperClasses = computed(() => {
|
|
95
93
|
return [style.menuItem, style.variant[props.variant]];
|
|
96
94
|
});
|
|
97
95
|
|
|
96
|
+
const itemComponent = computed(() => {
|
|
97
|
+
if (isSubmenuTrigger) {
|
|
98
|
+
return dropdownState?.contextMenu ? ContextMenuSubTrigger : DropdownMenuSubTrigger;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return dropdownState?.contextMenu ? ContextMenuItem : DropdownMenuItem;
|
|
102
|
+
});
|
|
103
|
+
|
|
98
104
|
const computedType = computed(() => {
|
|
99
105
|
if (props.href) {
|
|
100
106
|
return 'a';
|
|
@@ -103,11 +109,35 @@ export default defineComponent({
|
|
|
103
109
|
return 'div';
|
|
104
110
|
});
|
|
105
111
|
|
|
112
|
+
const componentProps = computed(() => {
|
|
113
|
+
if (isSubmenuTrigger) {
|
|
114
|
+
return {};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
as: computedType.value,
|
|
119
|
+
href: props.href
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
function handleSelect() {
|
|
124
|
+
if (props.disabled || isSubmenuTrigger) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
dropdownState?.handleSelect([String(props.label ?? wrapper.value?.textContent?.trim() ?? '')]);
|
|
129
|
+
props.onSelect(props.label ?? wrapper.value?.textContent?.trim() ?? '');
|
|
130
|
+
}
|
|
131
|
+
|
|
106
132
|
return {
|
|
107
133
|
wrapper,
|
|
134
|
+
itemComponent,
|
|
135
|
+
isSubmenuTrigger,
|
|
108
136
|
hasIconLeft,
|
|
109
137
|
hasIconRight,
|
|
110
138
|
computedWrapperClasses,
|
|
139
|
+
componentProps,
|
|
140
|
+
handleSelect,
|
|
111
141
|
style,
|
|
112
142
|
computedType
|
|
113
143
|
};
|
|
@@ -1,26 +1,34 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<component :is="separatorComponent" :class="computedClasses" />
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script lang="ts">
|
|
6
|
-
import {computed, defineComponent} from
|
|
7
|
-
import
|
|
8
|
-
import
|
|
6
|
+
import { computed, defineComponent, inject } from 'vue';
|
|
7
|
+
import { ContextMenuSeparator, DropdownMenuSeparator } from 'reka-ui';
|
|
8
|
+
import * as style from './style';
|
|
9
|
+
import { DROPDOWN_STATE } from './symbol';
|
|
10
|
+
|
|
9
11
|
export default defineComponent({
|
|
10
|
-
name:
|
|
12
|
+
name: 'DropdownSeperator',
|
|
11
13
|
components: {
|
|
14
|
+
ContextMenuSeparator,
|
|
12
15
|
DropdownMenuSeparator
|
|
13
16
|
},
|
|
14
17
|
setup() {
|
|
18
|
+
const dropdownState = inject(DROPDOWN_STATE, null);
|
|
19
|
+
|
|
15
20
|
const computedClasses = computed(() => {
|
|
16
|
-
return [
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
return [style.menuSeperator];
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const separatorComponent = computed(() => {
|
|
25
|
+
return dropdownState?.contextMenu ? ContextMenuSeparator : DropdownMenuSeparator;
|
|
19
26
|
});
|
|
20
27
|
|
|
21
28
|
return {
|
|
22
|
-
computedClasses
|
|
23
|
-
|
|
29
|
+
computedClasses,
|
|
30
|
+
separatorComponent
|
|
31
|
+
};
|
|
24
32
|
}
|
|
25
|
-
})
|
|
33
|
+
});
|
|
26
34
|
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<slot />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { defineComponent, provide } from 'vue';
|
|
7
|
+
import { DROPDOWN_TRIGGER_STATE } from './symbol';
|
|
8
|
+
|
|
9
|
+
export default defineComponent({
|
|
10
|
+
name: 'DropdownTriggerProvider',
|
|
11
|
+
setup() {
|
|
12
|
+
provide(DROPDOWN_TRIGGER_STATE, true);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
</script>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div>
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
<MDropdown v-model:open="isOpen" :style="{ top: `199px`, left: `9px` }">
|
|
5
|
+
<MDropdown contextMenu v-model:open="isOpen" :style="{ top: `199px`, left: `9px` }">
|
|
6
6
|
<div style="background: #eee; width: 500px; height: 500px;">
|
|
7
7
|
</div>
|
|
8
8
|
<template #menu>
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
|
|
48
48
|
<script lang="ts" setup>
|
|
49
49
|
import { ref } from 'vue';
|
|
50
|
-
const isOpen = ref(
|
|
50
|
+
const isOpen = ref(false);
|
|
51
51
|
const handleClick = () => {
|
|
52
52
|
alert('hi');
|
|
53
53
|
}
|