@m3ui-vue/m3ui-vue 0.5.0 → 0.5.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.
Files changed (36) hide show
  1. package/dist/{MMenuItem-Dw2ARZic.js → MMenuItem-DyY4zhRA.js} +217 -294
  2. package/dist/MMenuItem-DyY4zhRA.js.map +1 -0
  3. package/dist/code-editor.js +88 -74
  4. package/dist/code-editor.js.map +1 -1
  5. package/dist/components/MJsonEditor.vue.d.ts +7 -0
  6. package/dist/components/MJsonViewer.vue.d.ts +5 -0
  7. package/dist/composables/useLocale.d.ts +6 -0
  8. package/dist/locales/index.js +49 -7
  9. package/dist/locales/index.js.map +1 -1
  10. package/dist/m3ui-vue.css +1 -1
  11. package/dist/m3ui.js +1601 -1590
  12. package/dist/m3ui.js.map +1 -1
  13. package/dist/rich-text-editor.js +24 -23
  14. package/dist/rich-text-editor.js.map +1 -1
  15. package/dist/styles.css +1 -1
  16. package/dist/useLocale-QCIVDYWx.js +88 -0
  17. package/dist/useLocale-QCIVDYWx.js.map +1 -0
  18. package/package.json +1 -1
  19. package/src/components/MCircleProgressBar.vue +2 -2
  20. package/src/components/MCodeEditor.vue +1 -0
  21. package/src/components/MColorPicker.vue +1 -0
  22. package/src/components/MColorPickerModal.vue +1 -0
  23. package/src/components/MContextMenu.vue +6 -0
  24. package/src/components/MJsonEditor.vue +35 -9
  25. package/src/components/MJsonViewer.vue +17 -1
  26. package/src/components/MNotificationHost.vue +19 -5
  27. package/src/components/MSnackbar.vue +15 -5
  28. package/src/composables/useLocale.ts +18 -0
  29. package/src/locales/de.ts +10 -0
  30. package/src/locales/es.ts +10 -0
  31. package/src/locales/fr.ts +10 -0
  32. package/src/locales/ja.ts +10 -0
  33. package/src/locales/ko.ts +10 -0
  34. package/src/locales/pt.ts +10 -0
  35. package/src/locales/zh.ts +10 -0
  36. package/dist/MMenuItem-Dw2ARZic.js.map +0 -1
@@ -2,6 +2,16 @@
2
2
  import { ref, computed, watch } from 'vue'
3
3
  import MCodeEditor from './MCodeEditor.vue'
4
4
  import MIcon from './MIcon.vue'
5
+ import { useLocale } from '../composables/useLocale'
6
+
7
+ export interface JsonEditorLabels {
8
+ valid?: string
9
+ invalid?: string
10
+ format?: string
11
+ minify?: string
12
+ }
13
+
14
+ const locale = useLocale()
5
15
 
