@teammodlr/ui-kit 3.0.0-beta.2 → 3.0.0-beta.20
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/colorpicker/ColorPicker.vue.d.ts +0 -1
- package/lib/components/colorpicker/style/ColorPicker.css.d.ts +1 -0
- package/lib/components/dialog/Dialog.vue.d.ts +6 -2
- package/lib/components/dialogprovider/types.d.ts +2 -0
- package/lib/components/drawer/Drawer.vue.d.ts +142 -0
- package/lib/components/drawer/style/Drawer.css.d.ts +33 -0
- package/lib/components/drawer/style/index.d.ts +1 -0
- package/lib/components/index.d.ts +2 -0
- package/lib/components/messageprovider/MessageProvider.vue.d.ts +2 -0
- package/lib/components/messageprovider/style/Toaster.css.d.ts +1 -0
- package/lib/components/popover/Popover.vue.d.ts +113 -0
- package/lib/components/popover/style/Popover.css.d.ts +4 -0
- package/lib/components/popover/style/index.d.ts +1 -0
- package/lib/index.cjs.js +3 -3
- package/lib/index.es.js +5754 -5230
- package/lib/style.css +1 -1
- package/package.json +1 -1
- package/src/components/cardcontextmenu/style/Dropdown.css.ts +7 -0
- package/src/components/colorpicker/ColorPicker.vue +8 -11
- package/src/components/colorpicker/examples/basic.vue +8 -17
- package/src/components/colorpicker/style/ColorPicker.css.ts +6 -1
- package/src/components/dialog/Dialog.vue +32 -13
- package/src/components/dialog/style/Dialog.css.ts +15 -1
- package/src/components/dialogprovider/DialogProvider.vue +7 -1
- package/src/components/dialogprovider/types.ts +2 -0
- package/src/components/drawer/Drawer.vue +276 -0
- package/src/components/drawer/examples/basic.vue +15 -0
- package/src/components/drawer/examples/custom-title.vue +21 -0
- package/src/components/drawer/examples/index.stories.ts +24 -0
- package/src/components/drawer/examples/index.ts +7 -0
- package/src/components/drawer/examples/no-mask.vue +15 -0
- package/src/components/drawer/examples/no-outside-close.vue +15 -0
- package/src/components/drawer/examples/placements.vue +28 -0
- package/src/components/drawer/examples/with-footer.vue +21 -0
- package/src/components/drawer/examples/with-trigger.vue +13 -0
- package/src/components/drawer/style/Drawer.css.ts +208 -0
- package/src/components/drawer/style/index.ts +1 -0
- package/src/components/dropdown/Dropdown.vue +1 -1
- package/src/components/dropdown/style/Dropdown.css.ts +16 -0
- package/src/components/index.ts +2 -0
- package/src/components/messageprovider/MessageProvider.vue +36 -7
- package/src/components/messageprovider/style/Toaster.css.ts +24 -0
- package/src/components/modal/style/Modal.css.ts +26 -2
- package/src/components/popover/Popover.vue +155 -0
- package/src/components/popover/examples/arrow.vue +47 -0
- package/src/components/popover/examples/basic.vue +15 -0
- package/src/components/popover/examples/index.stories.ts +19 -0
- package/src/components/popover/examples/index.ts +4 -0
- package/src/components/popover/examples/placement.vue +59 -0
- package/src/components/popover/examples/variant.vue +30 -0
- package/src/components/popover/style/Popover.css.ts +203 -0
- package/src/components/popover/style/index.ts +1 -0
- package/src/components/tab/Tab.vue +1 -1
- package/src/components/tab/style/Tab.css.ts +6 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import {
|
|
2
|
+
globalKeyframes,
|
|
3
|
+
style,
|
|
4
|
+
styleVariants
|
|
5
|
+
} from '@vanilla-extract/css';
|
|
6
|
+
import { themeVars } from '../../../styles/theme.css';
|
|
7
|
+
|
|
8
|
+
export const mask = style({
|
|
9
|
+
position: 'fixed',
|
|
10
|
+
top: 0,
|
|
11
|
+
insetInlineEnd: 0,
|
|
12
|
+
bottom: 0,
|
|
13
|
+
insetInlineStart: 0,
|
|
14
|
+
height: '100%',
|
|
15
|
+
backgroundColor: 'hsla(0,0%,45.1%,0.7)'
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const drawerBase = {
|
|
19
|
+
position: 'fixed' as const,
|
|
20
|
+
backgroundColor: '#fff',
|
|
21
|
+
display: 'flex',
|
|
22
|
+
flexDirection: 'column' as const,
|
|
23
|
+
boxShadow:
|
|
24
|
+
'0 6px 16px 0 rgba(0,0,0,0.08), 0 3px 6px -4px rgba(0,0,0,0.12), 0 9px 28px 8px rgba(0,0,0,0.05)',
|
|
25
|
+
selectors: {
|
|
26
|
+
'&:focus': { outline: 'none' },
|
|
27
|
+
'&:focus-visible': { outline: 'none' }
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const placement = styleVariants({
|
|
32
|
+
left: {
|
|
33
|
+
...drawerBase,
|
|
34
|
+
top: 0,
|
|
35
|
+
left: 0,
|
|
36
|
+
bottom: 0,
|
|
37
|
+
height: '100%'
|
|
38
|
+
},
|
|
39
|
+
right: {
|
|
40
|
+
...drawerBase,
|
|
41
|
+
top: 0,
|
|
42
|
+
right: 0,
|
|
43
|
+
bottom: 0,
|
|
44
|
+
height: '100%'
|
|
45
|
+
},
|
|
46
|
+
top: {
|
|
47
|
+
...drawerBase,
|
|
48
|
+
top: 0,
|
|
49
|
+
left: 0,
|
|
50
|
+
right: 0,
|
|
51
|
+
width: '100%'
|
|
52
|
+
},
|
|
53
|
+
bottom: {
|
|
54
|
+
...drawerBase,
|
|
55
|
+
bottom: 0,
|
|
56
|
+
left: 0,
|
|
57
|
+
right: 0,
|
|
58
|
+
width: '100%'
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const DURATION = '0.28s';
|
|
63
|
+
const TIMING = 'cubic-bezier(0.16, 1, 0.3, 1)';
|
|
64
|
+
|
|
65
|
+
const SLIDE_LEFT_IN = 'drawer-slide-left-in';
|
|
66
|
+
const SLIDE_LEFT_OUT = 'drawer-slide-left-out';
|
|
67
|
+
const SLIDE_RIGHT_IN = 'drawer-slide-right-in';
|
|
68
|
+
const SLIDE_RIGHT_OUT = 'drawer-slide-right-out';
|
|
69
|
+
const SLIDE_TOP_IN = 'drawer-slide-top-in';
|
|
70
|
+
const SLIDE_TOP_OUT = 'drawer-slide-top-out';
|
|
71
|
+
const SLIDE_BOTTOM_IN = 'drawer-slide-bottom-in';
|
|
72
|
+
const SLIDE_BOTTOM_OUT = 'drawer-slide-bottom-out';
|
|
73
|
+
|
|
74
|
+
globalKeyframes(SLIDE_LEFT_IN, {
|
|
75
|
+
from: { transform: 'translateX(-100%)' },
|
|
76
|
+
to: { transform: 'translateX(0)' }
|
|
77
|
+
});
|
|
78
|
+
globalKeyframes(SLIDE_LEFT_OUT, {
|
|
79
|
+
from: { transform: 'translateX(0)' },
|
|
80
|
+
to: { transform: 'translateX(-100%)' }
|
|
81
|
+
});
|
|
82
|
+
globalKeyframes(SLIDE_RIGHT_IN, {
|
|
83
|
+
from: { transform: 'translateX(100%)' },
|
|
84
|
+
to: { transform: 'translateX(0)' }
|
|
85
|
+
});
|
|
86
|
+
globalKeyframes(SLIDE_RIGHT_OUT, {
|
|
87
|
+
from: { transform: 'translateX(0)' },
|
|
88
|
+
to: { transform: 'translateX(100%)' }
|
|
89
|
+
});
|
|
90
|
+
globalKeyframes(SLIDE_TOP_IN, {
|
|
91
|
+
from: { transform: 'translateY(-100%)' },
|
|
92
|
+
to: { transform: 'translateY(0)' }
|
|
93
|
+
});
|
|
94
|
+
globalKeyframes(SLIDE_TOP_OUT, {
|
|
95
|
+
from: { transform: 'translateY(0)' },
|
|
96
|
+
to: { transform: 'translateY(-100%)' }
|
|
97
|
+
});
|
|
98
|
+
globalKeyframes(SLIDE_BOTTOM_IN, {
|
|
99
|
+
from: { transform: 'translateY(100%)' },
|
|
100
|
+
to: { transform: 'translateY(0)' }
|
|
101
|
+
});
|
|
102
|
+
globalKeyframes(SLIDE_BOTTOM_OUT, {
|
|
103
|
+
from: { transform: 'translateY(0)' },
|
|
104
|
+
to: { transform: 'translateY(100%)' }
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
export const slideTransition = {
|
|
108
|
+
left: {
|
|
109
|
+
enterActive: style({ animation: `${DURATION} ${SLIDE_LEFT_IN} ${TIMING}`, willChange: 'transform' }),
|
|
110
|
+
leaveActive: style({ animation: `${DURATION} ${SLIDE_LEFT_OUT} ${TIMING}`, willChange: 'transform' }),
|
|
111
|
+
enterFrom: style({ transform: 'translateX(-100%)' }),
|
|
112
|
+
leaveTo: style({ transform: 'translateX(-100%)' })
|
|
113
|
+
},
|
|
114
|
+
right: {
|
|
115
|
+
enterActive: style({ animation: `${DURATION} ${SLIDE_RIGHT_IN} ${TIMING}`, willChange: 'transform' }),
|
|
116
|
+
leaveActive: style({ animation: `${DURATION} ${SLIDE_RIGHT_OUT} ${TIMING}`, willChange: 'transform' }),
|
|
117
|
+
enterFrom: style({ transform: 'translateX(100%)' }),
|
|
118
|
+
leaveTo: style({ transform: 'translateX(100%)' })
|
|
119
|
+
},
|
|
120
|
+
top: {
|
|
121
|
+
enterActive: style({ animation: `${DURATION} ${SLIDE_TOP_IN} ${TIMING}`, willChange: 'transform' }),
|
|
122
|
+
leaveActive: style({ animation: `${DURATION} ${SLIDE_TOP_OUT} ${TIMING}`, willChange: 'transform' }),
|
|
123
|
+
enterFrom: style({ transform: 'translateY(-100%)' }),
|
|
124
|
+
leaveTo: style({ transform: 'translateY(-100%)' })
|
|
125
|
+
},
|
|
126
|
+
bottom: {
|
|
127
|
+
enterActive: style({ animation: `${DURATION} ${SLIDE_BOTTOM_IN} ${TIMING}`, willChange: 'transform' }),
|
|
128
|
+
leaveActive: style({ animation: `${DURATION} ${SLIDE_BOTTOM_OUT} ${TIMING}`, willChange: 'transform' }),
|
|
129
|
+
enterFrom: style({ transform: 'translateY(100%)' }),
|
|
130
|
+
leaveTo: style({ transform: 'translateY(100%)' })
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const header = style({
|
|
135
|
+
display: 'flex',
|
|
136
|
+
justifyContent: 'space-between',
|
|
137
|
+
alignItems: 'center',
|
|
138
|
+
padding: `${themeVars.space[4]} ${themeVars.space[4]} 0 ${themeVars.space[4]}`,
|
|
139
|
+
flexShrink: '0'
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
export const title = style({
|
|
143
|
+
margin: 0,
|
|
144
|
+
fontSize: `${themeVars.fontSize.xlarge}`,
|
|
145
|
+
fontWeight: '500',
|
|
146
|
+
color: themeVars.color.font.default
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
export const close = style({
|
|
150
|
+
outline: 'none',
|
|
151
|
+
display: 'inline-flex',
|
|
152
|
+
alignItems: 'center',
|
|
153
|
+
justifyContent: 'center',
|
|
154
|
+
width: '1.5rem',
|
|
155
|
+
height: '1.5rem',
|
|
156
|
+
backgroundColor: 'transparent',
|
|
157
|
+
border: 'none',
|
|
158
|
+
padding: 0,
|
|
159
|
+
cursor: 'pointer',
|
|
160
|
+
borderRadius: themeVars.rounded.full,
|
|
161
|
+
position: 'relative',
|
|
162
|
+
transition: 'background-color 0.2s',
|
|
163
|
+
':hover': {
|
|
164
|
+
backgroundColor: themeVars.color.gray[150]
|
|
165
|
+
},
|
|
166
|
+
':focus-visible': {
|
|
167
|
+
outline: 'none',
|
|
168
|
+
backgroundColor: themeVars.color.gray[150]
|
|
169
|
+
},
|
|
170
|
+
'::before': {
|
|
171
|
+
content: '""',
|
|
172
|
+
position: 'absolute',
|
|
173
|
+
top: '50%',
|
|
174
|
+
left: '50%',
|
|
175
|
+
transform: 'translate(-50%, -50%) rotate(45deg)',
|
|
176
|
+
width: '0.8rem',
|
|
177
|
+
height: '2px',
|
|
178
|
+
backgroundColor: themeVars.color.gray[500],
|
|
179
|
+
transformOrigin: 'center'
|
|
180
|
+
},
|
|
181
|
+
'::after': {
|
|
182
|
+
content: '""',
|
|
183
|
+
position: 'absolute',
|
|
184
|
+
top: '50%',
|
|
185
|
+
left: '50%',
|
|
186
|
+
transform: 'translate(-50%, -50%) rotate(-45deg)',
|
|
187
|
+
width: '0.8rem',
|
|
188
|
+
height: '2px',
|
|
189
|
+
backgroundColor: themeVars.color.gray[500],
|
|
190
|
+
transformOrigin: 'center'
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
export const body = style({
|
|
195
|
+
padding: themeVars.space[4],
|
|
196
|
+
display: 'flex',
|
|
197
|
+
flexDirection: 'column',
|
|
198
|
+
flexGrow: '1',
|
|
199
|
+
overflowY: 'auto',
|
|
200
|
+
color: themeVars.color.font.text
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
export const footer = style({
|
|
204
|
+
display: 'flex',
|
|
205
|
+
alignItems: 'center',
|
|
206
|
+
padding: `0 ${themeVars.space[4]} ${themeVars.space[4]} ${themeVars.space[4]}`,
|
|
207
|
+
flexShrink: '0'
|
|
208
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Drawer.css';
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</ContextMenuSubContent>
|
|
10
10
|
</ContextMenuPortal>
|
|
11
11
|
</ContextMenuSub>
|
|
12
|
-
<ContextMenuRoot v-else-if="isContextMenu" v-model:open="isOpen" v-bind="$attrs">
|
|
12
|
+
<ContextMenuRoot v-else-if="isContextMenu" v-model:open="isOpen" :modal="modal" v-bind="$attrs">
|
|
13
13
|
<ContextMenuTrigger as-child>
|
|
14
14
|
<slot />
|
|
15
15
|
</ContextMenuTrigger>
|
|
@@ -197,6 +197,22 @@ export const menuItem = style({
|
|
|
197
197
|
backgroundColor: vars.backgroundColor,
|
|
198
198
|
color: vars.color,
|
|
199
199
|
outline: 'none'
|
|
200
|
+
},
|
|
201
|
+
':focus': {
|
|
202
|
+
vars: {
|
|
203
|
+
[vars.backgroundColor]: themeVars.color.gray[150],
|
|
204
|
+
},
|
|
205
|
+
backgroundColor: vars.backgroundColor,
|
|
206
|
+
outline: 'none'
|
|
207
|
+
},
|
|
208
|
+
selectors: {
|
|
209
|
+
'&[aria-expanded="true"]': {
|
|
210
|
+
vars: {
|
|
211
|
+
[vars.backgroundColor]: themeVars.color.gray[150],
|
|
212
|
+
},
|
|
213
|
+
backgroundColor: vars.backgroundColor,
|
|
214
|
+
outline: 'none'
|
|
215
|
+
}
|
|
200
216
|
}
|
|
201
217
|
});
|
|
202
218
|
|
package/src/components/index.ts
CHANGED
|
@@ -55,4 +55,6 @@ export { default as MConfirm } from './confirm/Confirm.vue';
|
|
|
55
55
|
export { default as MConfirmProvider } from './confirm/ConfirmProvider.vue';
|
|
56
56
|
export { default as MDialog } from './dialog/Dialog.vue';
|
|
57
57
|
export { default as MDialogProvider } from './dialogprovider/DialogProvider.vue';
|
|
58
|
+
export { default as MDrawer } from './drawer/Drawer.vue';
|
|
58
59
|
export { default as MTree } from './tree/Tree.vue';
|
|
60
|
+
export { default as MPopover } from './popover/Popover.vue';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<slot />
|
|
3
3
|
<Toaster
|
|
4
|
+
:class="style.toaster"
|
|
4
5
|
:position="sonnerPosition"
|
|
5
6
|
:duration="timeout"
|
|
6
7
|
:visible-toasts="max"
|
|
@@ -24,6 +25,7 @@ import type {
|
|
|
24
25
|
MessageType,
|
|
25
26
|
} from './types';
|
|
26
27
|
import type { PropType } from 'vue';
|
|
28
|
+
import * as style from './style/Toaster.css';
|
|
27
29
|
|
|
28
30
|
interface PrivateMessageReactive extends MessageReactive {
|
|
29
31
|
id: string;
|
|
@@ -62,7 +64,7 @@ export default defineComponent({
|
|
|
62
64
|
},
|
|
63
65
|
},
|
|
64
66
|
setup(props) {
|
|
65
|
-
const activeMessages = new Map<string, { stop: () => void; closed: boolean; onClose?: () => void }>();
|
|
67
|
+
const activeMessages = new Map<string, { stop: () => void; closed: boolean; currentId: string; onClose?: () => void }>();
|
|
66
68
|
|
|
67
69
|
const sonnerPosition = computed(() => placementMap[props.placement]);
|
|
68
70
|
|
|
@@ -98,9 +100,9 @@ export default defineComponent({
|
|
|
98
100
|
return timeout ?? props.timeout;
|
|
99
101
|
}
|
|
100
102
|
|
|
101
|
-
function
|
|
103
|
+
function createToast(message: PrivateMessageReactive, sonnerId: string) {
|
|
102
104
|
const options: ExternalToast = {
|
|
103
|
-
id:
|
|
105
|
+
id: sonnerId,
|
|
104
106
|
duration: normalizeDuration(message.timeout),
|
|
105
107
|
closeButton: message.closeButton ?? message.closable,
|
|
106
108
|
richColors: message.richColors,
|
|
@@ -131,6 +133,23 @@ export default defineComponent({
|
|
|
131
133
|
}
|
|
132
134
|
}
|
|
133
135
|
|
|
136
|
+
function syncToast(message: PrivateMessageReactive) {
|
|
137
|
+
const active = activeMessages.get(message.id);
|
|
138
|
+
if (!active) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const oldId = active.currentId;
|
|
143
|
+
const newId = Math.random().toString(16).slice(2, 14);
|
|
144
|
+
active.currentId = newId;
|
|
145
|
+
|
|
146
|
+
toast.dismiss(oldId);
|
|
147
|
+
|
|
148
|
+
requestAnimationFrame(() => {
|
|
149
|
+
createToast(message, newId);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
134
153
|
function closeMessage(id: string, invokeOnClose: boolean) {
|
|
135
154
|
const active = activeMessages.get(id);
|
|
136
155
|
if (!active || active.closed) {
|
|
@@ -162,20 +181,29 @@ export default defineComponent({
|
|
|
162
181
|
type: options.type,
|
|
163
182
|
onClose: options.onClose,
|
|
164
183
|
destroy: () => {
|
|
184
|
+
const active = activeMessages.get(id);
|
|
185
|
+
const sonnerId = active?.currentId ?? id;
|
|
165
186
|
closeMessage(id, false);
|
|
166
|
-
toast.dismiss(
|
|
187
|
+
toast.dismiss(sonnerId);
|
|
167
188
|
},
|
|
168
189
|
}) as PrivateMessageReactive;
|
|
169
190
|
|
|
191
|
+
const sonnerId = Math.random().toString(16).slice(2, 14);
|
|
192
|
+
activeMessages.set(id, { stop: () => {}, closed: false, currentId: sonnerId, onClose: options.onClose });
|
|
193
|
+
|
|
170
194
|
const stop = watch(
|
|
171
195
|
() => [message.content, message.type, message.timeout, message.closable, message.closeButton, message.richColors, sonnerPosition.value],
|
|
172
|
-
() => {
|
|
173
|
-
|
|
196
|
+
(_, oldVal) => {
|
|
197
|
+
if (!oldVal) {
|
|
198
|
+
createToast(message, activeMessages.get(id)!.currentId);
|
|
199
|
+
} else {
|
|
200
|
+
syncToast(message);
|
|
201
|
+
}
|
|
174
202
|
},
|
|
175
203
|
{ immediate: true }
|
|
176
204
|
);
|
|
177
205
|
|
|
178
|
-
activeMessages.
|
|
206
|
+
activeMessages.get(id)!.stop = stop;
|
|
179
207
|
|
|
180
208
|
return message;
|
|
181
209
|
}
|
|
@@ -192,6 +220,7 @@ export default defineComponent({
|
|
|
192
220
|
|
|
193
221
|
return {
|
|
194
222
|
sonnerPosition,
|
|
223
|
+
style,
|
|
195
224
|
};
|
|
196
225
|
},
|
|
197
226
|
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { globalStyle, style } from '@vanilla-extract/css';
|
|
2
|
+
import { themeVars } from '../../../styles/theme.css';
|
|
3
|
+
|
|
4
|
+
export const toaster = style({});
|
|
5
|
+
|
|
6
|
+
globalStyle(`${toaster} [data-sonner-toast][data-type='success'] [data-icon]`, {
|
|
7
|
+
color: themeVars.color.green[500]
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
globalStyle(`${toaster} [data-sonner-toast][data-type='error'] [data-icon]`, {
|
|
11
|
+
color: themeVars.color.red[500]
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
globalStyle(`${toaster} [data-sonner-toast][data-type='warning'] [data-icon]`, {
|
|
15
|
+
color: themeVars.color.amber[500]
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
globalStyle(`${toaster} [data-sonner-toast][data-type='info'] [data-icon]`, {
|
|
19
|
+
color: themeVars.color.blue[500]
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
globalStyle(`${toaster} [data-sonner-toast][data-type='loading'] [data-icon]`, {
|
|
23
|
+
color: themeVars.color.gray[500]
|
|
24
|
+
});
|
|
@@ -79,7 +79,16 @@ export const modal = style({
|
|
|
79
79
|
top: 100,
|
|
80
80
|
paddingBottom: '24px',
|
|
81
81
|
maxWidth: `calc(100vw - 32px)`,
|
|
82
|
-
pointerEvents: 'none'
|
|
82
|
+
pointerEvents: 'none',
|
|
83
|
+
selectors: {
|
|
84
|
+
'&:focus': {
|
|
85
|
+
outline: 'none'
|
|
86
|
+
},
|
|
87
|
+
'&:focus-visible': {
|
|
88
|
+
outline: 'none',
|
|
89
|
+
boxShadow: 'none'
|
|
90
|
+
}
|
|
91
|
+
}
|
|
83
92
|
});
|
|
84
93
|
|
|
85
94
|
export const centeredWrapper = style({
|
|
@@ -113,7 +122,17 @@ export const container = style({
|
|
|
113
122
|
flexDirection: 'column',
|
|
114
123
|
position: 'relative',
|
|
115
124
|
gap: themeVars.space[2],
|
|
116
|
-
pointerEvents: 'auto'
|
|
125
|
+
pointerEvents: 'auto',
|
|
126
|
+
selectors: {
|
|
127
|
+
'&:focus': {
|
|
128
|
+
outline: 'none'
|
|
129
|
+
},
|
|
130
|
+
'&:focus-visible': {
|
|
131
|
+
outline: 'none',
|
|
132
|
+
boxShadow:
|
|
133
|
+
'0 1px 2px -2px rgba(0, 0, 0, 0.08), 0 3px 6px 0 rgba(0, 0, 0, 0.06), 0 5px 12px 4px rgba(0, 0, 0, 0.04)'
|
|
134
|
+
}
|
|
135
|
+
}
|
|
117
136
|
});
|
|
118
137
|
|
|
119
138
|
export const hasSidebar = style({
|
|
@@ -159,6 +178,11 @@ export const close = style([
|
|
|
159
178
|
':focus': {
|
|
160
179
|
backgroundColor: themeVars.color.gray[150]
|
|
161
180
|
},
|
|
181
|
+
':focus-visible': {
|
|
182
|
+
outline: 'none',
|
|
183
|
+
boxShadow: 'none',
|
|
184
|
+
backgroundColor: themeVars.color.gray[150]
|
|
185
|
+
},
|
|
162
186
|
'::before': {
|
|
163
187
|
content: '""',
|
|
164
188
|
position: 'absolute',
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<PopoverRoot v-model:open="isOpen" :modal="modal">
|
|
3
|
+
<PopoverTrigger as-child>
|
|
4
|
+
<slot />
|
|
5
|
+
</PopoverTrigger>
|
|
6
|
+
<PopoverPortal :disabled="!transfer">
|
|
7
|
+
<PopoverContent
|
|
8
|
+
:class="contentClasses"
|
|
9
|
+
:side="resolvedSide"
|
|
10
|
+
:align="resolvedAlign"
|
|
11
|
+
:side-offset="sideOffset"
|
|
12
|
+
:collision-padding="collisionPadding"
|
|
13
|
+
:style="{ zIndex: zIndex }"
|
|
14
|
+
>
|
|
15
|
+
<slot name="content" />
|
|
16
|
+
<PopoverArrow v-if="showArrow" :class="style.arrow" :width="12" :height="6" />
|
|
17
|
+
</PopoverContent>
|
|
18
|
+
</PopoverPortal>
|
|
19
|
+
</PopoverRoot>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script lang="ts">
|
|
23
|
+
import {
|
|
24
|
+
PopoverArrow,
|
|
25
|
+
PopoverContent,
|
|
26
|
+
PopoverPortal,
|
|
27
|
+
PopoverRoot,
|
|
28
|
+
PopoverTrigger,
|
|
29
|
+
type PopoverContentProps
|
|
30
|
+
} from 'reka-ui';
|
|
31
|
+
import {
|
|
32
|
+
computed,
|
|
33
|
+
defineComponent,
|
|
34
|
+
ref,
|
|
35
|
+
useAttrs,
|
|
36
|
+
watch,
|
|
37
|
+
type PropType
|
|
38
|
+
} from 'vue';
|
|
39
|
+
import {
|
|
40
|
+
type Placement,
|
|
41
|
+
placementWhileList
|
|
42
|
+
} from '../../composables/usePopper';
|
|
43
|
+
import { useZIndex } from '../../composables/useZIndex';
|
|
44
|
+
import * as style from './style';
|
|
45
|
+
|
|
46
|
+
export default defineComponent({
|
|
47
|
+
name: 'MPopover',
|
|
48
|
+
inheritAttrs: false,
|
|
49
|
+
components: {
|
|
50
|
+
PopoverArrow,
|
|
51
|
+
PopoverContent,
|
|
52
|
+
PopoverPortal,
|
|
53
|
+
PopoverRoot,
|
|
54
|
+
PopoverTrigger
|
|
55
|
+
},
|
|
56
|
+
props: {
|
|
57
|
+
open: {
|
|
58
|
+
type: Boolean,
|
|
59
|
+
default: false
|
|
60
|
+
},
|
|
61
|
+
modal: {
|
|
62
|
+
type: Boolean,
|
|
63
|
+
default: false
|
|
64
|
+
},
|
|
65
|
+
placement: {
|
|
66
|
+
type: String as PropType<Placement>,
|
|
67
|
+
default: 'bottom',
|
|
68
|
+
validator: (value: Placement) => placementWhileList.includes(value)
|
|
69
|
+
},
|
|
70
|
+
transfer: {
|
|
71
|
+
type: Boolean,
|
|
72
|
+
default: true
|
|
73
|
+
},
|
|
74
|
+
sideOffset: {
|
|
75
|
+
type: Number,
|
|
76
|
+
default: 5
|
|
77
|
+
},
|
|
78
|
+
collisionPadding: {
|
|
79
|
+
type: [Number, Object] as PropType<number | { top?: number; right?: number; bottom?: number; left?: number }>,
|
|
80
|
+
default: 10
|
|
81
|
+
},
|
|
82
|
+
arrow: {
|
|
83
|
+
type: Boolean,
|
|
84
|
+
default: false
|
|
85
|
+
},
|
|
86
|
+
variant: {
|
|
87
|
+
type: String as PropType<'light' | 'dark'>,
|
|
88
|
+
default: 'light'
|
|
89
|
+
},
|
|
90
|
+
zIndex: {
|
|
91
|
+
type: Number
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
emits: ['update:open'],
|
|
95
|
+
setup(props, { emit }) {
|
|
96
|
+
const attrs = useAttrs();
|
|
97
|
+
const { nextZIndex } = useZIndex();
|
|
98
|
+
const isOpen = ref(props.open);
|
|
99
|
+
const zIndex = ref(props.zIndex ?? nextZIndex());
|
|
100
|
+
|
|
101
|
+
const resolvedPlacement = computed(() => {
|
|
102
|
+
const [side, align] = props.placement.split('-');
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
side: side === 'top' || side === 'right' || side === 'bottom' || side === 'left'
|
|
106
|
+
? side
|
|
107
|
+
: undefined,
|
|
108
|
+
align: align === 'start' || align === 'center' || align === 'end'
|
|
109
|
+
? align
|
|
110
|
+
: undefined
|
|
111
|
+
} as {
|
|
112
|
+
side?: PopoverContentProps['side'];
|
|
113
|
+
align?: PopoverContentProps['align'];
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const showArrow = computed(() => {
|
|
118
|
+
const { align } = resolvedPlacement.value;
|
|
119
|
+
return props.arrow && (!align || align === 'center');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const contentClasses = computed(() => {
|
|
123
|
+
return [
|
|
124
|
+
'm-popover-content',
|
|
125
|
+
style.content,
|
|
126
|
+
{
|
|
127
|
+
[style.dark]: props.variant === 'dark'
|
|
128
|
+
},
|
|
129
|
+
attrs.class
|
|
130
|
+
];
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
watch(
|
|
134
|
+
() => props.open,
|
|
135
|
+
value => {
|
|
136
|
+
isOpen.value = value;
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
watch(isOpen, value => {
|
|
141
|
+
emit('update:open', value);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
isOpen,
|
|
146
|
+
zIndex,
|
|
147
|
+
showArrow,
|
|
148
|
+
contentClasses,
|
|
149
|
+
resolvedSide: computed(() => resolvedPlacement.value.side),
|
|
150
|
+
resolvedAlign: computed(() => resolvedPlacement.value.align),
|
|
151
|
+
style
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
</script>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div style="padding: 100px; display: flex; gap: 16px; flex-wrap: wrap;">
|
|
3
|
+
<MPopover arrow placement="bottom">
|
|
4
|
+
<MButton>Bottom (Arrow)</MButton>
|
|
5
|
+
<template #content>
|
|
6
|
+
<div style="padding: 8px; min-width: 180px;">
|
|
7
|
+
<p style="margin: 0; font-size: 14px;">
|
|
8
|
+
Arrow points to the trigger.
|
|
9
|
+
</p>
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
</MPopover>
|
|
13
|
+
|
|
14
|
+
<MPopover arrow placement="top">
|
|
15
|
+
<MButton>Top (Arrow)</MButton>
|
|
16
|
+
<template #content>
|
|
17
|
+
<div style="padding: 8px; min-width: 180px;">
|
|
18
|
+
<p style="margin: 0; font-size: 14px;">
|
|
19
|
+
Arrow points to the trigger.
|
|
20
|
+
</p>
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
</MPopover>
|
|
24
|
+
|
|
25
|
+
<MPopover arrow placement="left">
|
|
26
|
+
<MButton>Left (Arrow)</MButton>
|
|
27
|
+
<template #content>
|
|
28
|
+
<div style="padding: 8px; min-width: 180px;">
|
|
29
|
+
<p style="margin: 0; font-size: 14px;">
|
|
30
|
+
Arrow points to the trigger.
|
|
31
|
+
</p>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
</MPopover>
|
|
35
|
+
|
|
36
|
+
<MPopover arrow placement="right">
|
|
37
|
+
<MButton>Right (Arrow)</MButton>
|
|
38
|
+
<template #content>
|
|
39
|
+
<div style="padding: 8px; min-width: 180px;">
|
|
40
|
+
<p style="margin: 0; font-size: 14px;">
|
|
41
|
+
Arrow points to the trigger.
|
|
42
|
+
</p>
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
45
|
+
</MPopover>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div style="padding: 100px;">
|
|
3
|
+
<MPopover>
|
|
4
|
+
<MButton>Open Popover</MButton>
|
|
5
|
+
<template #content>
|
|
6
|
+
<div style="padding: 8px; min-width: 200px;">
|
|
7
|
+
<h4 style="margin: 0 0 8px; font-weight: 600;">Popover Title</h4>
|
|
8
|
+
<p style="margin: 0; color: #666; font-size: 14px;">
|
|
9
|
+
This is the popover content. You can put anything here.
|
|
10
|
+
</p>
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
</MPopover>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import MPopover from '../Popover.vue';
|
|
2
|
+
import MButton from '../../button/Button.vue';
|
|
3
|
+
|
|
4
|
+
import { MPopoverBasic, MPopoverPlacement, MPopoverArrow, MPopoverVariant } from './index';
|
|
5
|
+
import { createStory, popperPositionArgType } from '../../../__storybook__';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
component: MPopover,
|
|
9
|
+
subcomponents: { MButton },
|
|
10
|
+
title: 'Components/Popover',
|
|
11
|
+
argTypes: {
|
|
12
|
+
...popperPositionArgType()
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const Basic = createStory(MPopoverBasic);
|
|
17
|
+
export const Placement = createStory(MPopoverPlacement);
|
|
18
|
+
export const Arrow = createStory(MPopoverArrow);
|
|
19
|
+
export const Variant = createStory(MPopoverVariant);
|