@teammodlr/ui-kit 2.0.40 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/avatar/Avatar.vue.d.ts +1 -1
- package/lib/components/avatargroup/AvatarGroup.vue.d.ts +1 -1
- package/lib/components/badge/Badge.vue.d.ts +1 -1
- package/lib/components/breadcrumb/Breadcrumb.vue.d.ts +1 -10
- package/lib/components/breadcrumb/BreadcrumbItem.vue.d.ts +1 -1
- package/lib/components/button/Button.vue.d.ts +2 -2
- package/lib/components/buttongroup/ButtonGroup.vue.d.ts +1 -1
- package/lib/components/checkbox/Checkbox.vue.d.ts +1 -1
- package/lib/components/colorpicker/ColorPicker.vue.d.ts +1 -1
- package/lib/components/dialog/Dialog.vue.d.ts +46 -0
- package/lib/components/dialog/DialogProvider.vue.d.ts +37 -0
- package/lib/components/dialog/props.d.ts +22 -0
- package/lib/components/dialog/providerProps.d.ts +8 -0
- package/lib/components/dialog/types.d.ts +27 -0
- package/lib/components/dialog/useDialog.d.ts +2 -0
- package/lib/components/dropdown/Dropdown.vue.d.ts +1 -1
- package/lib/components/dropdown/DropdownItem.vue.d.ts +1 -1
- package/lib/components/dropdown/DropdownList.vue.d.ts +1 -1
- package/lib/components/dropdown/DropdownSeperator.vue.d.ts +1 -1
- package/lib/components/dropdown/DropdownWrapper.vue.d.ts +1 -1
- package/lib/components/form/Form.vue.d.ts +1 -1
- package/lib/components/image/Image.vue.d.ts +1 -1
- package/lib/components/index.d.ts +3 -0
- package/lib/components/input/Input.vue.d.ts +2 -2
- package/lib/components/link/Link.vue.d.ts +1 -1
- package/lib/components/messageprovider/Message.vue.d.ts +2 -2
- package/lib/components/messageprovider/MessageProvider.vue.d.ts +3 -3
- package/lib/components/modal/Modal.vue.d.ts +12 -1
- package/lib/components/pagination/Pagination.vue.d.ts +1 -1
- package/lib/components/radio/Radio.vue.d.ts +13 -4
- package/lib/components/radiobutton/RadioButton.vue.d.ts +1 -1
- package/lib/components/radiobuttongroup/RadioButtonGroup.vue.d.ts +1 -1
- package/lib/components/renderer/examlpes/basic.vue.d.ts +2 -0
- package/lib/components/renderer/examlpes/index.d.ts +1 -0
- package/lib/components/renderer/props.d.ts +12 -0
- package/lib/components/renderer/renderer.d.ts +23 -0
- package/lib/components/select/Select.vue.d.ts +2 -2
- package/lib/components/select/style/Select.css.d.ts +2 -0
- package/lib/components/skeleton/Skeleton.vue.d.ts +1 -1
- package/lib/components/slider/Slider.vue.d.ts +1 -1
- package/lib/components/switch/Switch.vue.d.ts +1 -1
- package/lib/components/tab/Tab.vue.d.ts +1 -1
- package/lib/components/tab/TabGroup.vue.d.ts +1 -1
- package/lib/components/table/Table.vue.d.ts +1 -1
- package/lib/components/table/TableBody.vue.d.ts +1 -1
- package/lib/components/table/TableCell.vue.d.ts +1 -1
- package/lib/components/table/TableHead.vue.d.ts +1 -1
- package/lib/components/table/TableHeadRow.vue.d.ts +1 -1
- package/lib/components/table/TableRow.vue.d.ts +1 -1
- package/lib/components/tag/Tag.vue.d.ts +2 -2
- package/lib/components/textarea/Textarea.vue.d.ts +3 -3
- package/lib/components/tooltip/Tooltip.vue.d.ts +1 -1
- package/lib/components/transfer/Transfer.vue.d.ts +1 -1
- package/lib/components/virtualscroll/VirtualScroll.vue.d.ts +1 -1
- package/lib/composables/index.d.ts +1 -0
- package/lib/index.cjs.js +2 -8
- package/lib/index.es.js +2877 -3237
- package/lib/nuxt.plugin.js +1 -1
- package/lib/style.css +1 -1
- package/lib/styles/theme.css.d.ts +10 -10
- package/package.json +24 -27
- package/src/components/breadcrumb/Breadcrumb.vue +4 -8
- package/src/components/dialog/Dialog.vue +60 -0
- package/src/components/dialog/DialogProvider.vue +81 -0
- package/src/components/dialog/examples/basic.vue +48 -0
- package/src/components/dialog/examples/index.stories.ts +29 -0
- package/src/components/dialog/examples/index.ts +1 -0
- package/src/components/dialog/examples/wrapper.vue +9 -0
- package/src/components/dialog/props.ts +24 -0
- package/src/components/dialog/providerProps.ts +11 -0
- package/src/components/dialog/types.ts +34 -0
- package/src/components/dialog/useDialog.ts +12 -0
- package/src/components/index.ts +3 -0
- package/src/components/messageprovider/MessageProvider.vue +7 -7
- package/src/components/messageprovider/style/Message.css.ts +2 -1
- package/src/components/modal/Modal.vue +36 -11
- package/src/components/radio/Radio.vue +32 -33
- package/src/components/radio/examples/basic.vue +2 -3
- package/src/components/radio/examples/group.vue +15 -0
- package/src/components/radio/examples/index.stories.ts +2 -0
- package/src/components/radio/examples/index.ts +1 -0
- package/src/components/renderer/examlpes/basic.vue +23 -0
- package/src/components/renderer/examlpes/index.stories.ts +18 -0
- package/src/components/renderer/examlpes/index.ts +1 -0
- package/src/components/renderer/props.ts +15 -0
- package/src/components/renderer/renderer.ts +16 -0
- package/src/components/select/Select.vue +7 -1
- package/src/components/select/style/Select.css.ts +25 -1
- package/src/composables/index.ts +2 -1
- package/src/composables/useZIndex.ts +5 -3
- package/src/examples/modal/modal.stories.ts +9 -0
- package/src/examples/modal/modal.vue +52 -0
- package/src/exports/nuxt.plugin.js +1 -1
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { inject } from 'vue';
|
|
2
|
+
import type { DialogApiInjection } from './types';
|
|
3
|
+
|
|
4
|
+
export function useDialog(): DialogApiInjection {
|
|
5
|
+
const api = inject('m-dialog', null);
|
|
6
|
+
|
|
7
|
+
if (api === null) {
|
|
8
|
+
throw new Error('m-dialog api is not provided, ensure the component is wrapped in <m-dialog-provider />.');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return api;
|
|
12
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { default as MRenderer } from './renderer/renderer';
|
|
1
2
|
export { default as MAvatar } from './avatar/Avatar.vue';
|
|
2
3
|
export { default as MAvatarGroup } from './avatargroup/AvatarGroup.vue';
|
|
3
4
|
export { default as MBadge } from './badge/Badge.vue';
|
|
@@ -39,3 +40,5 @@ export { default as MTextarea } from './textarea/Textarea.vue';
|
|
|
39
40
|
export { default as MTooltip } from './tooltip/Tooltip.vue';
|
|
40
41
|
export { default as MTransfer } from './transfer/Transfer.vue';
|
|
41
42
|
export { default as MVirtualScroll } from './virtualscroll/VirtualScroll.vue';
|
|
43
|
+
export { default as MDialog } from './dialog/Dialog.vue';
|
|
44
|
+
export { default as MDialogProvider } from './dialog/DialogProvider.vue';
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<slot />
|
|
3
|
-
<template
|
|
3
|
+
<template>
|
|
4
4
|
<Teleport :to="teleportTo ?? 'body'">
|
|
5
5
|
<transition
|
|
6
6
|
type="animation"
|
|
7
|
-
:enter-active-class="
|
|
8
|
-
:leave-active-class="
|
|
9
|
-
:enter-from-class="
|
|
10
|
-
:leave-to-class="
|
|
7
|
+
:enter-active-class="modalScale.enterActive"
|
|
8
|
+
:leave-active-class="modalScale.leaveActive"
|
|
9
|
+
:enter-from-class="modalScale.enterFrom"
|
|
10
|
+
:leave-to-class="modalScale.leaveTo"
|
|
11
11
|
>
|
|
12
12
|
<div :class="classes">
|
|
13
13
|
<MMessage v-for="message in messageList"
|
|
@@ -39,7 +39,7 @@ import type { PropType } from 'vue';
|
|
|
39
39
|
import MMessage from './Message.vue';
|
|
40
40
|
import { useCachedUid } from '../../composables/useCachedUid';
|
|
41
41
|
import * as style from './style';
|
|
42
|
-
import {
|
|
42
|
+
import { modalScale } from '../../styles/transitions.css';
|
|
43
43
|
export type MessageProviderInst = MessageApiInjection;
|
|
44
44
|
|
|
45
45
|
interface PrivateMessageReactive extends MessageReactive {
|
|
@@ -144,7 +144,7 @@ export default defineComponent({
|
|
|
144
144
|
messageList: messageListRef,
|
|
145
145
|
onInternalAfterLeave,
|
|
146
146
|
classes,
|
|
147
|
-
|
|
147
|
+
modalScale
|
|
148
148
|
},
|
|
149
149
|
api,
|
|
150
150
|
)
|
|
@@ -35,7 +35,8 @@ export const base = style({
|
|
|
35
35
|
fontSize: themeVars.fontSize.base,
|
|
36
36
|
color: themeVars.color.font.text,
|
|
37
37
|
alignItems: "center",
|
|
38
|
-
|
|
38
|
+
willChange: "top, bottom, width",
|
|
39
|
+
transition: "top 0.3s ease-out 0.5s, bottom 0.3s ease-out 0.5s, width 0.3s ease-out 0.5s",
|
|
39
40
|
})
|
|
40
41
|
|
|
41
42
|
export const placement = styleVariants({
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
:enter-from-class="fade.enterFrom"
|
|
8
8
|
:leave-to-class="fade.leaveTo"
|
|
9
9
|
>
|
|
10
|
-
<div v-show="isOpen" :class="style.background" :style="{zIndex: zIndex}" @
|
|
10
|
+
<div v-show="isOpen" :class="style.background" :style="{zIndex: zIndex}" @mousedown="closeOutside">
|
|
11
11
|
<Transition
|
|
12
12
|
type="animation"
|
|
13
13
|
:enter-active-class="modalScale.enterActive"
|
|
@@ -46,11 +46,10 @@
|
|
|
46
46
|
import type {PropType} from "vue";
|
|
47
47
|
import type {Size} from "../../types/props";
|
|
48
48
|
import {defineComponent, ref, computed, watch, nextTick} from 'vue';
|
|
49
|
-
import {useFocusTrap} from '@vueuse/integrations/useFocusTrap'
|
|
50
49
|
import * as style from './style';
|
|
51
50
|
import { modalScale, fade } from "../../styles/transitions.css";
|
|
52
51
|
import {useZIndex} from "../../composables/useZIndex";
|
|
53
|
-
import {
|
|
52
|
+
import { useEventListener, useMagicKeys } from "@vueuse/core";
|
|
54
53
|
|
|
55
54
|
export default defineComponent({
|
|
56
55
|
name: "MModal",
|
|
@@ -67,6 +66,10 @@ export default defineComponent({
|
|
|
67
66
|
type: Boolean,
|
|
68
67
|
default: true
|
|
69
68
|
},
|
|
69
|
+
onClose: {
|
|
70
|
+
type: Function as PropType<() => void>,
|
|
71
|
+
default: () => {}
|
|
72
|
+
},
|
|
70
73
|
zIndex: {
|
|
71
74
|
type: Number
|
|
72
75
|
}
|
|
@@ -77,11 +80,13 @@ export default defineComponent({
|
|
|
77
80
|
const isOpen = ref(false);
|
|
78
81
|
const target = ref();
|
|
79
82
|
const zIndex = ref(props.zIndex ?? nextZIndex());
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
|
|
84
|
+
const clickInside = ref(false);
|
|
85
|
+
// const {hasFocus, activate, deactivate} = useFocusTrap(target, {
|
|
86
|
+
// immediate: true,
|
|
87
|
+
// escapeDeactivates: false,
|
|
88
|
+
// allowOutsideClick: true
|
|
89
|
+
// });
|
|
85
90
|
|
|
86
91
|
const { escape } = useMagicKeys()
|
|
87
92
|
|
|
@@ -98,13 +103,19 @@ export default defineComponent({
|
|
|
98
103
|
];
|
|
99
104
|
});
|
|
100
105
|
|
|
106
|
+
useEventListener(target, 'mousedown', handleMouseDown);
|
|
107
|
+
useEventListener(document, 'mouseup', handleMouseUp);
|
|
108
|
+
|
|
101
109
|
const closeOutside = () => {
|
|
102
|
-
if (props.canClickOutside) {
|
|
110
|
+
if (props.canClickOutside && !clickInside.value) {
|
|
103
111
|
close();
|
|
104
112
|
}
|
|
105
113
|
};
|
|
106
114
|
|
|
107
115
|
const close = () => {
|
|
116
|
+
if (props.onClose) {
|
|
117
|
+
props.onClose();
|
|
118
|
+
}
|
|
108
119
|
ownerScrollbarClose();
|
|
109
120
|
isOpen.value = false;
|
|
110
121
|
};
|
|
@@ -115,6 +126,18 @@ export default defineComponent({
|
|
|
115
126
|
isOpen.value = true;
|
|
116
127
|
};
|
|
117
128
|
|
|
129
|
+
function handleMouseUp(event: MouseEvent) {
|
|
130
|
+
nextTick(() => {
|
|
131
|
+
if (clickInside.value) {
|
|
132
|
+
clickInside.value = false;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function handleMouseDown(event: MouseEvent) {
|
|
138
|
+
clickInside.value = true;
|
|
139
|
+
}
|
|
140
|
+
|
|
118
141
|
function ownerScrollbarOpen() {
|
|
119
142
|
let ownerWindow = window;
|
|
120
143
|
let documentElement = ownerWindow.document.documentElement;
|
|
@@ -144,16 +167,18 @@ export default defineComponent({
|
|
|
144
167
|
zIndex.value = props.zIndex ? zIndex.value++ : nextZIndex();
|
|
145
168
|
emit('open');
|
|
146
169
|
nextTick(() => {
|
|
147
|
-
activate()
|
|
170
|
+
// activate()
|
|
148
171
|
})
|
|
149
172
|
} else {
|
|
150
|
-
deactivate()
|
|
173
|
+
// deactivate()
|
|
151
174
|
}
|
|
152
175
|
});
|
|
153
176
|
|
|
154
177
|
return {
|
|
155
178
|
close,
|
|
156
179
|
closeOutside,
|
|
180
|
+
handleMouseUp,
|
|
181
|
+
handleMouseDown,
|
|
157
182
|
open,
|
|
158
183
|
target,
|
|
159
184
|
style,
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<label :class="style.base"
|
|
2
|
+
<label :class="style.base">
|
|
3
3
|
<input
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
v-model="pick"
|
|
5
|
+
:value="value"
|
|
6
|
+
type="radio"
|
|
7
|
+
:aria-checked="checked ? 'true' : 'false'"
|
|
8
|
+
:aria-disabled="(disabled || loading) ? 'true' : 'false'"
|
|
9
|
+
:aria-labelledby="`${id}-label`"
|
|
10
|
+
:disabled="disabled || loading"
|
|
11
|
+
:name="name"
|
|
12
|
+
:id="id"
|
|
13
|
+
v-bind="$attrs"
|
|
14
|
+
v-on="inputListeners"
|
|
15
|
+
:class="style.input"
|
|
15
16
|
/>
|
|
16
17
|
<span :class="classes"></span>
|
|
17
18
|
<span :class="style.label" :id="`${id}-label`">
|
|
@@ -27,10 +28,11 @@
|
|
|
27
28
|
</template>
|
|
28
29
|
|
|
29
30
|
<script lang="ts">
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import
|
|
31
|
+
import type { PropType } from 'vue';
|
|
32
|
+
import { computed, defineComponent, defineExpose, ref, toRef } from 'vue';
|
|
33
|
+
import { useInput } from '../../composables/useInput';
|
|
34
|
+
import { useInteractive } from "../../composables/useInteractive";
|
|
35
|
+
import type { Size } from '../../types/props';
|
|
34
36
|
import * as style from './style';
|
|
35
37
|
|
|
36
38
|
export default defineComponent({
|
|
@@ -53,6 +55,10 @@ export default defineComponent({
|
|
|
53
55
|
loading: {
|
|
54
56
|
type: Boolean,
|
|
55
57
|
default: false
|
|
58
|
+
},
|
|
59
|
+
value: {
|
|
60
|
+
type: [String, Number, Boolean],
|
|
61
|
+
default: null
|
|
56
62
|
}
|
|
57
63
|
},
|
|
58
64
|
setup(props, {slots, emit}) {
|
|
@@ -74,8 +80,16 @@ export default defineComponent({
|
|
|
74
80
|
|
|
75
81
|
const disabled = computed(() => formDisabled || formLoading || props.disabled || props.loading);
|
|
76
82
|
const name = toRef(props, 'name');
|
|
77
|
-
const checked =
|
|
83
|
+
const checked = computed(() => props.modelValue === props.value);
|
|
78
84
|
const hasSlot = computed(() => !!(slots.default));
|
|
85
|
+
const pick = computed({
|
|
86
|
+
get() {
|
|
87
|
+
return props.modelValue;
|
|
88
|
+
},
|
|
89
|
+
set(value) {
|
|
90
|
+
emit('update:modelValue', value);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
79
93
|
|
|
80
94
|
const classes = computed(() => {
|
|
81
95
|
return [
|
|
@@ -92,21 +106,6 @@ export default defineComponent({
|
|
|
92
106
|
return formError.value || props.error;
|
|
93
107
|
});
|
|
94
108
|
|
|
95
|
-
watch(() => props.modelValue, (value) => {
|
|
96
|
-
checked.value = !!value;
|
|
97
|
-
}, {immediate: true});
|
|
98
|
-
|
|
99
|
-
watch(() => checked.value, (value) => {
|
|
100
|
-
emit('update:modelValue', value);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
function toggle() {
|
|
104
|
-
if (disabled.value) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
checked.value = !checked.value;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
109
|
defineExpose({
|
|
111
110
|
focus,
|
|
112
111
|
blur,
|
|
@@ -122,9 +121,9 @@ export default defineComponent({
|
|
|
122
121
|
disabled,
|
|
123
122
|
name,
|
|
124
123
|
checked,
|
|
124
|
+
pick,
|
|
125
125
|
radioRef,
|
|
126
126
|
inputError,
|
|
127
|
-
toggle,
|
|
128
127
|
style,
|
|
129
128
|
classes,
|
|
130
129
|
hasSlot,
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<MRadio
|
|
2
|
+
<MRadio label="Test" name="item" value="sms" v-model="selected" />
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script lang="ts" setup>
|
|
6
6
|
import { ref } from 'vue'
|
|
7
|
-
|
|
8
|
-
const checked = ref(false);
|
|
7
|
+
const selected = ref('');
|
|
9
8
|
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<MRadio label="SMS" name="item" value="sms" v-model="selected" /><br />
|
|
4
|
+
<MRadio label="Email" name="item" value="email" v-model="selected" />
|
|
5
|
+
<div>
|
|
6
|
+
Selected: {{ selected }}
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script lang="ts" setup>
|
|
12
|
+
import { ref } from 'vue'
|
|
13
|
+
|
|
14
|
+
const selected = ref('sms');
|
|
15
|
+
</script>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<MRenderer :h="renderMessage" :props="{ message: msg }">
|
|
3
|
+
</MRenderer>
|
|
4
|
+
</template>
|
|
5
|
+
|
|
6
|
+
<script setup lang="ts">
|
|
7
|
+
import { h, ref } from 'vue'
|
|
8
|
+
const msg = ref('some content')
|
|
9
|
+
|
|
10
|
+
function renderMessage({ message }: { message: string }) {
|
|
11
|
+
return h('p', [
|
|
12
|
+
'Here are ',
|
|
13
|
+
h(
|
|
14
|
+
'span',
|
|
15
|
+
{
|
|
16
|
+
style: 'color: red'
|
|
17
|
+
},
|
|
18
|
+
[message]
|
|
19
|
+
),
|
|
20
|
+
' that using render function',
|
|
21
|
+
])
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import MRenderer from "../renderer";
|
|
2
|
+
import {
|
|
3
|
+
MRendererBasic,
|
|
4
|
+
} from "./index";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
createStory, sizeArgType
|
|
8
|
+
} from "../../../__storybook__";
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
component: MRenderer,
|
|
12
|
+
title: 'Components/Renderer',
|
|
13
|
+
argTypes: {
|
|
14
|
+
...sizeArgType()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const Basic = createStory(MRendererBasic);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as MRendererBasic } from './basic.vue';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ExtractPropTypes, PropType } from 'vue';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const rendererProps = {
|
|
5
|
+
h: {
|
|
6
|
+
type: Function,
|
|
7
|
+
default: null
|
|
8
|
+
},
|
|
9
|
+
props: {
|
|
10
|
+
type: Object as PropType<Record<string, any>>,
|
|
11
|
+
default: undefined
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type RendererProps = ExtractPropTypes<typeof rendererProps>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineComponent, renderSlot } from 'vue';
|
|
2
|
+
import { rendererProps } from './props';
|
|
3
|
+
|
|
4
|
+
export default defineComponent({
|
|
5
|
+
name: "Renderer",
|
|
6
|
+
props: rendererProps,
|
|
7
|
+
setup(props, { slots }) {
|
|
8
|
+
return () => {
|
|
9
|
+
if (typeof props.h !== 'function') {
|
|
10
|
+
return renderSlot(slots, 'default', props.props);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return props.h(props.props);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
})
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
<div :class="style.menu" v-if="isOpen" ref="popper" :style="computedConsistentWidth"
|
|
42
42
|
:aria-hidden="isOpen ? 'false' : 'true'">
|
|
43
43
|
<div v-if="searchable" :class="style.search">
|
|
44
|
-
<MInput v-model="search" placeholder="Search" size="sm" ref="searchRef"/>
|
|
44
|
+
<!-- <MInput v-model="search" placeholder="Search" size="sm" ref="searchRef"/> -->
|
|
45
|
+
<input type="text" ref="searchRef" v-model="search" placeholder="Search" :class="style.searchInput" />
|
|
45
46
|
</div>
|
|
46
47
|
<div :class="style.options">
|
|
47
48
|
<div v-for="(option, index) in computedOptions" :key="index" ref="optionsRef"
|
|
@@ -54,6 +55,11 @@
|
|
|
54
55
|
@hover="selectedIndex = index">
|
|
55
56
|
{{ option.label }}
|
|
56
57
|
</div>
|
|
58
|
+
<template v-if="computedOptions.length === 0">
|
|
59
|
+
<div :class="style.noResults">
|
|
60
|
+
No results
|
|
61
|
+
</div>
|
|
62
|
+
</template>
|
|
57
63
|
</div>
|
|
58
64
|
</div>
|
|
59
65
|
</Transition>
|
|
@@ -63,6 +63,7 @@ export const base = style({
|
|
|
63
63
|
lineHeight: vars.height,
|
|
64
64
|
boxSizing: 'border-box',
|
|
65
65
|
resize: 'none',
|
|
66
|
+
cursor: 'pointer',
|
|
66
67
|
boxShadow: 'none',
|
|
67
68
|
transition: `color .3s ${themeVars.transition.default},
|
|
68
69
|
background-color .3s ${themeVars.transition.default},
|
|
@@ -194,13 +195,23 @@ export const placeholder = style({
|
|
|
194
195
|
})
|
|
195
196
|
|
|
196
197
|
export const search = style({
|
|
197
|
-
padding: `${themeVars.space[1]} ${themeVars.space[1]} 0`,
|
|
198
|
+
// padding: `${themeVars.space[1]} ${themeVars.space[1]} 0`,
|
|
198
199
|
backgroundColor: '#FFFFFF',
|
|
199
200
|
position: 'sticky',
|
|
200
201
|
top: 0,
|
|
201
202
|
zIndex: 1,
|
|
202
203
|
});
|
|
203
204
|
|
|
205
|
+
export const searchInput = style({
|
|
206
|
+
padding: `${themeVars.space[2.5]} ${themeVars.space[2.5]}`,
|
|
207
|
+
border: 'none',
|
|
208
|
+
outline: 'none',
|
|
209
|
+
width: '100%',
|
|
210
|
+
fontSize: themeVars.fontSize.base,
|
|
211
|
+
borderBottom: `1px solid ${themeVars.color.gray[200]}`,
|
|
212
|
+
color: themeVars.color.gray[800],
|
|
213
|
+
});
|
|
214
|
+
|
|
204
215
|
export const options = style({
|
|
205
216
|
padding: themeVars.space[1],
|
|
206
217
|
display: 'flex',
|
|
@@ -259,3 +270,16 @@ export const optionSelected = style({
|
|
|
259
270
|
},
|
|
260
271
|
}
|
|
261
272
|
});
|
|
273
|
+
|
|
274
|
+
export const noResults = style({
|
|
275
|
+
padding: `${themeVars.space[2]} 0`,
|
|
276
|
+
display: 'flex',
|
|
277
|
+
// flexDirection: 'column',
|
|
278
|
+
alignItems: 'center',
|
|
279
|
+
textAlign: 'center',
|
|
280
|
+
justifyContent: 'center',
|
|
281
|
+
gap: themeVars.space[0.5],
|
|
282
|
+
width: '100%',
|
|
283
|
+
color: themeVars.color.gray[500],
|
|
284
|
+
fontSize: themeVars.fontSize.small,
|
|
285
|
+
});
|
package/src/composables/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type {InjectionKey, Ref} from "vue";
|
|
2
2
|
import {computed, inject, ref, unref} from "vue";
|
|
3
|
-
import {isNumber} from "@vueuse/core";
|
|
4
3
|
|
|
5
4
|
const zIndex = ref(0);
|
|
6
5
|
export const initialZIndex = 1000;
|
|
@@ -11,7 +10,10 @@ export const useZIndex = (override?: Ref<number>) => {
|
|
|
11
10
|
|
|
12
11
|
const initial = computed(() => {
|
|
13
12
|
const fromInjection = unref(injection);
|
|
14
|
-
|
|
13
|
+
if (fromInjection === undefined || isNaN(fromInjection)) {
|
|
14
|
+
return initialZIndex;
|
|
15
|
+
}
|
|
16
|
+
return fromInjection;
|
|
15
17
|
});
|
|
16
18
|
|
|
17
19
|
const current = computed(() => {
|
|
@@ -28,4 +30,4 @@ export const useZIndex = (override?: Ref<number>) => {
|
|
|
28
30
|
current,
|
|
29
31
|
nextZIndex
|
|
30
32
|
}
|
|
31
|
-
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<MModal ref="modal" title="I am a modal" size="md" :canClickOutside="true" :canBounceOnOpen="false" :canSlideIn="true">
|
|
3
|
+
<template #body>
|
|
4
|
+
<div>
|
|
5
|
+
<MSelect
|
|
6
|
+
v-model="value"
|
|
7
|
+
:options="options"
|
|
8
|
+
:option-value="'id'"
|
|
9
|
+
:option-label="'name'"
|
|
10
|
+
blank
|
|
11
|
+
searchable
|
|
12
|
+
/>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
<template #footer>
|
|
16
|
+
<div style="display: flex; flex-grow: 1; justify-content: end;">
|
|
17
|
+
<MButton variant="primary" @click="modal?.close()">
|
|
18
|
+
Okay
|
|
19
|
+
</MButton>
|
|
20
|
+
<MButton style="margin-left: 8px;" @click="modal?.close()">
|
|
21
|
+
Cancel
|
|
22
|
+
</MButton>
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
25
|
+
</MModal>
|
|
26
|
+
|
|
27
|
+
<div style="position: relative; width: 100%; height: 1000px;">
|
|
28
|
+
<button @click="open" style="position: absolute; width: 100px; height: 50px; top: 0; left: 0;">Top Left</button>
|
|
29
|
+
<button @click="open" style="position: absolute; width: 100px; height: 50px; top: 0; right: 0;">Top Right</button>
|
|
30
|
+
<button @click="open" style="position: absolute; width: 100px; height: 50px; bottom: 0; left: 0;">Bottom
|
|
31
|
+
Left</button>
|
|
32
|
+
<button @click="open" style="position: absolute; width: 100px; height: 50px; bottom: 0; right: 0;">Bottom
|
|
33
|
+
Right</button>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script lang="ts" setup>
|
|
38
|
+
import { ref } from 'vue'
|
|
39
|
+
|
|
40
|
+
const modal = ref<any>(null);
|
|
41
|
+
// make list of options with 1000 items
|
|
42
|
+
const options = Array.from({ length: 50 }, (_, i) => ({
|
|
43
|
+
id: i,
|
|
44
|
+
name: `Option ${i+1}`
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
const value = ref();
|
|
48
|
+
const open = (event: MouseEvent) => {
|
|
49
|
+
modal.value.open(event.target);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
</script>
|