@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.
Files changed (47) hide show
  1. package/dist/{MMenuItem-COdgD4m7.js → MMenuItem-Dw2ARZic.js} +30 -24
  2. package/dist/{MMenuItem-COdgD4m7.js.map → MMenuItem-Dw2ARZic.js.map} +1 -1
  3. package/dist/components/MAutocomplete.vue.d.ts +2 -1
  4. package/dist/components/MColorPicker.vue.d.ts +2 -1
  5. package/dist/components/MContextMenu.vue.d.ts +7 -21
  6. package/dist/components/MDatePicker.vue.d.ts +2 -1
  7. package/dist/components/MDateRangePicker.vue.d.ts +2 -1
  8. package/dist/components/MMaskField.vue.d.ts +2 -1
  9. package/dist/components/MMenuDivider.vue.d.ts +3 -0
  10. package/dist/components/MMenuItem.vue.d.ts +1 -0
  11. package/dist/components/MMultiAutocomplete.vue.d.ts +2 -1
  12. package/dist/components/MMultiSelect.vue.d.ts +2 -1
  13. package/dist/components/MNumberField.vue.d.ts +2 -1
  14. package/dist/components/MSelect.vue.d.ts +2 -1
  15. package/dist/components/MTagInput.vue.d.ts +2 -1
  16. package/dist/components/MTextField.vue.d.ts +2 -1
  17. package/dist/components/MTimePicker.vue.d.ts +2 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/m3ui-vue.css +1 -1
  20. package/dist/m3ui.js +809 -877
  21. package/dist/m3ui.js.map +1 -1
  22. package/dist/rich-text-editor.js +1 -1
  23. package/dist/styles.css +1 -1
  24. package/package.json +1 -1
  25. package/src/components/MAbsolute.vue +3 -2
  26. package/src/components/MAutocomplete.vue +3 -2
  27. package/src/components/MCircleProgressBar.vue +7 -5
  28. package/src/components/MColorPicker.vue +3 -2
  29. package/src/components/MContextMenu.vue +51 -38
  30. package/src/components/MDatePicker.vue +3 -2
  31. package/src/components/MDateRangePicker.vue +3 -2
  32. package/src/components/MMaskField.vue +3 -2
  33. package/src/components/MMenuDivider.vue +3 -0
  34. package/src/components/MMenuItem.vue +2 -0
  35. package/src/components/MMultiAutocomplete.vue +3 -2
  36. package/src/components/MMultiSelect.vue +3 -2
  37. package/src/components/MNumberField.vue +3 -2
  38. package/src/components/MSelect.vue +3 -2
  39. package/src/components/MSlider.vue +20 -16
  40. package/src/components/MTabs.vue +1 -1
  41. package/src/components/MTagInput.vue +3 -2
  42. package/src/components/MTextField.vue +3 -2
  43. package/src/components/MTimePicker.vue +3 -2
  44. package/src/components/MWindow.vue +5 -5
  45. package/src/index.ts +1 -1
  46. package/dist/components/_MContextMenuPanel.vue.d.ts +0 -13
  47. 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?: string;
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">{{ error }}</p>
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?: string
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">{{ error }}</p>
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-[10px] right-[10px] h-[5px]', cursor: 'cursor-ns-resize' },
261
- { dir: 'e', class: 'top-[10px] right-0 bottom-[10px] w-[5px]', cursor: 'cursor-ew-resize' },
262
- { dir: 'w', class: 'top-[10px] left-0 bottom-[10px] w-[5px]', cursor: 'cursor-ew-resize' },
263
- { dir: 'se', class: 'bottom-0 right-0 w-[12px] h-[12px]', cursor: 'cursor-nwse-resize' },
264
- { dir: 'sw', class: 'bottom-0 left-0 w-[12px] h-[12px]', cursor: 'cursor-nesw-resize' },
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>