@saasmakers/ui 1.4.43 → 1.4.44
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/app/components/bases/BaseAlert.vue +0 -1
- package/app/components/bases/BaseAvatar.vue +4 -3
- package/app/components/bases/BaseButton.vue +0 -1
- package/app/components/bases/BaseIcon.vue +0 -1
- package/app/components/bases/BaseOverlay.vue +0 -1
- package/app/components/bases/BaseQuote.vue +0 -1
- package/app/components/bases/BaseTag.vue +0 -2
- package/app/components/bases/BaseTags.vue +1 -3
- package/app/components/bases/BaseText.vue +0 -1
- package/app/components/fields/FieldAvatar.vue +5 -2
- package/app/components/fields/FieldCheckbox.vue +0 -1
- package/app/components/fields/FieldDays.vue +0 -1
- package/app/components/fields/FieldEmojis.vue +0 -2
- package/app/components/fields/FieldInput.vue +0 -3
- package/app/components/fields/FieldMessage.vue +1 -0
- package/app/components/fields/FieldSelect.vue +3 -8
- package/app/components/fields/FieldTextarea.vue +0 -3
- package/app/components/fields/FieldTime.vue +0 -2
- package/app/composables/useChartist.ts +4 -0
- package/app/composables/useToasts.ts +20 -15
- package/nuxt.config.ts +2 -1
- package/package.json +3 -3
|
@@ -23,12 +23,10 @@ defineSlots<{
|
|
|
23
23
|
}>()
|
|
24
24
|
|
|
25
25
|
const { createToast } = useToasts()
|
|
26
|
-
|
|
27
26
|
const error = ref(false)
|
|
28
27
|
const fileInput = ref<HTMLInputElement>()
|
|
29
28
|
const hovered = ref(false)
|
|
30
29
|
const loaded = ref(false)
|
|
31
|
-
|
|
32
30
|
const { t } = useI18n()
|
|
33
31
|
|
|
34
32
|
const isClickable = computed(() => {
|
|
@@ -40,7 +38,10 @@ function onAvatarSelected(event: Event) {
|
|
|
40
38
|
|
|
41
39
|
if (file) {
|
|
42
40
|
if (props.maxSizeMb && file.size > props.maxSizeMb * 1024 * 1024) {
|
|
43
|
-
return createToast(
|
|
41
|
+
return createToast({
|
|
42
|
+
message: t('fileSizeTooLarge', { maxSizeMb: props.maxSizeMb }),
|
|
43
|
+
status: 'error',
|
|
44
|
+
})
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
emit('avatarSelected', event, file)
|
|
@@ -28,13 +28,11 @@ const emit = defineEmits<{
|
|
|
28
28
|
}>()
|
|
29
29
|
|
|
30
30
|
const modelValue = defineModel<BaseTags['modelValue']>({ default: () => [] })
|
|
31
|
-
|
|
32
31
|
const keyForTagCreation = ref(Date.now())
|
|
33
32
|
const keyForTagUpdate = ref(Date.now())
|
|
34
33
|
const root = ref<HTMLDivElement>()
|
|
35
34
|
const showingAllTags = ref(false)
|
|
36
35
|
const showingTagCreationField = ref(false)
|
|
37
|
-
|
|
38
36
|
const { t } = useI18n()
|
|
39
37
|
const { getIcon } = useLayerIcons()
|
|
40
38
|
|
|
@@ -85,7 +83,6 @@ function onShowTagField() {
|
|
|
85
83
|
if (!showingTagCreationField.value) {
|
|
86
84
|
showingTagCreationField.value = true
|
|
87
85
|
|
|
88
|
-
// Focus contenteditable
|
|
89
86
|
nextTick(() => {
|
|
90
87
|
const element = root.value?.querySelector<HTMLInputElement>('input[type="text"]')
|
|
91
88
|
|
|
@@ -104,6 +101,7 @@ function onTagClick(event: MouseEvent, tagId?: number | string) {
|
|
|
104
101
|
}
|
|
105
102
|
else if (props.selectableUnique) {
|
|
106
103
|
value = [tagId]
|
|
104
|
+
|
|
107
105
|
emit('attach', event, tagId)
|
|
108
106
|
}
|
|
109
107
|
else {
|
|
@@ -26,7 +26,6 @@ const emit = defineEmits<{
|
|
|
26
26
|
|
|
27
27
|
const { createToast } = useToasts()
|
|
28
28
|
const { t } = useI18n()
|
|
29
|
-
|
|
30
29
|
const fileInput = ref<HTMLInputElement>()
|
|
31
30
|
const id = useId()
|
|
32
31
|
|
|
@@ -41,7 +40,11 @@ function onAvatarChange(event: Event) {
|
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
if (props.maxSizeMb && file.size > props.maxSizeMb * 1024 * 1024) {
|
|
44
|
-
createToast(
|
|
43
|
+
createToast({
|
|
44
|
+
message: t('fileSizeTooLarge', { maxSizeMb: props.maxSizeMb }),
|
|
45
|
+
status: 'error',
|
|
46
|
+
})
|
|
47
|
+
|
|
45
48
|
return
|
|
46
49
|
}
|
|
47
50
|
|
|
@@ -11,9 +11,7 @@ const emit = defineEmits<{
|
|
|
11
11
|
|
|
12
12
|
const { locale, t } = useI18n()
|
|
13
13
|
const { normalizeText } = useLayerUtils()
|
|
14
|
-
|
|
15
14
|
const modelValue = defineModel<FieldEmojis['modelValue']>({ default: '' })
|
|
16
|
-
|
|
17
15
|
const searchRaw = ref('')
|
|
18
16
|
const searchQuery = refDebounced(searchRaw, 250)
|
|
19
17
|
|
|
@@ -36,12 +36,9 @@ const { fadeIn } = useMotion()
|
|
|
36
36
|
const { normalizeText } = useLayerUtils()
|
|
37
37
|
const { t } = useI18n()
|
|
38
38
|
const id = useId()
|
|
39
|
-
|
|
40
39
|
const modelValue = defineModel<FieldSelect['modelValue']>({ default: '' })
|
|
41
|
-
|
|
42
40
|
const opened = ref(false)
|
|
43
41
|
const searchRaw = ref('')
|
|
44
|
-
|
|
45
42
|
const searchInput = ref<InstanceType<typeof FieldInput>>()
|
|
46
43
|
|
|
47
44
|
const computedColumns = computed(() => {
|
|
@@ -55,7 +52,6 @@ const computedColumns = computed(() => {
|
|
|
55
52
|
const computedOptions = computed(() => {
|
|
56
53
|
const options: FieldSelectOption[] = []
|
|
57
54
|
|
|
58
|
-
// Add index to each option
|
|
59
55
|
if (props.columns.length > 0) {
|
|
60
56
|
for (const column of props.columns) {
|
|
61
57
|
for (const columnOption of column.options) {
|
|
@@ -152,8 +148,7 @@ function onMouseLeaveOrBlur() {
|
|
|
152
148
|
|
|
153
149
|
function onOptionClick(event: MouseEvent, option: FieldSelectOption) {
|
|
154
150
|
if (!props.disabled) {
|
|
155
|
-
|
|
156
|
-
if ((selectedOption.value || {}).value === option.value) {
|
|
151
|
+
if (selectedOption.value?.value === option.value) {
|
|
157
152
|
reset()
|
|
158
153
|
}
|
|
159
154
|
else {
|
|
@@ -348,8 +343,8 @@ function selectOption(event: MouseEvent, value: string) {
|
|
|
348
343
|
:class="{
|
|
349
344
|
'border-b border-gray-200 dark:border-gray-800 p-3 hover:bg-gray-100 dark:hover:bg-gray-800 last:border-b-0': computedColumns.length < 2,
|
|
350
345
|
'px-2 py-1 hover:bg-gray-100 dark:hover:bg-gray-800 last:mb-2': computedColumns.length >= 2,
|
|
351
|
-
'font-medium underline':
|
|
352
|
-
'text-gray-900 dark:text-gray-100':
|
|
346
|
+
'font-medium underline': option.value === selectedOption?.value,
|
|
347
|
+
'text-gray-900 dark:text-gray-100': option.value === selectedOption?.value,
|
|
353
348
|
'bg-white dark:bg-gray-900': selectedOption && option.value !== selectedOption.value,
|
|
354
349
|
}"
|
|
355
350
|
role="button"
|
|
@@ -27,11 +27,8 @@ const emit = defineEmits<{
|
|
|
27
27
|
}>()
|
|
28
28
|
|
|
29
29
|
const id = useId()
|
|
30
|
-
|
|
31
30
|
const modelValue = defineModel<FieldTextarea['modelValue']>({ default: '' })
|
|
32
|
-
|
|
33
31
|
const textarea = ref<HTMLTextAreaElement>()
|
|
34
|
-
|
|
35
32
|
const { isDesktopBrowser } = useDevice()
|
|
36
33
|
|
|
37
34
|
onMounted(() => {
|
|
@@ -80,10 +80,12 @@ export default function useChartist() {
|
|
|
80
80
|
// Animation for bar charts
|
|
81
81
|
if (ctx.type === 'bar') {
|
|
82
82
|
const barCtx = ctx as BarDrawEvent
|
|
83
|
+
|
|
83
84
|
// Access private options property via type assertion
|
|
84
85
|
const chartOptions = (chart as unknown as {
|
|
85
86
|
options?: Options & Partial<BarChartOptions>
|
|
86
87
|
}).options
|
|
88
|
+
|
|
87
89
|
const horizontal = !!(chartOptions as BarChartOptions | undefined)?.horizontalBars
|
|
88
90
|
|
|
89
91
|
// For vertical bars, y1 is baseline, y2 is top. For horizontal, x1 is baseline, x2 is end.
|
|
@@ -93,6 +95,7 @@ export default function useChartist() {
|
|
|
93
95
|
// Start collapsed at baseline
|
|
94
96
|
if (horizontal) {
|
|
95
97
|
barCtx.element.attr({ x2: from })
|
|
98
|
+
|
|
96
99
|
barCtx.element.animate({
|
|
97
100
|
x2: {
|
|
98
101
|
begin,
|
|
@@ -106,6 +109,7 @@ export default function useChartist() {
|
|
|
106
109
|
}
|
|
107
110
|
else {
|
|
108
111
|
barCtx.element.attr({ y2: from })
|
|
112
|
+
|
|
109
113
|
barCtx.element.animate({
|
|
110
114
|
y2: {
|
|
111
115
|
begin,
|
|
@@ -13,43 +13,46 @@ export default function useToast() {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
dismissTimers.clear()
|
|
16
|
+
|
|
16
17
|
toasts.value = []
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
const createToast = (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
) => {
|
|
20
|
+
const createToast = (params: {
|
|
21
|
+
action?: BaseToastAction
|
|
22
|
+
i18nParams?: Record<string, number | string>
|
|
23
|
+
message: string
|
|
24
|
+
status?: BaseStatus
|
|
25
|
+
}) => {
|
|
25
26
|
if (!import.meta.client) {
|
|
26
27
|
return
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
const text = message.includes(' ')
|
|
30
|
-
? message
|
|
31
|
-
: nuxtApp.$i18n.t(`toasts.${message}`, i18nParams ?? {})
|
|
30
|
+
const text = params.message.includes(' ')
|
|
31
|
+
? params.message
|
|
32
|
+
: nuxtApp.$i18n.t(`toasts.${params.message}`, params.i18nParams ?? {})
|
|
32
33
|
|
|
33
|
-
const fingerprint = getFingerprint(status, text, action?.label)
|
|
34
|
+
const fingerprint = getFingerprint(params.status, text, params.action?.label)
|
|
34
35
|
const existingToast = toasts.value.find(item => getFingerprint(item.status, item.text, item.action?.label) === fingerprint)
|
|
35
36
|
|
|
36
37
|
if (existingToast) {
|
|
37
|
-
if (action) {
|
|
38
|
-
existingToast.action = action
|
|
38
|
+
if (params.action) {
|
|
39
|
+
existingToast.action = params.action
|
|
39
40
|
}
|
|
41
|
+
|
|
40
42
|
scheduleDismiss(existingToast.id, !!existingToast.action)
|
|
43
|
+
|
|
41
44
|
return
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
const toast: BaseToast = {
|
|
45
|
-
action,
|
|
48
|
+
action: params.action,
|
|
46
49
|
id: crypto.randomUUID(),
|
|
47
|
-
status,
|
|
50
|
+
status: params.status,
|
|
48
51
|
text,
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
toasts.value.push(toast)
|
|
52
|
-
scheduleDismiss(toast.id, !!action)
|
|
55
|
+
scheduleDismiss(toast.id, !!params.action)
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
return {
|
|
@@ -62,6 +65,7 @@ export default function useToast() {
|
|
|
62
65
|
|
|
63
66
|
function clearDismissTimer(toastId: string) {
|
|
64
67
|
const timer = dismissTimers.get(toastId)
|
|
68
|
+
|
|
65
69
|
if (timer !== undefined) {
|
|
66
70
|
clearTimeout(timer)
|
|
67
71
|
dismissTimers.delete(toastId)
|
|
@@ -73,6 +77,7 @@ function closeToast(toastId: string) {
|
|
|
73
77
|
return
|
|
74
78
|
|
|
75
79
|
clearDismissTimer(toastId)
|
|
80
|
+
|
|
76
81
|
toasts.value = toasts.value.filter(item => item.id !== toastId)
|
|
77
82
|
}
|
|
78
83
|
|
package/nuxt.config.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { localeCodes } from '@saasmakers/shared'
|
|
1
2
|
import path from 'node:path'
|
|
2
3
|
import { fileURLToPath } from 'node:url'
|
|
3
4
|
import { defineNuxtConfig } from 'nuxt/config'
|
|
@@ -71,7 +72,7 @@ export default defineNuxtConfig({
|
|
|
71
72
|
|
|
72
73
|
i18n: {
|
|
73
74
|
defaultLocale: 'en',
|
|
74
|
-
locales:
|
|
75
|
+
locales: localeCodes,
|
|
75
76
|
strategy: 'prefix_except_default',
|
|
76
77
|
|
|
77
78
|
detectBrowserLanguage: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saasmakers/ui",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.44",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Reusable Nuxt UI components for SaaS Makers projects",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,10 +51,10 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"nuxt": "4.3.1",
|
|
53
53
|
"typescript": "5.9.3",
|
|
54
|
-
"@saasmakers/shared": "0.2.
|
|
54
|
+
"@saasmakers/shared": "0.2.8"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@saasmakers/shared": "^0.2.
|
|
57
|
+
"@saasmakers/shared": "^0.2.8",
|
|
58
58
|
"nuxt": "^4.3.1"
|
|
59
59
|
},
|
|
60
60
|
"publishConfig": {
|