@saasmakers/ui 0.1.107 → 0.1.109
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 +13 -10
- package/app/components/bases/BaseAvatar.vue +28 -2
- package/app/components/bases/BaseCharacter.vue +8 -7
- package/app/components/bases/BaseChart.vue +21 -19
- package/app/components/bases/BaseEmoji.vue +12 -2
- package/app/components/bases/BaseHeading.stories.ts +1 -1
- package/app/components/bases/BaseHeading.vue +7 -1
- package/app/components/bases/BaseIcon.vue +42 -25
- package/app/components/bases/BaseMessage.vue +4 -6
- package/app/components/bases/BaseMetric.vue +9 -8
- package/app/components/bases/BaseOverlay.vue +18 -3
- package/app/components/bases/BaseParagraph.stories.ts +1 -1
- package/app/components/bases/BaseParagraph.vue +7 -1
- package/app/components/bases/BaseQuote.stories.ts +1 -1
- package/app/components/bases/BaseQuote.vue +20 -17
- package/app/components/bases/BaseSpinner.vue +11 -1
- package/app/components/bases/BaseTag.vue +22 -1
- package/app/components/bases/BaseTags.vue +3 -4
- package/app/components/bases/BaseToast.vue +7 -3
- package/app/components/fields/FieldDays.vue +2 -1
- package/app/components/fields/FieldEmojis.vue +3 -3
- package/app/components/fields/FieldLabel.vue +20 -7
- package/app/components/fields/FieldMessage.vue +60 -92
- package/app/components/fields/FieldSelect.vue +34 -8
- package/app/components/fields/FieldTime.vue +12 -1
- package/app/composables/useChartist.ts +1 -1
- package/app/composables/useDevice.ts +1 -0
- package/app/composables/useLayerUtils.ts +16 -16
- package/app/composables/useToasts.ts +1 -1
- package/app/composables/useTranslation.ts +1 -1
- package/app/types/bases.d.ts +2 -0
- package/nuxt.config.ts +6 -6
- package/package.json +17 -13
|
@@ -25,17 +25,20 @@ const { getIcon } = useLayerIcons()
|
|
|
25
25
|
const isClosed = ref(false)
|
|
26
26
|
|
|
27
27
|
const buttonColor = computed<BaseColor>(() => {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
switch (props.status) {
|
|
29
|
+
case 'error': {
|
|
30
|
+
return 'red'
|
|
31
|
+
}
|
|
32
|
+
case 'success': {
|
|
33
|
+
return 'green'
|
|
34
|
+
}
|
|
35
|
+
case 'warning': {
|
|
36
|
+
return 'orange'
|
|
37
|
+
}
|
|
38
|
+
default: {
|
|
39
|
+
return 'indigo'
|
|
40
|
+
}
|
|
30
41
|
}
|
|
31
|
-
else if (props.status === 'success') {
|
|
32
|
-
return 'green'
|
|
33
|
-
}
|
|
34
|
-
else if (props.status === 'warning') {
|
|
35
|
-
return 'orange'
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return 'indigo'
|
|
39
42
|
})
|
|
40
43
|
|
|
41
44
|
onBeforeMount(async () => {
|
|
@@ -31,6 +31,10 @@ const loaded = ref(false)
|
|
|
31
31
|
|
|
32
32
|
const { t } = useI18n()
|
|
33
33
|
|
|
34
|
+
const isClickable = computed(() => {
|
|
35
|
+
return props.to || props.editable
|
|
36
|
+
})
|
|
37
|
+
|
|
34
38
|
function onAvatarSelected(event: Event) {
|
|
35
39
|
const file = (event.target as HTMLInputElement).files?.[0]
|
|
36
40
|
|
|
@@ -43,6 +47,10 @@ function onAvatarSelected(event: Event) {
|
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
|
|
50
|
+
function onBlur() {
|
|
51
|
+
hovered.value = false
|
|
52
|
+
}
|
|
53
|
+
|
|
46
54
|
function onClick(event: MouseEvent) {
|
|
47
55
|
emit('click', event)
|
|
48
56
|
|
|
@@ -56,6 +64,16 @@ function onError() {
|
|
|
56
64
|
loaded.value = true
|
|
57
65
|
}
|
|
58
66
|
|
|
67
|
+
function onFocus() {
|
|
68
|
+
hovered.value = true
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function onKeyDown(event: KeyboardEvent) {
|
|
72
|
+
if (isClickable.value) {
|
|
73
|
+
(event.currentTarget as HTMLElement).click()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
59
77
|
function onLoad() {
|
|
60
78
|
loaded.value = true
|
|
61
79
|
}
|
|
@@ -76,6 +94,8 @@ function onMouseLeave() {
|
|
|
76
94
|
:to="to"
|
|
77
95
|
@mouseenter="onMouseEnter"
|
|
78
96
|
@mouseleave="onMouseLeave"
|
|
97
|
+
@focusin="onFocus"
|
|
98
|
+
@focusout="onBlur"
|
|
79
99
|
>
|
|
80
100
|
<div
|
|
81
101
|
:aria-label="editable ? t('edit') : undefined"
|
|
@@ -83,10 +103,14 @@ function onMouseLeave() {
|
|
|
83
103
|
:class="{
|
|
84
104
|
'rounded-full': circular,
|
|
85
105
|
'shadow': shadow,
|
|
86
|
-
'cursor-pointer':
|
|
106
|
+
'cursor-pointer': isClickable,
|
|
87
107
|
}"
|
|
88
|
-
|
|
108
|
+
role="button"
|
|
109
|
+
:aria-disabled="!isClickable"
|
|
110
|
+
tabindex="0"
|
|
89
111
|
@click="onClick"
|
|
112
|
+
@keydown.enter="onKeyDown"
|
|
113
|
+
@keydown.space.prevent="onKeyDown"
|
|
90
114
|
>
|
|
91
115
|
<img
|
|
92
116
|
class="h-full w-full object-cover drag-none"
|
|
@@ -97,6 +121,7 @@ function onMouseLeave() {
|
|
|
97
121
|
'border-3': borderWidth === 3,
|
|
98
122
|
'border-4': borderWidth === 4,
|
|
99
123
|
}"
|
|
124
|
+
:alt="editable ? t('edit') : ''"
|
|
100
125
|
loading="lazy"
|
|
101
126
|
:src="!error && src ? src : '/images/bases/BaseAvatar/default.svg'"
|
|
102
127
|
@error="onError"
|
|
@@ -114,6 +139,7 @@ function onMouseLeave() {
|
|
|
114
139
|
v-if="editable"
|
|
115
140
|
ref="fileInput"
|
|
116
141
|
accept="image/*"
|
|
142
|
+
:aria-label="t('edit')"
|
|
117
143
|
class="hidden"
|
|
118
144
|
type="file"
|
|
119
145
|
@change="onAvatarSelected"
|
|
@@ -15,17 +15,18 @@ const width = computed(() => {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
switch (props.character) {
|
|
18
|
-
case 'nada':
|
|
18
|
+
case 'nada': {
|
|
19
19
|
return size[props.size] + 4
|
|
20
|
-
|
|
21
|
-
case 'power':
|
|
20
|
+
}
|
|
21
|
+
case 'power': {
|
|
22
22
|
return size[props.size] + 3
|
|
23
|
-
|
|
24
|
-
case 'yoda':
|
|
23
|
+
}
|
|
24
|
+
case 'yoda': {
|
|
25
25
|
return size[props.size] + 8
|
|
26
|
-
|
|
27
|
-
default:
|
|
26
|
+
}
|
|
27
|
+
default: {
|
|
28
28
|
return size[props.size]
|
|
29
|
+
}
|
|
29
30
|
}
|
|
30
31
|
})
|
|
31
32
|
</script>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { BarChart, LineChart, PieChart } from 'chartist'
|
|
3
3
|
import type { BaseChart } from '../../types/bases'
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const properties = withDefaults(defineProps<BaseChart>(), {
|
|
6
6
|
data: () => ({
|
|
7
7
|
labels: [],
|
|
8
8
|
series: [],
|
|
@@ -16,18 +16,12 @@ const chart = ref()
|
|
|
16
16
|
const root = ref<HTMLDivElement>()
|
|
17
17
|
|
|
18
18
|
watch(
|
|
19
|
-
() =>
|
|
19
|
+
() => properties.data,
|
|
20
20
|
() => {
|
|
21
21
|
if (chart.value) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
else if (props.type === 'bar') {
|
|
26
|
-
chart.value.update((props.data as ChartistBarChartData), props.options)
|
|
27
|
-
}
|
|
28
|
-
else if (props.type === 'pie') {
|
|
29
|
-
chart.value.update((props.data as ChartistPieChartData), props.options)
|
|
30
|
-
}
|
|
22
|
+
const data = properties.data
|
|
23
|
+
|
|
24
|
+
return chart.value.update(data, properties.options)
|
|
31
25
|
}
|
|
32
26
|
},
|
|
33
27
|
{ deep: true },
|
|
@@ -35,14 +29,22 @@ watch(
|
|
|
35
29
|
|
|
36
30
|
onMounted(() => {
|
|
37
31
|
if (root.value) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
32
|
+
switch (properties.type) {
|
|
33
|
+
case 'bar': {
|
|
34
|
+
chart.value = new BarChart(root.value, (properties.data as ChartistBarChartData), properties.options)
|
|
35
|
+
|
|
36
|
+
break
|
|
37
|
+
}
|
|
38
|
+
case 'line': {
|
|
39
|
+
chart.value = new LineChart(root.value, (properties.data as ChartistLineChartData), properties.options)
|
|
40
|
+
|
|
41
|
+
break
|
|
42
|
+
}
|
|
43
|
+
case 'pie': {
|
|
44
|
+
chart.value = new PieChart(root.value, (properties.data as ChartistPieChartData), properties.options)
|
|
45
|
+
|
|
46
|
+
break
|
|
47
|
+
}
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
})
|
|
@@ -21,6 +21,12 @@ const { urls } = useAppConfig()
|
|
|
21
21
|
function onClick(event: MouseEvent) {
|
|
22
22
|
emit('click', event, props.emoji)
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
function onKeyDown(event: KeyboardEvent) {
|
|
26
|
+
if (props.clickable) {
|
|
27
|
+
(event.currentTarget as HTMLElement).click()
|
|
28
|
+
}
|
|
29
|
+
}
|
|
24
30
|
</script>
|
|
25
31
|
|
|
26
32
|
<template>
|
|
@@ -43,11 +49,15 @@ function onClick(event: MouseEvent) {
|
|
|
43
49
|
'h-16 w-16': size === '3xl' && hasBox,
|
|
44
50
|
'h-18 w-18': size === '4xl' && hasBox,
|
|
45
51
|
}"
|
|
52
|
+
role="button"
|
|
53
|
+
tabindex="0"
|
|
46
54
|
@click="onClick"
|
|
55
|
+
@keydown.enter="onKeyDown"
|
|
56
|
+
@keydown.space.prevent="onKeyDown"
|
|
47
57
|
>
|
|
48
58
|
<img
|
|
49
59
|
v-if="emoji"
|
|
50
|
-
class="flex"
|
|
60
|
+
class="pointer-events-none flex"
|
|
51
61
|
:class="{
|
|
52
62
|
'h-2.5 w-2.5': size === '3xs',
|
|
53
63
|
'h-3 w-3': size === '2xs',
|
|
@@ -60,9 +70,9 @@ function onClick(event: MouseEvent) {
|
|
|
60
70
|
'h-10 w-10': size === '3xl',
|
|
61
71
|
'h-12 w-12': size === '4xl',
|
|
62
72
|
}"
|
|
73
|
+
:alt="emoji"
|
|
63
74
|
loading="lazy"
|
|
64
75
|
:src="`${urls.storage}/images/emojis/${emoji}.svg`"
|
|
65
|
-
@click.stop="onClick"
|
|
66
76
|
>
|
|
67
77
|
|
|
68
78
|
<slot />
|
|
@@ -5,6 +5,7 @@ withDefaults(defineProps<BaseHeading>(), {
|
|
|
5
5
|
alignment: 'left',
|
|
6
6
|
size: 'base',
|
|
7
7
|
tag: 'h1',
|
|
8
|
+
text: '',
|
|
8
9
|
})
|
|
9
10
|
|
|
10
11
|
defineSlots<{
|
|
@@ -27,6 +28,11 @@ defineSlots<{
|
|
|
27
28
|
'text-2xl sm:text-4xl': size === 'lg',
|
|
28
29
|
}"
|
|
29
30
|
>
|
|
30
|
-
<
|
|
31
|
+
<BaseText
|
|
32
|
+
v-if="text"
|
|
33
|
+
:text="text"
|
|
34
|
+
/>
|
|
35
|
+
|
|
36
|
+
<slot v-else />
|
|
31
37
|
</component>
|
|
32
38
|
</template>
|
|
@@ -29,40 +29,47 @@ const confirming = ref(false)
|
|
|
29
29
|
const { t } = useI18n()
|
|
30
30
|
const { getIcon } = useLayerIcons()
|
|
31
31
|
|
|
32
|
+
const isClickable = computed(() => {
|
|
33
|
+
return props.clickable || props.to
|
|
34
|
+
})
|
|
35
|
+
|
|
32
36
|
const statusIcon = computed<string | undefined>(() => {
|
|
33
37
|
switch (props.status) {
|
|
34
|
-
case 'error':
|
|
38
|
+
case 'error': {
|
|
35
39
|
return getIcon('closeCircle')
|
|
36
|
-
|
|
37
|
-
case 'info':
|
|
40
|
+
}
|
|
41
|
+
case 'info': {
|
|
38
42
|
return getIcon('infoCircle')
|
|
39
|
-
|
|
40
|
-
case 'success':
|
|
43
|
+
}
|
|
44
|
+
case 'success': {
|
|
41
45
|
return getIcon('checkCircle')
|
|
42
|
-
|
|
43
|
-
case 'warning':
|
|
46
|
+
}
|
|
47
|
+
case 'warning': {
|
|
44
48
|
return getIcon('exclamationCircle')
|
|
45
|
-
|
|
46
|
-
default:
|
|
47
|
-
return
|
|
49
|
+
}
|
|
50
|
+
default: {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
48
53
|
}
|
|
49
54
|
})
|
|
50
55
|
|
|
51
56
|
const statusColor = computed<BaseColor | undefined>(() => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
57
|
+
switch (props.status) {
|
|
58
|
+
case 'error': {
|
|
59
|
+
return 'red'
|
|
60
|
+
}
|
|
61
|
+
case 'info': {
|
|
62
|
+
return 'indigo'
|
|
63
|
+
}
|
|
64
|
+
case 'success': {
|
|
65
|
+
return 'green'
|
|
66
|
+
}
|
|
67
|
+
case 'warning': {
|
|
68
|
+
return 'orange'
|
|
69
|
+
}
|
|
70
|
+
default: {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
66
73
|
}
|
|
67
74
|
})
|
|
68
75
|
|
|
@@ -91,17 +98,27 @@ function onClick(event: MouseEvent) {
|
|
|
91
98
|
|
|
92
99
|
emit('click', event)
|
|
93
100
|
}
|
|
101
|
+
|
|
102
|
+
function onKeyDown(event: KeyboardEvent) {
|
|
103
|
+
if (isClickable.value) {
|
|
104
|
+
(event.currentTarget as HTMLElement).click()
|
|
105
|
+
}
|
|
106
|
+
}
|
|
94
107
|
</script>
|
|
95
108
|
|
|
96
109
|
<template>
|
|
97
110
|
<div
|
|
98
111
|
class="flex items-center"
|
|
99
112
|
:class="{
|
|
100
|
-
'cursor-pointer hover:underline hover:text-gray-900 dark:hover:text-gray-100':
|
|
113
|
+
'cursor-pointer hover:underline hover:text-gray-900 dark:hover:text-gray-100': isClickable,
|
|
101
114
|
'flex-row': !reverse,
|
|
102
115
|
'flex-row-reverse': reverse,
|
|
103
116
|
}"
|
|
117
|
+
role="button"
|
|
118
|
+
tabindex="0"
|
|
104
119
|
@click="onClick"
|
|
120
|
+
@keydown.enter="onKeyDown"
|
|
121
|
+
@keydown.space.prevent="onKeyDown"
|
|
105
122
|
>
|
|
106
123
|
<component
|
|
107
124
|
:is="to ? NuxtLinkLocale : 'span'"
|
|
@@ -32,17 +32,15 @@ defineSlots<{
|
|
|
32
32
|
alignment="center"
|
|
33
33
|
size="sm"
|
|
34
34
|
tag="h1"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
</BaseHeading>
|
|
35
|
+
:text="title"
|
|
36
|
+
/>
|
|
38
37
|
|
|
39
38
|
<BaseParagraph
|
|
40
39
|
v-if="description"
|
|
41
40
|
alignment="center"
|
|
42
41
|
class="mt-2"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
</BaseParagraph>
|
|
42
|
+
:text="description"
|
|
43
|
+
/>
|
|
46
44
|
|
|
47
45
|
<div
|
|
48
46
|
v-if="$slots.default"
|
|
@@ -14,17 +14,18 @@ const { getIcon } = useLayerIcons()
|
|
|
14
14
|
|
|
15
15
|
const performanceIcon = computed<string | undefined>(() => {
|
|
16
16
|
switch (props.performance) {
|
|
17
|
-
case 'down':
|
|
17
|
+
case 'down': {
|
|
18
18
|
return getIcon('arrowDown')
|
|
19
|
-
|
|
20
|
-
case 'equal':
|
|
19
|
+
}
|
|
20
|
+
case 'equal': {
|
|
21
21
|
return getIcon('arrowRight')
|
|
22
|
-
|
|
23
|
-
case 'up':
|
|
22
|
+
}
|
|
23
|
+
case 'up': {
|
|
24
24
|
return getIcon('arrowUp')
|
|
25
|
-
|
|
26
|
-
default:
|
|
27
|
-
return
|
|
25
|
+
}
|
|
26
|
+
default: {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
28
29
|
}
|
|
29
30
|
})
|
|
30
31
|
</script>
|
|
@@ -4,7 +4,7 @@ import { Motion } from 'motion-v'
|
|
|
4
4
|
import type { BaseOverlay } from '../../types/bases'
|
|
5
5
|
import useMotion from '../../composables/useMotion'
|
|
6
6
|
|
|
7
|
-
withDefaults(defineProps<BaseOverlay>(), {
|
|
7
|
+
const props = withDefaults(defineProps<BaseOverlay>(), {
|
|
8
8
|
active: true,
|
|
9
9
|
clickable: true,
|
|
10
10
|
fixed: true,
|
|
@@ -25,6 +25,10 @@ defineSlots<{
|
|
|
25
25
|
const { getIcon } = useLayerIcons()
|
|
26
26
|
const { fadeIn } = useMotion()
|
|
27
27
|
|
|
28
|
+
const isClickable = computed(() => {
|
|
29
|
+
return props.clickable || props.hasClose
|
|
30
|
+
})
|
|
31
|
+
|
|
28
32
|
function onClick(event: MouseEvent) {
|
|
29
33
|
emit('click', event)
|
|
30
34
|
}
|
|
@@ -33,6 +37,12 @@ function onClose(event: KeyboardEvent | MouseEvent) {
|
|
|
33
37
|
emit('close', event)
|
|
34
38
|
}
|
|
35
39
|
|
|
40
|
+
function onKeyDown(event: KeyboardEvent) {
|
|
41
|
+
if (isClickable.value) {
|
|
42
|
+
(event.currentTarget as HTMLElement).click()
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
onKeyStroke('Escape', (event) => {
|
|
37
47
|
event.preventDefault()
|
|
38
48
|
|
|
@@ -44,13 +54,18 @@ onKeyStroke('Escape', (event) => {
|
|
|
44
54
|
<div
|
|
45
55
|
:class="{
|
|
46
56
|
'fixed inset-0': fixed,
|
|
47
|
-
'cursor-pointer':
|
|
57
|
+
'cursor-pointer': isClickable,
|
|
48
58
|
}"
|
|
59
|
+
role="button"
|
|
60
|
+
tabindex="0"
|
|
49
61
|
@click="onClick"
|
|
62
|
+
@keydown.enter="onKeyDown"
|
|
63
|
+
@keydown.space.prevent="onKeyDown"
|
|
50
64
|
>
|
|
51
65
|
<BaseIcon
|
|
52
66
|
v-if="hasClose"
|
|
53
|
-
class="absolute right-4 top-4 z-50 text-gray-200 dark:text-gray-800"
|
|
67
|
+
class="pointer-events-auto absolute right-4 top-4 z-50 text-gray-200 dark:text-gray-800"
|
|
68
|
+
clickable
|
|
54
69
|
:icon="getIcon('close')"
|
|
55
70
|
@click="onClose"
|
|
56
71
|
/>
|
|
@@ -4,6 +4,7 @@ import type { BaseParagraph } from '../../types/bases'
|
|
|
4
4
|
withDefaults(defineProps<BaseParagraph>(), {
|
|
5
5
|
alignment: 'left',
|
|
6
6
|
size: 'base',
|
|
7
|
+
text: '',
|
|
7
8
|
})
|
|
8
9
|
|
|
9
10
|
defineSlots<{
|
|
@@ -23,6 +24,11 @@ defineSlots<{
|
|
|
23
24
|
'text-lg sm:text-xl': size === 'lg',
|
|
24
25
|
}"
|
|
25
26
|
>
|
|
26
|
-
<
|
|
27
|
+
<BaseText
|
|
28
|
+
v-if="text"
|
|
29
|
+
:text="text"
|
|
30
|
+
/>
|
|
31
|
+
|
|
32
|
+
<slot v-else />
|
|
27
33
|
</p>
|
|
28
34
|
</template>
|
|
@@ -34,31 +34,30 @@ const { getIcon } = useLayerIcons()
|
|
|
34
34
|
const closed = ref(false)
|
|
35
35
|
|
|
36
36
|
const finalBackground = computed(() => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return props.background
|
|
42
|
-
}
|
|
37
|
+
const isBackgroundGray = props.background === 'gray'
|
|
38
|
+
const isReverseWithNonGrayLight = props.reverse && props.background !== 'gray-light'
|
|
39
|
+
|
|
40
|
+
return (isBackgroundGray || isReverseWithNonGrayLight) ? 'gray' : props.background
|
|
43
41
|
})
|
|
44
42
|
|
|
45
43
|
const finalReverse = computed(() => {
|
|
46
|
-
return props.reverse
|
|
44
|
+
return props.reverse === null ? props.character !== 'julien' : props.reverse
|
|
47
45
|
})
|
|
48
46
|
|
|
49
47
|
onMounted(() => {
|
|
50
|
-
|
|
51
|
-
closed.value = localStorage.getItem(props.closingId) === 'true'
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
closed.value = false
|
|
55
|
-
}
|
|
48
|
+
closed.value = props.hasClose && props.closingId ? localStorage.getItem(props.closingId) === 'true' : false
|
|
56
49
|
})
|
|
57
50
|
|
|
58
51
|
function onBubbleClick(event: MouseEvent) {
|
|
59
52
|
emit('click', event)
|
|
60
53
|
}
|
|
61
54
|
|
|
55
|
+
function onBubbleKeyDown(event: KeyboardEvent) {
|
|
56
|
+
if (props.clickable) {
|
|
57
|
+
(event.currentTarget as HTMLElement).click()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
62
61
|
function onClose(event: MouseEvent) {
|
|
63
62
|
if (props.closingId) {
|
|
64
63
|
localStorage.setItem(props.closingId, 'true')
|
|
@@ -108,7 +107,12 @@ function onClose(event: MouseEvent) {
|
|
|
108
107
|
'border-green-600 dark:border-green-400 text-green-600 dark:text-green-400': status === 'success',
|
|
109
108
|
'border-orange-600 dark:border-orange-400 text-orange-600 dark:text-orange-400': status === 'warning',
|
|
110
109
|
}"
|
|
110
|
+
role="button"
|
|
111
|
+
:aria-disabled="!clickable"
|
|
112
|
+
tabindex="0"
|
|
111
113
|
@click="onBubbleClick"
|
|
114
|
+
@keydown.enter="onBubbleKeyDown"
|
|
115
|
+
@keydown.space.prevent="onBubbleKeyDown"
|
|
112
116
|
>
|
|
113
117
|
<div class="flex items-center">
|
|
114
118
|
<div
|
|
@@ -119,10 +123,9 @@ function onClose(event: MouseEvent) {
|
|
|
119
123
|
</div>
|
|
120
124
|
|
|
121
125
|
<div class="flex-1">
|
|
122
|
-
<p
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
/>
|
|
126
|
+
<p v-if="!forceSlot">
|
|
127
|
+
{{ translatedContent }}
|
|
128
|
+
</p>
|
|
126
129
|
|
|
127
130
|
<slot v-else />
|
|
128
131
|
</div>
|
|
@@ -18,6 +18,12 @@ const emit = defineEmits<{
|
|
|
18
18
|
function onClick(event: MouseEvent) {
|
|
19
19
|
emit('click', event, props.id)
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
function onKeyDown(event: KeyboardEvent) {
|
|
23
|
+
if (props.clickable) {
|
|
24
|
+
(event.currentTarget as HTMLElement).click()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
21
27
|
</script>
|
|
22
28
|
|
|
23
29
|
<template>
|
|
@@ -28,7 +34,12 @@ function onClick(event: MouseEvent) {
|
|
|
28
34
|
'flex-row': !reverse,
|
|
29
35
|
'flex-row-reverse': reverse,
|
|
30
36
|
}"
|
|
37
|
+
role="button"
|
|
38
|
+
:aria-disabled="!clickable"
|
|
39
|
+
tabindex="0"
|
|
31
40
|
@click="onClick"
|
|
41
|
+
@keydown.enter="onKeyDown"
|
|
42
|
+
@keydown.space.prevent="onKeyDown"
|
|
32
43
|
>
|
|
33
44
|
<div
|
|
34
45
|
class="relative inline-block cursor-wait flex-initial"
|
|
@@ -44,7 +55,6 @@ function onClick(event: MouseEvent) {
|
|
|
44
55
|
'h-10 w-10': size === '3xl',
|
|
45
56
|
'h-12 w-12': size === '4xl',
|
|
46
57
|
}"
|
|
47
|
-
@click="onClick"
|
|
48
58
|
>
|
|
49
59
|
<div
|
|
50
60
|
v-for="wave in 2"
|
|
@@ -49,7 +49,11 @@ onBeforeMount(() => {
|
|
|
49
49
|
})
|
|
50
50
|
|
|
51
51
|
function initializeFormForExistingTag() {
|
|
52
|
-
form.name = String(props.text)?.
|
|
52
|
+
form.name = String(props.text)?.slice(1)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function onBlur() {
|
|
56
|
+
hovered.value = false
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
function onClick(event: MouseEvent) {
|
|
@@ -58,6 +62,10 @@ function onClick(event: MouseEvent) {
|
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
|
|
65
|
+
function onFocus() {
|
|
66
|
+
hovered.value = true
|
|
67
|
+
}
|
|
68
|
+
|
|
61
69
|
function onInputBlur(event: FocusEvent) {
|
|
62
70
|
emit('inputBlur', event, form.name.trim(), props.id)
|
|
63
71
|
}
|
|
@@ -66,6 +74,12 @@ function onInputSubmit(event: KeyboardEvent) {
|
|
|
66
74
|
emit('inputSubmit', event, form.name.trim(), props.id)
|
|
67
75
|
}
|
|
68
76
|
|
|
77
|
+
function onKeyDown(event: KeyboardEvent) {
|
|
78
|
+
if (props.clickable) {
|
|
79
|
+
(event.currentTarget as HTMLElement).click()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
69
83
|
function onMouseEnter() {
|
|
70
84
|
hovered.value = true
|
|
71
85
|
}
|
|
@@ -82,9 +96,16 @@ function onRemove(event: MouseEvent) {
|
|
|
82
96
|
<template>
|
|
83
97
|
<span
|
|
84
98
|
class="flex select-none"
|
|
99
|
+
role="button"
|
|
100
|
+
:aria-disabled="!clickable"
|
|
101
|
+
tabindex="0"
|
|
85
102
|
@click.stop="onClick"
|
|
103
|
+
@keydown.enter.stop="onKeyDown"
|
|
104
|
+
@keydown.space.prevent.stop="onKeyDown"
|
|
86
105
|
@mouseenter="onMouseEnter"
|
|
87
106
|
@mouseleave="onMouseLeave"
|
|
107
|
+
@focusin="onFocus"
|
|
108
|
+
@focusout="onBlur"
|
|
88
109
|
>
|
|
89
110
|
<component
|
|
90
111
|
:is="to ? NuxtLinkLocale : 'span'"
|