@m3ui-vue/m3ui-vue 0.2.0 → 0.2.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.
- package/dist/{MMenuItem-CIDblhtb.js → MMenuItem-DpoEsH91.js} +195 -114
- package/dist/MMenuItem-DpoEsH91.js.map +1 -0
- package/dist/components/MAlert.vue.d.ts +1 -0
- package/dist/components/MButton.vue.d.ts +1 -1
- package/dist/components/MCalendar.vue.d.ts +3 -0
- package/dist/components/MChip.vue.d.ts +3 -3
- package/dist/components/MCommandPalette.vue.d.ts +3 -2
- package/dist/components/MConfirmDialog.vue.d.ts +0 -2
- package/dist/components/MDataTable.vue.d.ts +8 -2
- package/dist/components/MDatePicker.vue.d.ts +2 -0
- package/dist/components/MDateRangePicker.vue.d.ts +5 -0
- package/dist/components/MDialog.vue.d.ts +1 -0
- package/dist/components/MFileUpload.vue.d.ts +15 -1
- package/dist/components/MInfiniteScroll.vue.d.ts +7 -5
- package/dist/components/MMultiSelect.vue.d.ts +13 -1
- package/dist/components/MRichTextEditor.vue.d.ts +28 -1
- package/dist/components/MScheduler.vue.d.ts +5 -0
- package/dist/components/MSnackbar.vue.d.ts +4 -1
- package/dist/components/MSpinner.vue.d.ts +1 -0
- package/dist/components/MSpotlightSearch.vue.d.ts +3 -2
- package/dist/components/MTable.vue.d.ts +2 -1
- package/dist/components/MTimePicker.vue.d.ts +1 -0
- package/dist/components/MTour.vue.d.ts +3 -0
- package/dist/components/MTransferList.vue.d.ts +19 -3
- package/dist/components/MTree.vue.d.ts +1 -1
- package/dist/composables/useLocale.d.ts +74 -0
- package/dist/index.d.ts +2 -0
- package/dist/locales/de.d.ts +2 -0
- package/dist/locales/es.d.ts +2 -0
- package/dist/locales/fr.d.ts +2 -0
- package/dist/locales/index.d.ts +8 -0
- package/dist/locales/index.js +489 -0
- package/dist/locales/index.js.map +1 -0
- package/dist/locales/ja.d.ts +2 -0
- package/dist/locales/ko.d.ts +2 -0
- package/dist/locales/pt.d.ts +2 -0
- package/dist/locales/zh.d.ts +2 -0
- package/dist/m3ui-vue.css +1 -1
- package/dist/m3ui.js +2734 -2647
- package/dist/m3ui.js.map +1 -1
- package/dist/plugin.d.ts +3 -1
- package/dist/rich-text-editor.d.ts +1 -0
- package/dist/rich-text-editor.js +141 -113
- package/dist/rich-text-editor.js.map +1 -1
- package/dist/styles/palettes.css +660 -0
- package/dist/styles.css +1 -1
- package/package.json +11 -2
- package/src/__tests__/MAlert.test.ts +59 -0
- package/src/__tests__/MConfirmDialog.test.ts +51 -0
- package/src/__tests__/MDialog.test.ts +58 -0
- package/src/__tests__/MSpinner.test.ts +37 -0
- package/src/__tests__/localePresets.test.ts +45 -0
- package/src/__tests__/plugin.test.ts +27 -0
- package/src/__tests__/setup.ts +11 -0
- package/src/__tests__/useColorPalette.test.ts +71 -0
- package/src/__tests__/useLocale.test.ts +50 -0
- package/src/__tests__/useTheme.test.ts +61 -0
- package/src/components/MAlert.vue +5 -1
- package/src/components/MCalendar.vue +14 -5
- package/src/components/MCommandPalette.vue +11 -7
- package/src/components/MConfirmDialog.vue +6 -5
- package/src/components/MDataTable.vue +18 -9
- package/src/components/MDatePicker.vue +11 -4
- package/src/components/MDateRangePicker.vue +15 -5
- package/src/components/MDialog.vue +5 -1
- package/src/components/MFileUpload.vue +22 -10
- package/src/components/MInfiniteScroll.vue +14 -9
- package/src/components/MMultiSelect.vue +11 -7
- package/src/components/MRichTextEditor.vue +95 -34
- package/src/components/MScheduler.vue +12 -4
- package/src/components/MSnackbar.vue +8 -1
- package/src/components/MSpinner.vue +5 -1
- package/src/components/MSpotlightSearch.vue +11 -7
- package/src/components/MTable.vue +8 -4
- package/src/components/MTimePicker.vue +5 -1
- package/src/components/MTour.vue +12 -9
- package/src/components/MTransferList.vue +30 -15
- package/src/composables/useColorPalette.ts +30 -20
- package/src/composables/useLocale.ts +181 -0
- package/src/index.ts +2 -0
- package/src/locales/de.ts +93 -0
- package/src/locales/es.ts +93 -0
- package/src/locales/fr.ts +93 -0
- package/src/locales/index.ts +8 -0
- package/src/locales/ja.ts +93 -0
- package/src/locales/ko.ts +93 -0
- package/src/locales/pt.ts +93 -0
- package/src/locales/zh.ts +93 -0
- package/src/plugin.ts +7 -1
- package/src/rich-text-editor.ts +1 -0
- package/src/styles/palettes.css +660 -0
- package/dist/MMenuItem-CIDblhtb.js.map +0 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { computed, ref } from 'vue'
|
|
3
3
|
import MIcon from './MIcon.vue'
|
|
4
4
|
import MIconButton from './MIconButton.vue'
|
|
5
|
+
import { useLocale } from '../composables/useLocale'
|
|
5
6
|
|
|
6
7
|
export interface CalendarEvent {
|
|
7
8
|
id: string | number
|
|
@@ -14,7 +15,15 @@ export interface CalendarEvent {
|
|
|
14
15
|
const props = withDefaults(defineProps<{
|
|
15
16
|
events?: CalendarEvent[]
|
|
16
17
|
locale?: string
|
|
17
|
-
|
|
18
|
+
todayLabel?: string
|
|
19
|
+
prevMonthLabel?: string
|
|
20
|
+
nextMonthLabel?: string
|
|
21
|
+
}>(), {
|
|
22
|
+
events: () => [],
|
|
23
|
+
locale: 'es-ES',
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const localeStrings = useLocale()
|
|
18
27
|
|
|
19
28
|
const emit = defineEmits<{
|
|
20
29
|
dateClick: [string]
|
|
@@ -96,8 +105,8 @@ const eventColor: Record<string, string> = {
|
|
|
96
105
|
<!-- Header -->
|
|
97
106
|
<div class="flex items-center justify-between border-b border-outline-variant bg-surface-container px-4 py-3">
|
|
98
107
|
<div class="flex items-center gap-1">
|
|
99
|
-
<MIconButton icon="chevron_left" label="
|
|
100
|
-
<MIconButton icon="chevron_right" label="
|
|
108
|
+
<MIconButton icon="chevron_left" :label="prevMonthLabel ?? localeStrings.previousMonth" :size="36" @click="prevMonth" />
|
|
109
|
+
<MIconButton icon="chevron_right" :label="nextMonthLabel ?? localeStrings.nextMonth" :size="36" @click="nextMonth" />
|
|
101
110
|
</div>
|
|
102
111
|
<h3 class="text-title-medium font-medium capitalize text-on-surface">{{ monthLabel }}</h3>
|
|
103
112
|
<button
|
|
@@ -105,7 +114,7 @@ const eventColor: Record<string, string> = {
|
|
|
105
114
|
class="cursor-pointer rounded-full border border-outline px-3 py-1 text-label-medium text-on-surface transition-colors hover:bg-on-surface/8"
|
|
106
115
|
@click="goToday"
|
|
107
116
|
>
|
|
108
|
-
|
|
117
|
+
{{ todayLabel ?? localeStrings.today }}
|
|
109
118
|
</button>
|
|
110
119
|
</div>
|
|
111
120
|
|
|
@@ -164,7 +173,7 @@ const eventColor: Record<string, string> = {
|
|
|
164
173
|
v-if="day.events.length > 2"
|
|
165
174
|
class="px-1 text-label-small text-on-surface-variant"
|
|
166
175
|
>
|
|
167
|
-
+{{ day.events.length - 2 }}
|
|
176
|
+
+{{ day.events.length - 2 }} {{ localeStrings.more }}
|
|
168
177
|
</span>
|
|
169
178
|
</div>
|
|
170
179
|
</div>
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, computed, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
|
|
3
3
|
import MIcon from './MIcon.vue'
|
|
4
|
+
import { useLocale } from '../composables/useLocale'
|
|
5
|
+
|
|
6
|
+
const locale = useLocale()
|
|
4
7
|
|
|
5
8
|
export interface CommandItem {
|
|
6
9
|
id: string
|
|
@@ -19,10 +22,11 @@ const props = withDefaults(
|
|
|
19
22
|
placeholder?: string
|
|
20
23
|
noResultsText?: string
|
|
21
24
|
hotkey?: string
|
|
25
|
+
navigateHint?: string
|
|
26
|
+
selectHint?: string
|
|
27
|
+
closeHint?: string
|
|
22
28
|
}>(),
|
|
23
29
|
{
|
|
24
|
-
placeholder: 'Buscar comando...',
|
|
25
|
-
noResultsText: 'Sin resultados',
|
|
26
30
|
hotkey: 'k',
|
|
27
31
|
},
|
|
28
32
|
)
|
|
@@ -136,7 +140,7 @@ onBeforeUnmount(() => document.removeEventListener('keydown', onGlobalKeydown))
|
|
|
136
140
|
ref="inputRef"
|
|
137
141
|
v-model="query"
|
|
138
142
|
type="text"
|
|
139
|
-
:placeholder="placeholder"
|
|
143
|
+
:placeholder="placeholder ?? locale.searchCommand"
|
|
140
144
|
class="h-12 flex-1 bg-transparent text-body-large text-on-surface outline-none placeholder:text-on-surface-variant/50"
|
|
141
145
|
@keydown="onKeydown"
|
|
142
146
|
/>
|
|
@@ -171,20 +175,20 @@ onBeforeUnmount(() => document.removeEventListener('keydown', onGlobalKeydown))
|
|
|
171
175
|
</template>
|
|
172
176
|
</template>
|
|
173
177
|
<p v-else class="px-4 py-6 text-center text-body-medium text-on-surface-variant">
|
|
174
|
-
{{ noResultsText }}
|
|
178
|
+
{{ noResultsText ?? locale.noResults }}
|
|
175
179
|
</p>
|
|
176
180
|
</div>
|
|
177
181
|
|
|
178
182
|
<!-- Footer -->
|
|
179
183
|
<div class="flex items-center gap-4 border-t border-outline-variant px-4 py-2">
|
|
180
184
|
<span class="flex items-center gap-1 text-label-small text-on-surface-variant">
|
|
181
|
-
<kbd class="rounded bg-surface-container px-1 py-0.5">↑↓</kbd>
|
|
185
|
+
<kbd class="rounded bg-surface-container px-1 py-0.5">↑↓</kbd> {{ navigateHint ?? locale.navigateHint }}
|
|
182
186
|
</span>
|
|
183
187
|
<span class="flex items-center gap-1 text-label-small text-on-surface-variant">
|
|
184
|
-
<kbd class="rounded bg-surface-container px-1 py-0.5">↵</kbd>
|
|
188
|
+
<kbd class="rounded bg-surface-container px-1 py-0.5">↵</kbd> {{ selectHint ?? locale.selectHint }}
|
|
185
189
|
</span>
|
|
186
190
|
<span class="flex items-center gap-1 text-label-small text-on-surface-variant">
|
|
187
|
-
<kbd class="rounded bg-surface-container px-1 py-0.5">esc</kbd>
|
|
191
|
+
<kbd class="rounded bg-surface-container px-1 py-0.5">esc</kbd> {{ closeHint ?? locale.closeHint }}
|
|
188
192
|
</span>
|
|
189
193
|
</div>
|
|
190
194
|
</div>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import MDialog from './MDialog.vue'
|
|
3
3
|
import MButton from './MButton.vue'
|
|
4
|
+
import { useLocale } from '../composables/useLocale'
|
|
4
5
|
|
|
5
|
-
withDefaults(
|
|
6
|
+
const props = withDefaults(
|
|
6
7
|
defineProps<{
|
|
7
8
|
modelValue: boolean
|
|
8
9
|
title: string
|
|
@@ -13,13 +14,13 @@ withDefaults(
|
|
|
13
14
|
loading?: boolean
|
|
14
15
|
}>(),
|
|
15
16
|
{
|
|
16
|
-
confirmLabel: 'Confirmar',
|
|
17
|
-
cancelLabel: 'Cancelar',
|
|
18
17
|
danger: false,
|
|
19
18
|
loading: false,
|
|
20
19
|
},
|
|
21
20
|
)
|
|
22
21
|
|
|
22
|
+
const locale = useLocale()
|
|
23
|
+
|
|
23
24
|
const emit = defineEmits<{ 'update:modelValue': [boolean]; confirm: [] }>()
|
|
24
25
|
</script>
|
|
25
26
|
|
|
@@ -33,10 +34,10 @@ const emit = defineEmits<{ 'update:modelValue': [boolean]; confirm: [] }>()
|
|
|
33
34
|
<p class="text-body-medium text-on-surface-variant">{{ message }}</p>
|
|
34
35
|
<template #actions>
|
|
35
36
|
<MButton variant="text" :disabled="loading" @click="emit('update:modelValue', false)">
|
|
36
|
-
{{ cancelLabel }}
|
|
37
|
+
{{ cancelLabel ?? locale.cancel }}
|
|
37
38
|
</MButton>
|
|
38
39
|
<MButton :color="danger ? 'error' : 'primary'" :loading="loading" @click="emit('confirm')">
|
|
39
|
-
{{ confirmLabel }}
|
|
40
|
+
{{ confirmLabel ?? locale.confirm }}
|
|
40
41
|
</MButton>
|
|
41
42
|
</template>
|
|
42
43
|
</MDialog>
|
|
@@ -5,6 +5,9 @@ import MIcon from './MIcon.vue'
|
|
|
5
5
|
import MIconButton from './MIconButton.vue'
|
|
6
6
|
import MPagination from './MPagination.vue'
|
|
7
7
|
import MChip from './MChip.vue'
|
|
8
|
+
import { useLocale } from '../composables/useLocale'
|
|
9
|
+
|
|
10
|
+
const locale = useLocale()
|
|
8
11
|
|
|
9
12
|
export interface DataTableColumn {
|
|
10
13
|
key: string
|
|
@@ -46,9 +49,15 @@ const props = withDefaults(defineProps<{
|
|
|
46
49
|
serverSide?: boolean
|
|
47
50
|
total?: number
|
|
48
51
|
page?: number
|
|
52
|
+
searchPlaceholder?: string
|
|
53
|
+
selectedText?: string
|
|
54
|
+
recordsText?: string
|
|
55
|
+
expandLabel?: string
|
|
56
|
+
columnsLabel?: string
|
|
57
|
+
exportLabel?: string
|
|
58
|
+
noGroupText?: string
|
|
49
59
|
}>(), {
|
|
50
60
|
loading: false,
|
|
51
|
-
emptyText: 'Sin resultados',
|
|
52
61
|
rowKey: 'id',
|
|
53
62
|
selectable: false,
|
|
54
63
|
modelValue: () => [],
|
|
@@ -137,7 +146,7 @@ const groupedRows = computed(() => {
|
|
|
137
146
|
if (!props.groupBy) return null
|
|
138
147
|
const map = new Map<string, Record<string, any>[]>()
|
|
139
148
|
for (const row of processedRows.value) {
|
|
140
|
-
const key = String(row[props.groupBy] ??
|
|
149
|
+
const key = String(row[props.groupBy] ?? (props.noGroupText ?? locale.noGroup))
|
|
141
150
|
if (!map.has(key)) map.set(key, [])
|
|
142
151
|
map.get(key)!.push(row)
|
|
143
152
|
}
|
|
@@ -269,7 +278,7 @@ function colStyle(col: DataTableColumn) {
|
|
|
269
278
|
>
|
|
270
279
|
<div v-if="searchable" class="flex min-w-48 flex-1 items-center gap-2 rounded-full border border-outline-variant bg-surface-container px-3 py-1.5 transition-[border-color,box-shadow] duration-150 focus-within:border-primary focus-within:ring-1 focus-within:ring-primary/30">
|
|
271
280
|
<MIcon name="search" :size="16" class="shrink-0 text-on-surface-variant" />
|
|
272
|
-
<input v-model="search" type="text" placeholder="
|
|
281
|
+
<input v-model="search" type="text" :placeholder="searchPlaceholder ?? locale.search" class="w-full bg-transparent text-body-medium text-on-surface outline-none placeholder:text-on-surface-variant" />
|
|
273
282
|
<button v-if="search" class="text-on-surface-variant transition-colors hover:text-on-surface" @click="search = ''">
|
|
274
283
|
<MIcon name="close" :size="14" />
|
|
275
284
|
</button>
|
|
@@ -279,13 +288,13 @@ function colStyle(col: DataTableColumn) {
|
|
|
279
288
|
|
|
280
289
|
<Transition enter-active-class="transition-[opacity,transform] duration-150" enter-from-class="opacity-0 scale-90" leave-active-class="transition-[opacity,transform] duration-100" leave-to-class="opacity-0 scale-90">
|
|
281
290
|
<span v-if="selectable && selected.length > 0" class="rounded-full bg-primary/12 px-3 py-1 text-label-small font-medium text-primary">
|
|
282
|
-
{{ selected.length }}
|
|
291
|
+
{{ selected.length }} {{ selectedText ?? locale.selectedCount }}{{ selected.length !== 1 ? 's' : '' }}
|
|
283
292
|
</span>
|
|
284
293
|
</Transition>
|
|
285
294
|
|
|
286
295
|
<!-- Column toggle -->
|
|
287
296
|
<div v-if="columnToggle" class="relative">
|
|
288
|
-
<MIconButton icon="view_column" label="
|
|
297
|
+
<MIconButton icon="view_column" :label="columnsLabel ?? locale.columns" :size="36" @click="showColMenu = !showColMenu" />
|
|
289
298
|
<div v-if="showColMenu" class="absolute right-0 top-full z-10 mt-1 min-w-40 rounded-lg bg-surface-container py-2 shadow-elevation-3">
|
|
290
299
|
<label v-for="col in columns" :key="col.key" class="flex cursor-pointer items-center gap-2 px-3 py-1.5 hover:bg-on-surface/4">
|
|
291
300
|
<MCheckbox
|
|
@@ -297,7 +306,7 @@ function colStyle(col: DataTableColumn) {
|
|
|
297
306
|
</div>
|
|
298
307
|
</div>
|
|
299
308
|
|
|
300
|
-
<MIconButton v-if="exportable" icon="download" label="
|
|
309
|
+
<MIconButton v-if="exportable" icon="download" :label="exportLabel ?? locale.exportCsv" :size="36" @click="exportCSV" />
|
|
301
310
|
</div>
|
|
302
311
|
|
|
303
312
|
<!-- Table -->
|
|
@@ -363,7 +372,7 @@ function colStyle(col: DataTableColumn) {
|
|
|
363
372
|
<td :colspan="visibleColumns.length + extraCols" class="border-t border-outline-variant px-4 py-14 text-center">
|
|
364
373
|
<slot name="empty">
|
|
365
374
|
<MIcon name="search_off" :size="36" class="mb-2 text-on-surface-variant opacity-30" />
|
|
366
|
-
<p class="text-body-medium text-on-surface-variant">{{ emptyText }}</p>
|
|
375
|
+
<p class="text-body-medium text-on-surface-variant">{{ emptyText ?? locale.noResults }}</p>
|
|
367
376
|
</slot>
|
|
368
377
|
</td>
|
|
369
378
|
</tr>
|
|
@@ -385,7 +394,7 @@ function colStyle(col: DataTableColumn) {
|
|
|
385
394
|
<td v-if="hasExpand" class="px-2" :class="dense ? 'py-1' : 'py-2'" @click.stop>
|
|
386
395
|
<MIconButton
|
|
387
396
|
icon="expand_more"
|
|
388
|
-
label="
|
|
397
|
+
:label="expandLabel ?? locale.expand"
|
|
389
398
|
:size="28"
|
|
390
399
|
:class="isExpanded(row) ? 'rotate-180' : ''"
|
|
391
400
|
class="transition-transform duration-200"
|
|
@@ -429,7 +438,7 @@ function colStyle(col: DataTableColumn) {
|
|
|
429
438
|
<!-- Footer -->
|
|
430
439
|
<div class="flex items-center justify-between gap-4 border-t border-outline-variant bg-surface-container-lowest px-4 py-2">
|
|
431
440
|
<span class="text-label-small text-on-surface-variant">
|
|
432
|
-
{{ totalCount }}
|
|
441
|
+
{{ totalCount }} {{ recordsText ?? locale.recordCount }}{{ totalCount !== 1 ? 's' : '' }}
|
|
433
442
|
</span>
|
|
434
443
|
<MPagination :page="currentPage" :per-page="perPage" :total="totalCount" @update:page="currentPage = $event" />
|
|
435
444
|
</div>
|
|
@@ -3,6 +3,7 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
|
3
3
|
import MIcon from './MIcon.vue'
|
|
4
4
|
import MIconButton from './MIconButton.vue'
|
|
5
5
|
import { useFieldBg } from '../composables/useFieldBg'
|
|
6
|
+
import { useLocale } from '../composables/useLocale'
|
|
6
7
|
|
|
7
8
|
const props = withDefaults(defineProps<{
|
|
8
9
|
modelValue: string | null
|
|
@@ -15,7 +16,13 @@ const props = withDefaults(defineProps<{
|
|
|
15
16
|
hint?: string
|
|
16
17
|
locale?: string
|
|
17
18
|
fieldBg?: string
|
|
18
|
-
|
|
19
|
+
prevMonthLabel?: string
|
|
20
|
+
nextMonthLabel?: string
|
|
21
|
+
}>(), {
|
|
22
|
+
locale: 'es-ES',
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const localeStrings = useLocale()
|
|
19
26
|
|
|
20
27
|
const emit = defineEmits<{ 'update:modelValue': [string | null] }>()
|
|
21
28
|
|
|
@@ -173,7 +180,7 @@ onUnmounted(() => {
|
|
|
173
180
|
>
|
|
174
181
|
<MIcon name="calendar_today" :size="20" class="shrink-0 text-on-surface-variant" />
|
|
175
182
|
<span v-if="displayValue" class="flex-1 text-on-surface">{{ displayValue }}</span>
|
|
176
|
-
<span v-else class="flex-1 text-on-surface-variant">{{ placeholder || label ||
|
|
183
|
+
<span v-else class="flex-1 text-on-surface-variant">{{ placeholder || label || localeStrings.selectDate }}</span>
|
|
177
184
|
<MIcon
|
|
178
185
|
v-if="modelValue"
|
|
179
186
|
name="close"
|
|
@@ -210,9 +217,9 @@ onUnmounted(() => {
|
|
|
210
217
|
>
|
|
211
218
|
<!-- Header -->
|
|
212
219
|
<div class="mb-3 flex items-center justify-between">
|
|
213
|
-
<MIconButton icon="chevron_left" label="
|
|
220
|
+
<MIconButton icon="chevron_left" :label="prevMonthLabel ?? localeStrings.previousMonth" :size="36" @click="prevMonth" />
|
|
214
221
|
<span class="text-title-small font-medium capitalize text-on-surface">{{ monthLabel }}</span>
|
|
215
|
-
<MIconButton icon="chevron_right" label="
|
|
222
|
+
<MIconButton icon="chevron_right" :label="nextMonthLabel ?? localeStrings.nextMonth" :size="36" @click="nextMonth" />
|
|
216
223
|
</div>
|
|
217
224
|
|
|
218
225
|
<!-- Weekday headers -->
|
|
@@ -3,6 +3,7 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
|
3
3
|
import MIcon from './MIcon.vue'
|
|
4
4
|
import MIconButton from './MIconButton.vue'
|
|
5
5
|
import { useFieldBg } from '../composables/useFieldBg'
|
|
6
|
+
import { useLocale } from '../composables/useLocale'
|
|
6
7
|
|
|
7
8
|
export interface DateRange {
|
|
8
9
|
start: string | null
|
|
@@ -12,6 +13,7 @@ export interface DateRange {
|
|
|
12
13
|
const props = withDefaults(defineProps<{
|
|
13
14
|
modelValue: DateRange
|
|
14
15
|
label?: string
|
|
16
|
+
placeholder?: string
|
|
15
17
|
min?: string
|
|
16
18
|
max?: string
|
|
17
19
|
disabled?: boolean
|
|
@@ -19,7 +21,15 @@ const props = withDefaults(defineProps<{
|
|
|
19
21
|
hint?: string
|
|
20
22
|
locale?: string
|
|
21
23
|
fieldBg?: string
|
|
22
|
-
|
|
24
|
+
prevMonthLabel?: string
|
|
25
|
+
nextMonthLabel?: string
|
|
26
|
+
pickStartText?: string
|
|
27
|
+
pickEndText?: string
|
|
28
|
+
}>(), {
|
|
29
|
+
locale: 'es-ES',
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const localeStrings = useLocale()
|
|
23
33
|
|
|
24
34
|
const emit = defineEmits<{ 'update:modelValue': [DateRange] }>()
|
|
25
35
|
|
|
@@ -184,7 +194,7 @@ onUnmounted(() => {
|
|
|
184
194
|
>
|
|
185
195
|
<MIcon name="date_range" :size="20" class="shrink-0 text-on-surface-variant" />
|
|
186
196
|
<span v-if="displayValue" class="flex-1 text-on-surface">{{ displayValue }}</span>
|
|
187
|
-
<span v-else class="flex-1 text-on-surface-variant">{{ label ||
|
|
197
|
+
<span v-else class="flex-1 text-on-surface-variant">{{ label || placeholder || localeStrings.selectRange }}</span>
|
|
188
198
|
<MIcon
|
|
189
199
|
v-if="modelValue.start || modelValue.end"
|
|
190
200
|
name="close"
|
|
@@ -219,13 +229,13 @@ onUnmounted(() => {
|
|
|
219
229
|
:style="dropPos"
|
|
220
230
|
>
|
|
221
231
|
<p class="mb-2 text-center text-label-medium text-on-surface-variant">
|
|
222
|
-
{{ picking === 'start' ?
|
|
232
|
+
{{ picking === 'start' ? (pickStartText ?? localeStrings.pickStart) : (pickEndText ?? localeStrings.pickEnd) }}
|
|
223
233
|
</p>
|
|
224
234
|
|
|
225
235
|
<div class="mb-3 flex items-center justify-between">
|
|
226
|
-
<MIconButton icon="chevron_left" label="
|
|
236
|
+
<MIconButton icon="chevron_left" :label="prevMonthLabel ?? localeStrings.previousMonth" :size="36" @click="prevMonth" />
|
|
227
237
|
<span class="text-title-small font-medium capitalize text-on-surface">{{ monthLabel }}</span>
|
|
228
|
-
<MIconButton icon="chevron_right" label="
|
|
238
|
+
<MIconButton icon="chevron_right" :label="nextMonthLabel ?? localeStrings.nextMonth" :size="36" @click="nextMonth" />
|
|
229
239
|
</div>
|
|
230
240
|
|
|
231
241
|
<div class="mb-1 grid grid-cols-7 gap-0.5 text-center">
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { watch } from 'vue'
|
|
3
3
|
import MIconButton from './MIconButton.vue'
|
|
4
|
+
import { useLocale } from '../composables/useLocale'
|
|
4
5
|
|
|
5
6
|
const props = withDefaults(
|
|
6
7
|
defineProps<{
|
|
@@ -8,6 +9,7 @@ const props = withDefaults(
|
|
|
8
9
|
title?: string
|
|
9
10
|
maxWidth?: string
|
|
10
11
|
persistent?: boolean
|
|
12
|
+
closeLabel?: string
|
|
11
13
|
}>(),
|
|
12
14
|
{
|
|
13
15
|
maxWidth: 'max-w-md',
|
|
@@ -15,6 +17,8 @@ const props = withDefaults(
|
|
|
15
17
|
},
|
|
16
18
|
)
|
|
17
19
|
|
|
20
|
+
const locale = useLocale()
|
|
21
|
+
|
|
18
22
|
const emit = defineEmits<{ 'update:modelValue': [boolean] }>()
|
|
19
23
|
|
|
20
24
|
function close() {
|
|
@@ -56,7 +60,7 @@ watch(
|
|
|
56
60
|
<h2 class="text-headline-small text-on-surface">
|
|
57
61
|
<slot name="title">{{ title }}</slot>
|
|
58
62
|
</h2>
|
|
59
|
-
<MIconButton v-if="!persistent" icon="close" label="
|
|
63
|
+
<MIconButton v-if="!persistent" icon="close" :label="closeLabel ?? locale.close" @click="close" />
|
|
60
64
|
</div>
|
|
61
65
|
<div class="overflow-y-auto px-6 py-2 text-body-medium text-on-surface-variant">
|
|
62
66
|
<slot />
|
|
@@ -3,6 +3,9 @@ import { ref, computed } from 'vue'
|
|
|
3
3
|
import MIcon from './MIcon.vue'
|
|
4
4
|
import MIconButton from './MIconButton.vue'
|
|
5
5
|
import MSpinner from './MSpinner.vue'
|
|
6
|
+
import { useLocale } from '../composables/useLocale'
|
|
7
|
+
|
|
8
|
+
const locale = useLocale()
|
|
6
9
|
|
|
7
10
|
export interface UploadFile {
|
|
8
11
|
file: File
|
|
@@ -18,8 +21,15 @@ const props = withDefaults(
|
|
|
18
21
|
multiple?: boolean
|
|
19
22
|
maxSize?: number
|
|
20
23
|
disabled?: boolean
|
|
24
|
+
dropText?: string
|
|
25
|
+
selectText?: string
|
|
26
|
+
maxSizePrefix?: string
|
|
27
|
+
removeLabel?: string
|
|
21
28
|
}>(),
|
|
22
|
-
{
|
|
29
|
+
{
|
|
30
|
+
multiple: false,
|
|
31
|
+
disabled: false,
|
|
32
|
+
},
|
|
23
33
|
)
|
|
24
34
|
|
|
25
35
|
const emit = defineEmits<{
|
|
@@ -128,14 +138,16 @@ function openPicker() {
|
|
|
128
138
|
class="text-on-surface-variant"
|
|
129
139
|
/>
|
|
130
140
|
<div class="text-center">
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
<slot name="dropzone">
|
|
142
|
+
<p class="text-body-large text-on-surface">
|
|
143
|
+
{{ dropText ?? locale.dropText }} <span class="font-medium text-primary">{{ selectText ?? locale.selectText }}</span>
|
|
144
|
+
</p>
|
|
145
|
+
<p v-if="accept || maxSize" class="mt-1 text-body-small text-on-surface-variant">
|
|
146
|
+
<span v-if="accept">{{ accept }}</span>
|
|
147
|
+
<span v-if="accept && maxSize"> · </span>
|
|
148
|
+
<span v-if="maxSize">{{ maxSizePrefix ?? locale.maxSizePrefix }} {{ formatSize(maxSize) }}</span>
|
|
149
|
+
</p>
|
|
150
|
+
</slot>
|
|
139
151
|
</div>
|
|
140
152
|
</div>
|
|
141
153
|
|
|
@@ -187,7 +199,7 @@ function openPicker() {
|
|
|
187
199
|
<MIcon v-else-if="entry.status === 'done'" name="check_circle" :size="20" class="text-success" />
|
|
188
200
|
<MIcon v-else-if="entry.status === 'error'" name="error" :size="20" class="text-error" />
|
|
189
201
|
|
|
190
|
-
<MIconButton icon="close" label="
|
|
202
|
+
<MIconButton icon="close" :label="removeLabel ?? locale.remove" :size="32" @click="removeFile(entry)" />
|
|
191
203
|
</div>
|
|
192
204
|
</TransitionGroup>
|
|
193
205
|
</div>
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
|
|
3
3
|
import MSpinner from './MSpinner.vue'
|
|
4
|
+
import { useLocale } from '../composables/useLocale'
|
|
5
|
+
|
|
6
|
+
const locale = useLocale()
|
|
4
7
|
|
|
5
8
|
const props = withDefaults(
|
|
6
9
|
defineProps<{
|
|
@@ -15,8 +18,6 @@ const props = withDefaults(
|
|
|
15
18
|
loading: false,
|
|
16
19
|
disabled: false,
|
|
17
20
|
threshold: 100,
|
|
18
|
-
loadingText: 'Cargando...',
|
|
19
|
-
endText: 'No hay más elementos',
|
|
20
21
|
ended: false,
|
|
21
22
|
},
|
|
22
23
|
)
|
|
@@ -55,13 +56,17 @@ onBeforeUnmount(() => observer?.disconnect())
|
|
|
55
56
|
<slot />
|
|
56
57
|
|
|
57
58
|
<div ref="sentinelRef" class="flex items-center justify-center py-4">
|
|
58
|
-
<
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
<slot v-if="loading" name="loading">
|
|
60
|
+
<div class="flex items-center gap-3">
|
|
61
|
+
<MSpinner :size="20" class="text-primary" />
|
|
62
|
+
<span class="text-body-medium text-on-surface-variant">{{ loadingText ?? locale.loadingMore }}</span>
|
|
63
|
+
</div>
|
|
64
|
+
</slot>
|
|
65
|
+
<slot v-else-if="ended" name="end">
|
|
66
|
+
<p class="text-body-small text-on-surface-variant">
|
|
67
|
+
{{ endText ?? locale.noMoreItems }}
|
|
68
|
+
</p>
|
|
69
|
+
</slot>
|
|
65
70
|
<slot v-else name="idle" />
|
|
66
71
|
</div>
|
|
67
72
|
</div>
|
|
@@ -3,6 +3,9 @@ import { computed, ref, useId, onMounted, onUnmounted, nextTick } from 'vue'
|
|
|
3
3
|
import MIcon from './MIcon.vue'
|
|
4
4
|
import MCheckbox from './MCheckbox.vue'
|
|
5
5
|
import { useFieldBg } from '../composables/useFieldBg'
|
|
6
|
+
import { useLocale } from '../composables/useLocale'
|
|
7
|
+
|
|
8
|
+
const locale = useLocale()
|
|
6
9
|
|
|
7
10
|
export interface MultiSelectOption {
|
|
8
11
|
label: string
|
|
@@ -26,6 +29,8 @@ const props = withDefaults(
|
|
|
26
29
|
searchable?: boolean
|
|
27
30
|
maxChips?: number
|
|
28
31
|
clearable?: boolean
|
|
32
|
+
searchPlaceholder?: string
|
|
33
|
+
noResultsText?: string
|
|
29
34
|
}>(),
|
|
30
35
|
{
|
|
31
36
|
modelValue: () => [],
|
|
@@ -299,7 +304,7 @@ const labelClasses = computed(() => {
|
|
|
299
304
|
ref="searchInput"
|
|
300
305
|
v-model="search"
|
|
301
306
|
type="text"
|
|
302
|
-
placeholder="
|
|
307
|
+
:placeholder="searchPlaceholder ?? locale.search"
|
|
303
308
|
class="w-full bg-transparent text-body-medium text-on-surface outline-none placeholder:text-on-surface-variant"
|
|
304
309
|
/>
|
|
305
310
|
</div>
|
|
@@ -319,12 +324,11 @@ const labelClasses = computed(() => {
|
|
|
319
324
|
/>
|
|
320
325
|
<span class="text-body-large text-on-surface">{{ opt.label }}</span>
|
|
321
326
|
</label>
|
|
322
|
-
<
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
</p>
|
|
327
|
+
<slot v-if="filteredOptions.length === 0" name="no-results">
|
|
328
|
+
<p class="px-4 py-3 text-center text-body-small text-on-surface-variant">
|
|
329
|
+
{{ noResultsText ?? locale.noResults }}
|
|
330
|
+
</p>
|
|
331
|
+
</slot>
|
|
328
332
|
</div>
|
|
329
333
|
</div>
|
|
330
334
|
</Transition>
|