@m3ui-vue/m3ui-vue 0.4.7 → 0.5.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/dist/{MMenuItem-COdgD4m7.js → MMenuItem-Dw2ARZic.js} +30 -24
- package/dist/{MMenuItem-COdgD4m7.js.map → MMenuItem-Dw2ARZic.js.map} +1 -1
- package/dist/components/MAutocomplete.vue.d.ts +2 -1
- package/dist/components/MColorPicker.vue.d.ts +2 -1
- package/dist/components/MContextMenu.vue.d.ts +7 -21
- package/dist/components/MDatePicker.vue.d.ts +2 -1
- package/dist/components/MDateRangePicker.vue.d.ts +2 -1
- package/dist/components/MMaskField.vue.d.ts +2 -1
- package/dist/components/MMenuDivider.vue.d.ts +3 -0
- package/dist/components/MMenuItem.vue.d.ts +1 -0
- package/dist/components/MMultiAutocomplete.vue.d.ts +2 -1
- package/dist/components/MMultiSelect.vue.d.ts +2 -1
- package/dist/components/MNumberField.vue.d.ts +2 -1
- package/dist/components/MSelect.vue.d.ts +2 -1
- package/dist/components/MTagInput.vue.d.ts +2 -1
- package/dist/components/MTextField.vue.d.ts +2 -1
- package/dist/components/MTimePicker.vue.d.ts +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/m3ui-vue.css +1 -1
- package/dist/m3ui.js +809 -877
- package/dist/m3ui.js.map +1 -1
- package/dist/rich-text-editor.js +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/components/MAbsolute.vue +3 -2
- package/src/components/MAutocomplete.vue +3 -2
- package/src/components/MCircleProgressBar.vue +7 -5
- package/src/components/MColorPicker.vue +3 -2
- package/src/components/MContextMenu.vue +51 -38
- package/src/components/MDatePicker.vue +3 -2
- package/src/components/MDateRangePicker.vue +3 -2
- package/src/components/MMaskField.vue +3 -2
- package/src/components/MMenuDivider.vue +3 -0
- package/src/components/MMenuItem.vue +2 -0
- package/src/components/MMultiAutocomplete.vue +3 -2
- package/src/components/MMultiSelect.vue +3 -2
- package/src/components/MNumberField.vue +3 -2
- package/src/components/MSelect.vue +3 -2
- package/src/components/MSlider.vue +20 -16
- package/src/components/MTabs.vue +1 -1
- package/src/components/MTagInput.vue +3 -2
- package/src/components/MTextField.vue +3 -2
- package/src/components/MTimePicker.vue +3 -2
- package/src/components/MWindow.vue +5 -5
- package/src/index.ts +1 -1
- package/dist/components/_MContextMenuPanel.vue.d.ts +0 -13
- package/src/components/_MContextMenuPanel.vue +0 -137
|
@@ -10,7 +10,8 @@ const props = withDefaults(
|
|
|
10
10
|
label: string;
|
|
11
11
|
type?: string;
|
|
12
12
|
variant?: "filled" | "outlined";
|
|
13
|
-
error?:
|
|
13
|
+
error?: boolean;
|
|
14
|
+
errorLabel?: string;
|
|
14
15
|
hint?: string;
|
|
15
16
|
disabled?: boolean;
|
|
16
17
|
required?: boolean;
|
|
@@ -188,7 +189,7 @@ function onInput(event: Event) {
|
|
|
188
189
|
</button>
|
|
189
190
|
</div>
|
|
190
191
|
|
|
191
|
-
<p v-if="error" class="px-4 text-body-small text-error">{{
|
|
192
|
+
<p v-if="error && errorLabel" class="px-4 text-body-small text-error">{{ errorLabel }}</p>
|
|
192
193
|
<p v-else-if="hint" class="px-4 text-body-small text-on-surface-variant">{{ hint }}</p>
|
|
193
194
|
</div>
|
|
194
195
|
</template>
|
|
@@ -9,7 +9,8 @@ const props = withDefaults(defineProps<{
|
|
|
9
9
|
label?: string
|
|
10
10
|
placeholder?: string
|
|
11
11
|
disabled?: boolean
|
|
12
|
-
error?:
|
|
12
|
+
error?: boolean
|
|
13
|
+
errorLabel?: string
|
|
13
14
|
hint?: string
|
|
14
15
|
minuteStep?: number
|
|
15
16
|
use24h?: boolean
|
|
@@ -148,7 +149,7 @@ onUnmounted(() => {
|
|
|
148
149
|
</label>
|
|
149
150
|
</div>
|
|
150
151
|
|
|
151
|
-
<p v-if="error" class="px-4 text-body-small text-error">{{
|
|
152
|
+
<p v-if="error && errorLabel" class="px-4 text-body-small text-error">{{ errorLabel }}</p>
|
|
152
153
|
<p v-else-if="hint" class="px-4 text-body-small text-on-surface-variant">{{ hint }}</p>
|
|
153
154
|
|
|
154
155
|
<Teleport to="body">
|
|
@@ -257,11 +257,11 @@ onUnmounted(() => {
|
|
|
257
257
|
|
|
258
258
|
// Resize handle definitions
|
|
259
259
|
const resizeHandles: { dir: ResizeDirection; class: string; cursor: string }[] = [
|
|
260
|
-
{ dir: 's', class: 'bottom-0 left-[
|
|
261
|
-
{ dir: 'e', class: 'top-[
|
|
262
|
-
{ dir: 'w', class: 'top-[
|
|
263
|
-
{ dir: 'se', class: 'bottom-0 right-0 w-[
|
|
264
|
-
{ dir: 'sw', class: 'bottom-0 left-0 w-[
|
|
260
|
+
{ dir: 's', class: 'bottom-0 left-[20px] right-[20px] h-[8px]', cursor: 'cursor-ns-resize' },
|
|
261
|
+
{ dir: 'e', class: 'top-[20px] right-0 bottom-[20px] w-[8px]', cursor: 'cursor-ew-resize' },
|
|
262
|
+
{ dir: 'w', class: 'top-[20px] left-0 bottom-[20px] w-[8px]', cursor: 'cursor-ew-resize' },
|
|
263
|
+
{ dir: 'se', class: 'bottom-0 right-0 w-[20px] h-[20px]', cursor: 'cursor-nwse-resize' },
|
|
264
|
+
{ dir: 'sw', class: 'bottom-0 left-0 w-[20px] h-[20px]', cursor: 'cursor-nesw-resize' },
|
|
265
265
|
]
|
|
266
266
|
</script>
|
|
267
267
|
|
package/src/index.ts
CHANGED
|
@@ -81,6 +81,7 @@ export { default as MLoadingOverlay } from './components/MLoadingOverlay.vue'
|
|
|
81
81
|
// MMarkdown — import from '@m3ui-vue/m3ui-vue/markdown'
|
|
82
82
|
export { default as MMasonry } from './components/MMasonry.vue'
|
|
83
83
|
export { default as MMenu } from './components/MMenu.vue'
|
|
84
|
+
export { default as MMenuDivider } from './components/MMenuDivider.vue'
|
|
84
85
|
export { default as MMenuItem } from './components/MMenuItem.vue'
|
|
85
86
|
export { default as MMaskField } from './components/MMaskField.vue'
|
|
86
87
|
export type { MaskPreset } from './components/MMaskField.vue'
|
|
@@ -151,7 +152,6 @@ export type { Placement } from './components/MAbsolute.vue'
|
|
|
151
152
|
export type { BadgePosition, BadgeOverlap } from './components/MBadge.vue'
|
|
152
153
|
export type { CalendarEvent } from './components/MCalendar.vue'
|
|
153
154
|
export type { CarouselItem } from './components/MCarousel.vue'
|
|
154
|
-
export type { ContextMenuItem } from './components/MContextMenu.vue'
|
|
155
155
|
export type { DataTableColumn, DataTableFetchParams } from './components/MDataTable.vue'
|
|
156
156
|
export type { DateRange } from './components/MDateRangePicker.vue'
|
|
157
157
|
export type { DragDropItem } from './components/MDragDropList.vue'
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { ContextMenuItem } from "./MContextMenu.vue";
|
|
2
|
-
type __VLS_Props = {
|
|
3
|
-
items: ContextMenuItem[];
|
|
4
|
-
x: number;
|
|
5
|
-
y: number;
|
|
6
|
-
};
|
|
7
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
-
close: () => any;
|
|
9
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
-
onClose?: (() => any) | undefined;
|
|
11
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
-
declare const _default: typeof __VLS_export;
|
|
13
|
-
export default _default;
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted, nextTick } from "vue";
|
|
3
|
-
import MIcon from "./MIcon.vue";
|
|
4
|
-
import MContextMenuPanel from "./_MContextMenuPanel.vue";
|
|
5
|
-
import type { ContextMenuItem } from "./MContextMenu.vue";
|
|
6
|
-
|
|
7
|
-
const props = defineProps<{
|
|
8
|
-
items: ContextMenuItem[];
|
|
9
|
-
x: number;
|
|
10
|
-
y: number;
|
|
11
|
-
}>();
|
|
12
|
-
|
|
13
|
-
const emit = defineEmits<{ close: [] }>();
|
|
14
|
-
|
|
15
|
-
const panel = ref<HTMLElement | null>(null);
|
|
16
|
-
const panelX = ref(props.x);
|
|
17
|
-
const panelY = ref(props.y);
|
|
18
|
-
const activeIndex = ref<number | null>(null);
|
|
19
|
-
const subPos = ref({ x: 0, y: 0 });
|
|
20
|
-
|
|
21
|
-
onMounted(async () => {
|
|
22
|
-
await nextTick();
|
|
23
|
-
if (!panel.value) return;
|
|
24
|
-
const el = panel.value;
|
|
25
|
-
panelX.value = Math.min(props.x, window.innerWidth - el.offsetWidth - 8);
|
|
26
|
-
panelY.value = Math.min(props.y, window.innerHeight - el.offsetHeight - 8);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
function onItemMouseEnter(index: number, item: ContextMenuItem, e: MouseEvent) {
|
|
30
|
-
if (item.divider || item.disabled) {
|
|
31
|
-
activeIndex.value = null;
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
if (!item.children?.length) {
|
|
35
|
-
activeIndex.value = null;
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
activeIndex.value = index;
|
|
40
|
-
const itemEl = e.currentTarget as HTMLElement;
|
|
41
|
-
const itemRect = itemEl.getBoundingClientRect();
|
|
42
|
-
const panelRect = panel.value!.getBoundingClientRect();
|
|
43
|
-
|
|
44
|
-
let x = panelRect.right;
|
|
45
|
-
let y = itemRect.top;
|
|
46
|
-
if (x + 220 > window.innerWidth) x = panelRect.left - 220;
|
|
47
|
-
if (y + 300 > window.innerHeight) y = Math.max(8, window.innerHeight - 300);
|
|
48
|
-
|
|
49
|
-
subPos.value = { x, y };
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function onItemClick(item: ContextMenuItem) {
|
|
53
|
-
if (item.disabled || item.divider || item.children?.length) return;
|
|
54
|
-
item.onClick?.();
|
|
55
|
-
emit("close");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function onPanelMouseLeave(e: MouseEvent) {
|
|
59
|
-
// Don't close if the mouse moved to another context menu panel (sibling sub-panel)
|
|
60
|
-
const related = e.relatedTarget as Element | null;
|
|
61
|
-
if (related?.closest(".m3-ctx-panel")) return;
|
|
62
|
-
activeIndex.value = null;
|
|
63
|
-
}
|
|
64
|
-
</script>
|
|
65
|
-
|
|
66
|
-
<template>
|
|
67
|
-
<div
|
|
68
|
-
ref="panel"
|
|
69
|
-
class="m3-ctx-panel absolute z-201 min-w-[200px] overflow-hidden rounded-lg bg-surface-container shadow-elevation-2"
|
|
70
|
-
:style="{ left: `${panelX}px`, top: `${panelY}px` }"
|
|
71
|
-
@mouseleave="onPanelMouseLeave"
|
|
72
|
-
>
|
|
73
|
-
<div class="py-1">
|
|
74
|
-
<template v-for="(item, i) in items" :key="i">
|
|
75
|
-
<hr v-if="item.divider" class="my-1 border-outline-variant" />
|
|
76
|
-
|
|
77
|
-
<component
|
|
78
|
-
v-else
|
|
79
|
-
:is="item.to && !item.disabled ? 'RouterLink' : 'div'"
|
|
80
|
-
:to="item.to && !item.disabled ? item.to : undefined"
|
|
81
|
-
class="relative flex cursor-default select-none items-center gap-3 px-4 py-2.5 text-body-large"
|
|
82
|
-
:class="[
|
|
83
|
-
item.disabled
|
|
84
|
-
? 'cursor-not-allowed opacity-38 text-on-surface'
|
|
85
|
-
: item.danger
|
|
86
|
-
? 'cursor-pointer text-error hover:bg-error/8'
|
|
87
|
-
: 'cursor-pointer text-on-surface hover:bg-on-surface/8',
|
|
88
|
-
activeIndex === i && !item.disabled
|
|
89
|
-
? item.danger
|
|
90
|
-
? 'bg-error/8'
|
|
91
|
-
: 'bg-on-surface/8'
|
|
92
|
-
: '',
|
|
93
|
-
]"
|
|
94
|
-
@mouseenter="onItemMouseEnter(i, item, $event)"
|
|
95
|
-
@click="onItemClick(item)"
|
|
96
|
-
>
|
|
97
|
-
<MIcon
|
|
98
|
-
v-if="item.icon"
|
|
99
|
-
:name="item.icon"
|
|
100
|
-
:size="18"
|
|
101
|
-
class="shrink-0"
|
|
102
|
-
:class="item.danger ? 'text-error' : 'text-on-surface-variant'"
|
|
103
|
-
/>
|
|
104
|
-
<span v-else class="w-[18px] shrink-0" />
|
|
105
|
-
|
|
106
|
-
<span class="flex-1">{{ item.label }}</span>
|
|
107
|
-
|
|
108
|
-
<span
|
|
109
|
-
v-if="item.shortcut"
|
|
110
|
-
class="text-label-small text-on-surface-variant"
|
|
111
|
-
>
|
|
112
|
-
{{ item.shortcut }}
|
|
113
|
-
</span>
|
|
114
|
-
|
|
115
|
-
<MIcon
|
|
116
|
-
v-if="item.children?.length"
|
|
117
|
-
name="chevron_right"
|
|
118
|
-
:size="18"
|
|
119
|
-
class="shrink-0 text-on-surface-variant"
|
|
120
|
-
/>
|
|
121
|
-
</component>
|
|
122
|
-
</template>
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
|
-
|
|
126
|
-
<!-- Sub-panel: sibling in the same Teleport layer.
|
|
127
|
-
No <Transition> wrapper — MContextMenuPanel is a fragment and cannot be
|
|
128
|
-
animated by Vue's Transition (produces a console warning). -->
|
|
129
|
-
<MContextMenuPanel
|
|
130
|
-
v-if="activeIndex !== null && items[activeIndex]?.children?.length"
|
|
131
|
-
:key="activeIndex"
|
|
132
|
-
:items="items[activeIndex]!.children!"
|
|
133
|
-
:x="subPos.x"
|
|
134
|
-
:y="subPos.y"
|
|
135
|
-
@close="emit('close')"
|
|
136
|
-
/>
|
|
137
|
-
</template>
|