6
16
  const props = withDefaults(
7
17
  defineProps<{
@@ -9,6 +19,7 @@ const props = withDefaults(
9
19
  readonly?: boolean
10
20
  minHeight?: string
11
21
  maxHeight?: string
22
+ labels?: JsonEditorLabels
12
23
  }>(),
13
24
  {
14
25
  readonly: false,
@@ -17,6 +28,14 @@ const props = withDefaults(
17
28
  },
18
29
  )
19
30
 
31
+ const l = computed<Required<JsonEditorLabels>>(() => ({
32
+ valid: locale.jsonValid,
33
+ invalid: locale.jsonInvalid,
34
+ format: locale.jsonFormat,
35
+ minify: locale.jsonMinify,
36
+ ...props.labels,
37
+ }))
38
+
20
39
  const emit = defineEmits<{ 'update:modelValue': [unknown] }>()
21
40
 
22
41
  const rawText = ref(JSON.stringify(props.modelValue, null, 2))
@@ -25,11 +44,18 @@ const parseError = ref<string | null>(null)
25
44
  const isValid = computed(() => !parseError.value)
26
45
 
27
46
  watch(() => props.modelValue, (val) => {
28
- const incoming = JSON.stringify(val, null, 2)
29
- if (incoming !== rawText.value) {
30
- rawText.value = incoming
31
- parseError.value = null
47
+ let current: unknown
48
+ try {
49
+ current = JSON.parse(rawText.value)
50
+ } catch {
51
+ current = undefined
32
52
  }
53
+ // Only resync from outside when the actual data changed, not just its formatting —
54
+ // otherwise the round-trip from formatJson/minifyJson emitting would immediately
55
+ // overwrite the newly (re)formatted text with a pretty-printed copy.
56
+ if (JSON.stringify(current) === JSON.stringify(val)) return
57
+ rawText.value = JSON.stringify(val, null, 2)
58
+ parseError.value = null
33
59
  })
34
60
 
35
61
  function onTextUpdate(text: string) {
@@ -84,28 +110,28 @@ function minifyJson() {
84
110
  :class="isValid ? 'bg-success-container text-on-success-container' : 'bg-error-container text-on-error-container'"
85
111
  >
86
112
  <MIcon :name="isValid ? 'check_circle' : 'error'" :size="14" />
87
- {{ isValid ? 'Válido' : 'Inválido' }}
113
+ {{ isValid ? l.valid : l.invalid }}
88
114
  </span>
89
115
 
90
116
  <button
91
117
  v-if="!readonly"
92
118
  type="button"
93
- title="Formatear"
119
+ :title="l.format"
94
120
  class="flex h-7 cursor-pointer items-center gap-1 rounded px-2 text-label-medium text-on-surface-variant transition-colors hover:bg-on-surface/8"
95
121
  @click="formatJson"
96
122
  >
97
123
  <MIcon name="format_indent_increase" :size="16" />
98
- Formatear
124
+ {{ l.format }}
99
125
  </button>
100
126
  <button
101
127
  v-if="!readonly"
102
128
  type="button"
103
- title="Minificar"
129
+ :title="l.minify"
104
130
  class="flex h-7 cursor-pointer items-center gap-1 rounded px-2 text-label-medium text-on-surface-variant transition-colors hover:bg-on-surface/8"
105
131
  @click="minifyJson"
106
132
  >
107
133
  <MIcon name="compress" :size="16" />
108
- Minificar
134
+ {{ l.minify }}
109
135
  </button>
110
136
  </div>
111
137
  </template>
@@ -1,18 +1,33 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, computed } from 'vue'
3
3
  import MIcon from './MIcon.vue'
4
+ import { useLocale } from '../composables/useLocale'
5
+
6
+ export interface JsonViewerLabels {
7
+ elements?: string
8
+ fields?: string
9
+ }
10
+
11
+ const locale = useLocale()
4
12
 
5
13
  const props = withDefaults(
6
14
  defineProps<{
7
15
  data: unknown
8
16
  rootName?: string
9
17
  expandDepth?: number
18
+ labels?: JsonViewerLabels
10
19
  /** @internal — used by recursive instances */
11
20
  _depth?: number
12
21
  }>(),
13
22
  { rootName: 'root', expandDepth: 2, _depth: 0 },
14
23
  )
15
24
 
25
+ const l = computed<Required<JsonViewerLabels>>(() => ({
26
+ elements: locale.jsonElements,
27
+ fields: locale.jsonFields,
28
+ ...props.labels,
29
+ }))
30
+
16
31
  const expanded = ref(props._depth < props.expandDepth)
17
32
 
18
33
  const dataType = computed(() => {
@@ -73,7 +88,7 @@ function formatValue(val: unknown) {
73
88
  <span v-if="_depth === 0 || rootName" class="text-tertiary">{{ _depth === 0 ? rootName : '' }}</span>
74
89
  <span class="text-on-surface-variant">{{ bracketOpen }}</span>
75
90
  <span v-if="!expanded" class="text-on-surface-variant/60">
76
- {{ childCount }} {{ dataType === 'array' ? 'elementos' : 'campos' }}
91
+ {{ childCount }} {{ dataType === 'array' ? l.elements : l.fields }}
77
92
  </span>
78
93
  <span v-if="!expanded" class="text-on-surface-variant">{{ bracketClose }}</span>
79
94
  </button>
@@ -89,6 +104,7 @@ function formatValue(val: unknown) {
89
104
  :data="entry.value"
90
105
  :root-name="entry.key"
91
106
  :expand-depth="expandDepth"
107
+ :labels="labels"
92
108
  :_depth="_depth + 1"
93
109
  />
94
110
  <!-- Primitive value -->
@@ -53,7 +53,7 @@ const getStyle = (variant: string) => variantStyles[variant] ?? variantStyles.in
53
53
  <Transition name="m3-badge">
54
54
  <span
55
55
  v-if="n.count >= 2"
56
- class="absolute -top-1.5 -right-1.5 z-10 flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold leading-none text-on-primary shadow-elevation-1"
56
+ class="notif-count-badge absolute -top-1.5 -right-1.5 z-10 flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold leading-none text-on-primary shadow-elevation-1"
57
57
  >
58
58
  <Transition name="m3-count" mode="out-in">
59
59
  <span :key="n.count">{{ n.count }}</span>
@@ -110,10 +110,10 @@ const getStyle = (variant: string) => variantStyles[variant] ?? variantStyles.in
110
110
 
111
111
  .m3-notif-bot-enter-active {
112
112
  transition: grid-template-rows 200ms ease, padding-bottom 200ms ease;
113
- overflow: hidden;
114
113
  }
115
114
  .m3-notif-bot-enter-active > .notif-inner {
116
115
  transition: opacity 150ms ease, transform 200ms ease;
116
+ overflow: hidden;
117
117
  }
118
118
  .m3-notif-bot-enter-from {
119
119
  grid-template-rows: 0fr;
@@ -126,10 +126,10 @@ const getStyle = (variant: string) => variantStyles[variant] ?? variantStyles.in
126
126
 
127
127
  .m3-notif-bot-leave-active {
128
128
  transition: grid-template-rows 250ms ease, padding-bottom 250ms ease;
129
- overflow: hidden;
130
129
  }
131
130
  .m3-notif-bot-leave-active > .notif-inner {
132
131
  transition: opacity 150ms ease, transform 150ms ease;
132
+ overflow: hidden;
133
133
  }
134
134
  .m3-notif-bot-leave-to {
135
135
  grid-template-rows: 0fr;
@@ -139,13 +139,20 @@ const getStyle = (variant: string) => variantStyles[variant] ?? variantStyles.in
139
139
  opacity: 0;
140
140
  transform: scale(0.93);
141
141
  }
142
+ .m3-notif-bot-leave-active > .notif-count-badge {
143
+ transition: opacity 150ms ease, transform 150ms ease;
144
+ }
145
+ .m3-notif-bot-leave-to > .notif-count-badge {
146
+ opacity: 0;
147
+ transform: scale(0.5);
148
+ }
142
149
 
143
150
  .m3-notif-top-enter-active {
144
151
  transition: grid-template-rows 200ms ease, padding-bottom 200ms ease;
145
- overflow: hidden;
146
152
  }
147
153
  .m3-notif-top-enter-active > .notif-inner {
148
154
  transition: opacity 150ms ease, transform 200ms ease;
155
+ overflow: hidden;
149
156
  }
150
157
  .m3-notif-top-enter-from {
151
158
  grid-template-rows: 0fr;
@@ -158,10 +165,10 @@ const getStyle = (variant: string) => variantStyles[variant] ?? variantStyles.in
158
165
 
159
166
  .m3-notif-top-leave-active {
160
167
  transition: grid-template-rows 250ms ease, padding-bottom 250ms ease;
161
- overflow: hidden;
162
168
  }
163
169
  .m3-notif-top-leave-active > .notif-inner {
164
170
  transition: opacity 150ms ease, transform 150ms ease;
171
+ overflow: hidden;
165
172
  }
166
173
  .m3-notif-top-leave-to {
167
174
  grid-template-rows: 0fr;
@@ -171,6 +178,13 @@ const getStyle = (variant: string) => variantStyles[variant] ?? variantStyles.in
171
178
  opacity: 0;
172
179
  transform: scale(0.93);
173
180
  }
181
+ .m3-notif-top-leave-active > .notif-count-badge {
182
+ transition: opacity 150ms ease, transform 150ms ease;
183
+ }
184
+ .m3-notif-top-leave-to > .notif-count-badge {
185
+ opacity: 0;
186
+ transform: scale(0.5);
187
+ }
174
188
 
175
189
  .m3-badge-enter-active { transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1); }
176
190
  .m3-badge-leave-active { transition: opacity 0.15s ease, transform 0.15s ease; }
@@ -94,7 +94,7 @@ const getVariantStyle = (variant: string): VariantStyle =>
94
94
  <Transition name="m3-badge">
95
95
  <span
96
96
  v-if="t.count >= 2"
97
- class="absolute -top-1.5 -right-1.5 z-10 flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold leading-none text-on-primary shadow-elevation-1"
97
+ class="toast-count-badge absolute -top-1.5 -right-1.5 z-10 flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold leading-none text-on-primary shadow-elevation-1"
98
98
  >
99
99
  <Transition name="m3-count" mode="out-in">
100
100
  <span :key="t.count">{{ t.count }}</span>
@@ -178,7 +178,6 @@ const getVariantStyle = (variant: string): VariantStyle =>
178
178
  transition:
179
179
  grid-template-rows 220ms cubic-bezier(0.2, 0, 0, 1),
180
180
  padding-bottom 220ms cubic-bezier(0.2, 0, 0, 1);
181
- overflow: hidden;
182
181
  }
183
182
  .m3-toast-bot-enter-active > .toast-inner {
184
183
  transition:
@@ -198,7 +197,6 @@ const getVariantStyle = (variant: string): VariantStyle =>
198
197
  transition:
199
198
  grid-template-rows 300ms cubic-bezier(0.2, 0, 0, 1),
200
199
  padding-bottom 300ms cubic-bezier(0.2, 0, 0, 1);
201
- overflow: hidden;
202
200
  }
203
201
  .m3-toast-bot-leave-active > .toast-inner {
204
202
  transition:
@@ -213,13 +211,19 @@ const getVariantStyle = (variant: string): VariantStyle =>
213
211
  opacity: 0;
214
212
  transform: scale(0.92);
215
213
  }
214
+ .m3-toast-bot-leave-active > .toast-count-badge {
215
+ transition: opacity 150ms ease, transform 150ms ease;
216
+ }
217
+ .m3-toast-bot-leave-to > .toast-count-badge {
218
+ opacity: 0;
219
+ transform: scale(0.5);
220
+ }
216
221
 
217
222
  /* ─── Top toasts ────────────────────────────────────────────────── */
218
223
  .m3-toast-top-enter-active {
219
224
  transition:
220
225
  grid-template-rows 220ms cubic-bezier(0.2, 0, 0, 1),
221
226
  padding-bottom 220ms cubic-bezier(0.2, 0, 0, 1);
222
- overflow: hidden;
223
227
  }
224
228
  .m3-toast-top-enter-active > .toast-inner {
225
229
  transition:
@@ -239,7 +243,6 @@ const getVariantStyle = (variant: string): VariantStyle =>
239
243
  transition:
240
244
  grid-template-rows 300ms cubic-bezier(0.2, 0, 0, 1),
241
245
  padding-bottom 300ms cubic-bezier(0.2, 0, 0, 1);
242
- overflow: hidden;
243
246
  }
244
247
  .m3-toast-top-leave-active > .toast-inner {
245
248
  transition:
@@ -254,6 +257,13 @@ const getVariantStyle = (variant: string): VariantStyle =>
254
257
  opacity: 0;
255
258
  transform: scale(0.92);
256
259
  }
260
+ .m3-toast-top-leave-active > .toast-count-badge {
261
+ transition: opacity 150ms ease, transform 150ms ease;
262
+ }
263
+ .m3-toast-top-leave-to > .toast-count-badge {
264
+ opacity: 0;
265
+ transform: scale(0.5);
266
+ }
257
267
 
258
268
  /* badge appear/disappear */
259
269
  .m3-badge-enter-active { transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1); }
@@ -90,6 +90,16 @@ export interface M3Locale {
90
90
  insertImage: string
91
91
  imageUrlLabel: string
92
92
  insert: string
93
+
94
+ // JSON editor
95
+ jsonValid: string
96
+ jsonInvalid: string
97
+ jsonFormat: string
98
+ jsonMinify: string
99
+
100
+ // JSON viewer
101
+ jsonElements: string
102
+ jsonFields: string
93
103
  }
94
104
 
95
105
  export const defaultLocale: M3Locale = {
@@ -171,6 +181,14 @@ export const defaultLocale: M3Locale = {
171
181
  insertImage: 'Insert image',
172
182
  imageUrlLabel: 'Image URL',
173
183
  insert: 'Insert',
184
+
185
+ jsonValid: 'Valid',
186
+ jsonInvalid: 'Invalid',
187
+ jsonFormat: 'Format',
188
+ jsonMinify: 'Minify',
189
+
190
+ jsonElements: 'elements',
191
+ jsonFields: 'fields',
174
192
  }
175
193
 
176
194
  export const M3_LOCALE_KEY: InjectionKey<MaybeRef<Partial<M3Locale>>> = Symbol('m3-locale')
package/src/locales/de.ts CHANGED
@@ -90,4 +90,14 @@ export const deLocale: M3Locale = {
90
90
  insertImage: 'Bild einfügen',
91
91
  imageUrlLabel: 'Bild-URL',
92
92
  insert: 'Einfügen',
93
+
94
+ // JSON editor
95
+ jsonValid: 'Gültig',
96
+ jsonInvalid: 'Ungültig',
97
+ jsonFormat: 'Formatieren',
98
+ jsonMinify: 'Minimieren',
99
+
100
+ // JSON viewer
101
+ jsonElements: 'Elemente',
102
+ jsonFields: 'Felder',
93
103
  }
package/src/locales/es.ts CHANGED
@@ -90,4 +90,14 @@ export const esLocale: M3Locale = {
90
90
  insertImage: 'Insertar imagen',
91
91
  imageUrlLabel: 'URL de la imagen',
92
92
  insert: 'Insertar',
93
+
94
+ // JSON editor
95
+ jsonValid: 'Válido',
96
+ jsonInvalid: 'Inválido',
97
+ jsonFormat: 'Formatear',
98
+ jsonMinify: 'Minificar',
99
+
100
+ // JSON viewer
101
+ jsonElements: 'elementos',
102
+ jsonFields: 'campos',
93
103
  }
package/src/locales/fr.ts CHANGED
@@ -90,4 +90,14 @@ export const frLocale: M3Locale = {
90
90
  insertImage: 'Insérer une image',
91
91
  imageUrlLabel: "URL de l'image",
92
92
  insert: 'Insérer',
93
+
94
+ // JSON editor
95
+ jsonValid: 'Valide',
96
+ jsonInvalid: 'Invalide',
97
+ jsonFormat: 'Formater',
98
+ jsonMinify: 'Minifier',
99
+
100
+ // JSON viewer
101
+ jsonElements: 'éléments',
102
+ jsonFields: 'champs',
93
103
  }
package/src/locales/ja.ts CHANGED
@@ -90,4 +90,14 @@ export const jaLocale: M3Locale = {
90
90
  insertImage: '画像を挿入',
91
91
  imageUrlLabel: '画像 URL',
92
92
  insert: '挿入',
93
+
94
+ // JSON editor
95
+ jsonValid: '有効',
96
+ jsonInvalid: '無効',
97
+ jsonFormat: '整形',
98
+ jsonMinify: '圧縮',
99
+
100
+ // JSON viewer
101
+ jsonElements: '要素',
102
+ jsonFields: 'フィールド',
93
103
  }
package/src/locales/ko.ts CHANGED
@@ -90,4 +90,14 @@ export const koLocale: M3Locale = {
90
90
  insertImage: '이미지 삽입',
91
91
  imageUrlLabel: '이미지 URL',
92
92
  insert: '삽입',
93
+
94
+ // JSON editor
95
+ jsonValid: '유효함',
96
+ jsonInvalid: '유효하지 않음',
97
+ jsonFormat: '서식 지정',
98
+ jsonMinify: '압축',
99
+
100
+ // JSON viewer
101
+ jsonElements: '요소',
102
+ jsonFields: '필드',
93
103
  }
package/src/locales/pt.ts CHANGED
@@ -90,4 +90,14 @@ export const ptLocale: M3Locale = {
90
90
  insertImage: 'Inserir imagem',
91
91
  imageUrlLabel: 'URL da imagem',
92
92
  insert: 'Inserir',
93
+
94
+ // JSON editor
95
+ jsonValid: 'Válido',
96
+ jsonInvalid: 'Inválido',
97
+ jsonFormat: 'Formatar',
98
+ jsonMinify: 'Minificar',
99
+
100
+ // JSON viewer
101
+ jsonElements: 'elementos',
102
+ jsonFields: 'campos',
93
103
  }
package/src/locales/zh.ts CHANGED
@@ -90,4 +90,14 @@ export const zhLocale: M3Locale = {
90
90
  insertImage: '插入图片',
91
91
  imageUrlLabel: '图片 URL',
92
92
  insert: '插入',
93
+
94
+ // JSON editor
95
+ jsonValid: '有效',
96
+ jsonInvalid: '无效',
97
+ jsonFormat: '格式化',
98
+ jsonMinify: '压缩',
99
+
100
+ // JSON viewer
101
+ jsonElements: '个元素',
102
+ jsonFields: '个字段',
93
103
  }