veloce-vue 0.40.0 → 0.45.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.
- package/components/Button.vue +68 -55
- package/components/Checkbox.vue +52 -48
- package/components/Input.vue +50 -25
- package/components/toast/ToastContainer.vue +38 -20
- package/composables/useToast.ts +41 -24
- package/package.json +1 -1
- package/styles/index.css +5 -3
- package/styles/utilities.css +1 -2
- package/types/components/Button.vue.d.ts +2 -2
- package/types/components/Checkbox.vue.d.ts +12 -3
- package/types/components/Input.vue.d.ts +2 -2
- package/types/components/toast/ToastContainer.vue.d.ts +11 -2
- package/types/composables/useToast.d.ts +20 -9
package/components/Button.vue
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, type Component } from
|
|
3
|
-
import { Icon, Loading } from
|
|
4
|
-
import { type Variant, type Severity, type Position, type Size, type FontWeight } from
|
|
2
|
+
import { computed, type Component } from "vue";
|
|
3
|
+
import { Icon, Loading } from "../exports/icons";
|
|
4
|
+
import { type Variant, type Severity, type Position, type Size, type FontWeight } from "../exports/types";
|
|
5
5
|
|
|
6
6
|
const props = defineProps({
|
|
7
|
-
label: { type: String, default:
|
|
7
|
+
label: { type: String, default: "" },
|
|
8
8
|
loading: { type: Boolean, default: false },
|
|
9
9
|
disabled: { type: Boolean, default: false },
|
|
10
|
-
variant: { type: String as () => Variant, default:
|
|
11
|
-
severity: { type: String as () => Severity, default:
|
|
10
|
+
variant: { type: String as () => Variant, default: "solid" },
|
|
11
|
+
severity: { type: String as () => Severity, default: "primary" },
|
|
12
12
|
icon: { type: Object as () => Component, default: () => null },
|
|
13
|
-
iconClass: { type: String, default:
|
|
14
|
-
iconPosition: { type: String as () => Position, default:
|
|
13
|
+
iconClass: { type: String, default: "" },
|
|
14
|
+
iconPosition: { type: String as () => Position, default: "right" },
|
|
15
15
|
rounded: { type: Boolean, default: false },
|
|
16
|
-
size: { type: String as () => Size, default:
|
|
17
|
-
fontWeight: { type: String as () => FontWeight, default:
|
|
16
|
+
size: { type: String as () => Size, default: "md" },
|
|
17
|
+
fontWeight: { type: String as () => FontWeight, default: "medium" as FontWeight },
|
|
18
18
|
neumorphic: { type: Boolean, default: false },
|
|
19
19
|
highlighted: { type: Boolean, default: false },
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
const severityClasses = {
|
|
23
23
|
primary: {
|
|
24
|
-
ghost:
|
|
25
|
-
outlined:
|
|
26
|
-
link:
|
|
27
|
-
soft:
|
|
28
|
-
solid:
|
|
29
|
-
neutral:
|
|
24
|
+
ghost: "bg-transparent text-primary hover:bg-primary/10 dark:hover:bg-neutral-800",
|
|
25
|
+
outlined: "border-primary! text-primary hover:bg-primary hover:text-inverted disabled:hover:text-primary disabled:hover:bg-primary disabled:hover:text-inverted",
|
|
26
|
+
link: "text-primary hover:underline",
|
|
27
|
+
soft: "bg-primary-light text-primary hover:bg-primary-light/80 dark:bg-primary/10 dark:text-primary dark:hover:bg-primary/20",
|
|
28
|
+
solid: "bg-primary text-inverted hover:bg-primary/70 disabled:hover:bg-primary dark:hover:bg-primary/80",
|
|
29
|
+
neutral: "bg-neutral-100 text-neutral-700 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700",
|
|
30
30
|
},
|
|
31
31
|
secondary: {
|
|
32
|
-
ghost:
|
|
33
|
-
outlined:
|
|
34
|
-
link:
|
|
35
|
-
soft:
|
|
36
|
-
solid:
|
|
37
|
-
neutral:
|
|
32
|
+
ghost: "bg-transparent text-secondary hover:bg-secondary/10 dark:hover:bg-neutral-800",
|
|
33
|
+
outlined: "border-secondary! text-secondary hover:bg-secondary hover:text-inverted disabled:hover:text-secondary disabled:hover:bg-secondary disabled:hover:text-inverted",
|
|
34
|
+
link: "text-secondary hover:underline",
|
|
35
|
+
soft: "bg-secondary-light text-secondary hover:bg-secondary-light/80 dark:bg-secondary/10 dark:text-secondary dark:hover:bg-secondary/20",
|
|
36
|
+
solid: "bg-secondary text-inverted hover:bg-secondary/70 disabled:hover:bg-secondary dark:hover:bg-secondary/80",
|
|
37
|
+
neutral: "bg-neutral-100 text-neutral-700 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700",
|
|
38
38
|
},
|
|
39
39
|
success: {
|
|
40
|
-
ghost:
|
|
41
|
-
outlined:
|
|
42
|
-
link:
|
|
43
|
-
soft:
|
|
44
|
-
solid:
|
|
45
|
-
neutral:
|
|
40
|
+
ghost: "bg-transparent text-success hover:bg-success/10 dark:hover:bg-neutral-800",
|
|
41
|
+
outlined: "border-success! text-success hover:bg-success hover:text-inverted disabled:hover:text-success disabled:hover:bg-success disabled:hover:text-inverted",
|
|
42
|
+
link: "text-success hover:underline",
|
|
43
|
+
soft: "bg-success-light text-success hover:bg-success-light/80 dark:bg-success/10 dark:text-success dark:hover:bg-success/20",
|
|
44
|
+
solid: "bg-success text-inverted hover:bg-success/70 disabled:hover:bg-success dark:hover:bg-success/80",
|
|
45
|
+
neutral: "bg-neutral-100 text-neutral-700 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700",
|
|
46
46
|
},
|
|
47
47
|
info: {
|
|
48
|
-
ghost:
|
|
49
|
-
outlined:
|
|
50
|
-
link:
|
|
51
|
-
soft:
|
|
52
|
-
solid:
|
|
53
|
-
neutral:
|
|
48
|
+
ghost: "bg-transparent text-info hover:bg-info/10 dark:hover:bg-neutral-800",
|
|
49
|
+
outlined: "border-info! text-info hover:bg-info hover:text-inverted disabled:hover:text-info disabled:hover:bg-info disabled:hover:text-inverted",
|
|
50
|
+
link: "text-info hover:underline",
|
|
51
|
+
soft: "bg-info-light text-info hover:bg-info-light/80 dark:bg-info/10 dark:text-info dark:hover:bg-info/20",
|
|
52
|
+
solid: "bg-info text-inverted hover:bg-info/70 disabled:hover:bg-info dark:hover:bg-info/80",
|
|
53
|
+
neutral: "bg-neutral-100 text-neutral-700 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700",
|
|
54
54
|
},
|
|
55
55
|
warning: {
|
|
56
|
-
ghost:
|
|
57
|
-
outlined:
|
|
58
|
-
link:
|
|
59
|
-
soft:
|
|
60
|
-
solid:
|
|
61
|
-
neutral:
|
|
56
|
+
ghost: "bg-transparent text-warning hover:bg-warning/10 dark:hover:bg-neutral-800",
|
|
57
|
+
outlined: "border-warning! text-warning hover:bg-warning hover:text-inverted disabled:hover:text-warning disabled:hover:bg-warning disabled:hover:text-inverted",
|
|
58
|
+
link: "text-warning hover:underline",
|
|
59
|
+
soft: "bg-warning-light text-warning hover:bg-warning-light/80 dark:bg-warning/10 dark:text-warning dark:hover:bg-warning/20",
|
|
60
|
+
solid: "bg-warning text-inverted hover:bg-warning/70 disabled:hover:bg-warning dark:hover:bg-warning/80",
|
|
61
|
+
neutral: "bg-neutral-100 text-neutral-700 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700",
|
|
62
62
|
},
|
|
63
63
|
error: {
|
|
64
|
-
ghost:
|
|
65
|
-
outlined:
|
|
66
|
-
link:
|
|
67
|
-
soft:
|
|
68
|
-
solid:
|
|
69
|
-
neutral:
|
|
64
|
+
ghost: "bg-transparent text-error hover:bg-error/10 dark:hover:bg-neutral-800",
|
|
65
|
+
outlined: "border-error! text-error hover:bg-error hover:text-inverted disabled:hover:text-error disabled:hover:bg-error disabled:hover:text-inverted",
|
|
66
|
+
link: "text-error hover:underline",
|
|
67
|
+
soft: "bg-error-light text-error hover:bg-error-light/80 dark:bg-error/10 dark:text-error dark:hover:bg-error/20",
|
|
68
|
+
solid: "bg-error text-inverted hover:bg-error/70 disabled:hover:bg-error dark:hover:bg-error/80",
|
|
69
|
+
neutral: "bg-neutral-100 text-neutral-700 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700",
|
|
70
70
|
},
|
|
71
71
|
neutral: {
|
|
72
|
-
ghost:
|
|
73
|
-
outlined:
|
|
74
|
-
link:
|
|
75
|
-
soft:
|
|
76
|
-
solid:
|
|
77
|
-
neutral:
|
|
72
|
+
ghost: "bg-transparent text-neutral-700 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-800",
|
|
73
|
+
outlined: "border-neutral-300! dark:border-neutral-700! text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-800 disabled:hover:text-neutral-700 disabled:hover:text-inverted",
|
|
74
|
+
link: "text-neutral-700 dark:text-neutral-300 hover:underline",
|
|
75
|
+
soft: "bg-neutral-100 text-neutral-700 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700",
|
|
76
|
+
solid: "bg-neutral-100 dark:bg-neutral-800 text-neutral-700 hover:bg-neutral-200 dark:hover:bg-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-100/80",
|
|
77
|
+
neutral: "bg-neutral-100 text-neutral-700 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-200 dark:hover:bg-neutral-700",
|
|
78
78
|
},
|
|
79
79
|
};
|
|
80
80
|
|
|
@@ -84,7 +84,20 @@ const classes = computed(() => {
|
|
|
84
84
|
</script>
|
|
85
85
|
|
|
86
86
|
<template>
|
|
87
|
-
<button
|
|
87
|
+
<button
|
|
88
|
+
type="button"
|
|
89
|
+
:disabled="props.disabled || props.loading"
|
|
90
|
+
:class="[
|
|
91
|
+
classes,
|
|
92
|
+
{ 'rounded-full': props.rounded },
|
|
93
|
+
{ 'justify-center': !props.icon },
|
|
94
|
+
{ 'px-2 py-1 text-sm': props.size === 'sm', 'px-2.5 py-1.5 text-sm': props.size === 'md', 'px-3 py-2 text-base': props.size === 'lg', 'px-3.5 py-2.5 text-lg': props.size === 'xl' },
|
|
95
|
+
{ 'font-normal': props.fontWeight === 'normal', 'font-medium': props.fontWeight === 'medium', 'font-semibold': props.fontWeight === 'semibold', 'font-bold': props.fontWeight === 'bold' },
|
|
96
|
+
{ 'veloce-button-neumorphic': props.neumorphic },
|
|
97
|
+
{ 'bg-highlight': props.highlighted },
|
|
98
|
+
]"
|
|
99
|
+
class="flex cursor-pointer items-center justify-center gap-2 rounded border border-transparent transition-all duration-200 focus:outline-none disabled:cursor-not-allowed disabled:opacity-75"
|
|
100
|
+
>
|
|
88
101
|
<slot v-if="$slots.default" />
|
|
89
102
|
<template v-else>
|
|
90
103
|
<span v-if="props.label" :class="{ 'order-2': props.iconPosition === 'left' }"> {{ props.label }} </span>
|
|
@@ -93,12 +106,12 @@ const classes = computed(() => {
|
|
|
93
106
|
</template>
|
|
94
107
|
</button>
|
|
95
108
|
</template>
|
|
96
|
-
<style
|
|
109
|
+
<style>
|
|
97
110
|
.veloce-button-neumorphic {
|
|
98
111
|
position: relative;
|
|
99
112
|
|
|
100
113
|
&::after {
|
|
101
|
-
content:
|
|
114
|
+
content: " ";
|
|
102
115
|
position: absolute;
|
|
103
116
|
inset: -1px;
|
|
104
117
|
border-top: inset;
|
package/components/Checkbox.vue
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { Icon, Check } from
|
|
3
|
-
import { computed, type Component } from
|
|
2
|
+
import { Icon, Check } from "../exports/icons";
|
|
3
|
+
import { computed, type Component } from "vue";
|
|
4
4
|
|
|
5
|
-
type CheckboxSize =
|
|
6
|
-
type CheckboxVariant =
|
|
5
|
+
type CheckboxSize = "sm" | "md" | "lg";
|
|
6
|
+
type CheckboxVariant = "primary" | "secondary" | "success" | "info" | "error" | "warning";
|
|
7
7
|
|
|
8
8
|
const props = defineProps({
|
|
9
|
-
label: { type: String, default:
|
|
10
|
-
labelClass: { type: String, default:
|
|
11
|
-
checkboxClass: { type: String, default:
|
|
12
|
-
size: { type: String as () => CheckboxSize, default:
|
|
13
|
-
variant: { type: String as () => CheckboxVariant, default:
|
|
9
|
+
label: { type: String, default: "" },
|
|
10
|
+
labelClass: { type: String, default: "" },
|
|
11
|
+
checkboxClass: { type: String, default: "" },
|
|
12
|
+
size: { type: String as () => CheckboxSize, default: "md" },
|
|
13
|
+
variant: { type: String as () => CheckboxVariant, default: "primary" },
|
|
14
14
|
icon: { type: Object as () => Component, default: () => Check },
|
|
15
|
+
iconClass: { type: String, default: "" },
|
|
15
16
|
disabled: { type: Boolean, default: false },
|
|
16
17
|
});
|
|
17
18
|
|
|
@@ -20,22 +21,22 @@ const model = defineModel<boolean>({ required: true });
|
|
|
20
21
|
const getSizeClasses = computed(() => {
|
|
21
22
|
const sizes = {
|
|
22
23
|
sm: {
|
|
23
|
-
checkbox:
|
|
24
|
-
icon:
|
|
25
|
-
gap:
|
|
26
|
-
text:
|
|
24
|
+
checkbox: "size-4",
|
|
25
|
+
icon: "size-3",
|
|
26
|
+
gap: "gap-1.5",
|
|
27
|
+
text: "text-sm",
|
|
27
28
|
},
|
|
28
29
|
md: {
|
|
29
|
-
checkbox:
|
|
30
|
-
icon:
|
|
31
|
-
gap:
|
|
32
|
-
text:
|
|
30
|
+
checkbox: "size-5",
|
|
31
|
+
icon: "size-5",
|
|
32
|
+
gap: "gap-2",
|
|
33
|
+
text: "text-base",
|
|
33
34
|
},
|
|
34
35
|
lg: {
|
|
35
|
-
checkbox:
|
|
36
|
-
icon:
|
|
37
|
-
gap:
|
|
38
|
-
text:
|
|
36
|
+
checkbox: "size-6",
|
|
37
|
+
icon: "size-6",
|
|
38
|
+
gap: "gap-2.5",
|
|
39
|
+
text: "text-lg",
|
|
39
40
|
},
|
|
40
41
|
};
|
|
41
42
|
return sizes[props.size];
|
|
@@ -44,40 +45,40 @@ const getSizeClasses = computed(() => {
|
|
|
44
45
|
const getVariantClasses = computed(() => {
|
|
45
46
|
const variants = {
|
|
46
47
|
primary: {
|
|
47
|
-
bg:
|
|
48
|
-
border:
|
|
49
|
-
text:
|
|
50
|
-
hover:
|
|
48
|
+
bg: "bg-primary",
|
|
49
|
+
border: "border-primary",
|
|
50
|
+
text: "text-white",
|
|
51
|
+
hover: "hover:border-primary/70",
|
|
51
52
|
},
|
|
52
53
|
secondary: {
|
|
53
|
-
bg:
|
|
54
|
-
border:
|
|
55
|
-
text:
|
|
56
|
-
hover:
|
|
54
|
+
bg: "bg-secondary",
|
|
55
|
+
border: "border-secondary",
|
|
56
|
+
text: "text-white",
|
|
57
|
+
hover: "hover:border-secondary/70",
|
|
57
58
|
},
|
|
58
59
|
success: {
|
|
59
|
-
bg:
|
|
60
|
-
border:
|
|
61
|
-
text:
|
|
62
|
-
hover:
|
|
60
|
+
bg: "bg-success",
|
|
61
|
+
border: "border-success",
|
|
62
|
+
text: "text-white",
|
|
63
|
+
hover: "hover:border-success/70",
|
|
63
64
|
},
|
|
64
65
|
info: {
|
|
65
|
-
bg:
|
|
66
|
-
border:
|
|
67
|
-
text:
|
|
68
|
-
hover:
|
|
66
|
+
bg: "bg-info",
|
|
67
|
+
border: "border-info",
|
|
68
|
+
text: "text-white",
|
|
69
|
+
hover: "hover:border-info/70",
|
|
69
70
|
},
|
|
70
71
|
warning: {
|
|
71
|
-
bg:
|
|
72
|
-
border:
|
|
73
|
-
text:
|
|
74
|
-
hover:
|
|
72
|
+
bg: "bg-warning",
|
|
73
|
+
border: "border-warning",
|
|
74
|
+
text: "text-white",
|
|
75
|
+
hover: "hover:border-warning/70",
|
|
75
76
|
},
|
|
76
77
|
error: {
|
|
77
|
-
bg:
|
|
78
|
-
border:
|
|
79
|
-
text:
|
|
80
|
-
hover:
|
|
78
|
+
bg: "bg-error",
|
|
79
|
+
border: "border-error",
|
|
80
|
+
text: "text-white",
|
|
81
|
+
hover: "hover:border-error/70",
|
|
81
82
|
},
|
|
82
83
|
};
|
|
83
84
|
return variants[props.variant];
|
|
@@ -85,9 +86,12 @@ const getVariantClasses = computed(() => {
|
|
|
85
86
|
</script>
|
|
86
87
|
|
|
87
88
|
<template>
|
|
88
|
-
<div :class="[getSizeClasses.gap, props.disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer']" class="flex w-fit select-none
|
|
89
|
-
<div
|
|
90
|
-
|
|
89
|
+
<div :class="[getSizeClasses.gap, props.disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer']" class="flex w-fit items-center select-none" @click="!props.disabled ? (model = !model) : null">
|
|
90
|
+
<div
|
|
91
|
+
:class="[getSizeClasses.checkbox, model ? [getVariantClasses.bg, getVariantClasses.border] : [getVariantClasses.border, props.disabled ? 'opacity-50' : getVariantClasses.hover], checkboxClass]"
|
|
92
|
+
class="m-0 flex items-center justify-center rounded-sm border-2 duration-200"
|
|
93
|
+
>
|
|
94
|
+
<Icon v-if="model" :icon="icon" :class="`${getSizeClasses.icon} ${getVariantClasses.text} ${iconClass}`" />
|
|
91
95
|
</div>
|
|
92
96
|
<div :class="[labelClass, getSizeClasses.text]">{{ label }}</div>
|
|
93
97
|
</div>
|
package/components/Input.vue
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, ref, type Component } from
|
|
3
|
-
import { useRandomId } from
|
|
4
|
-
import { Icon, Eye, EyeOff } from
|
|
5
|
-
import { type Size } from
|
|
2
|
+
import { computed, ref, type Component } from "vue";
|
|
3
|
+
import { useRandomId } from "../exports/utils";
|
|
4
|
+
import { Icon, Eye, EyeOff } from "../exports/icons";
|
|
5
|
+
import { type Size } from "../exports/types";
|
|
6
6
|
|
|
7
7
|
const id = useRandomId();
|
|
8
8
|
|
|
9
9
|
const props = defineProps({
|
|
10
10
|
leadingIcon: { type: Object as () => Component, default: () => null },
|
|
11
11
|
trailingIcon: { type: Object as () => Component, default: () => null },
|
|
12
|
-
placeholder: { type: String, default:
|
|
13
|
-
iconClass: { type: String, default:
|
|
14
|
-
helpText: { type: String, default:
|
|
15
|
-
type: { type: String as () =>
|
|
16
|
-
labelStyle: { type: String as () =>
|
|
17
|
-
label: { type: String, default:
|
|
18
|
-
size: { type: String as () => Size, default:
|
|
12
|
+
placeholder: { type: String, default: "" },
|
|
13
|
+
iconClass: { type: String, default: "" },
|
|
14
|
+
helpText: { type: String, default: "" },
|
|
15
|
+
type: { type: String as () => "text" | "password", default: "text" },
|
|
16
|
+
labelStyle: { type: String as () => "float" | "static", default: "static" },
|
|
17
|
+
label: { type: String, default: "" },
|
|
18
|
+
size: { type: String as () => Size, default: "md" },
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
const model = defineModel();
|
|
@@ -27,14 +27,14 @@ const togglePasswordVisibility = () => (isPasswordVisible.value = !isPasswordVis
|
|
|
27
27
|
|
|
28
28
|
const sizeClasses = computed(() => {
|
|
29
29
|
switch (props.size) {
|
|
30
|
-
case
|
|
31
|
-
return { container:
|
|
32
|
-
case
|
|
33
|
-
return { container:
|
|
34
|
-
case
|
|
35
|
-
return { container:
|
|
36
|
-
case
|
|
37
|
-
return { container:
|
|
30
|
+
case "sm":
|
|
31
|
+
return { container: "h-[30px]", input: "px-2 py-1 text-sm", icon: "size-4", text: "text-sm", floatLabel: { focus: "text-xs", base: "text-sm" } };
|
|
32
|
+
case "md":
|
|
33
|
+
return { container: "h-[34px]", input: "px-2.5 py-1.5 text-sm", icon: "size-4", text: "text-sm", floatLabel: { focus: "text-xs", base: "text-sm" } };
|
|
34
|
+
case "lg":
|
|
35
|
+
return { container: "h-[42px]", input: "px-3 py-2 text-base", icon: "size-5", text: "text-base", floatLabel: { focus: "text-sm", base: "text-base" } };
|
|
36
|
+
case "xl":
|
|
37
|
+
return { container: "h-[50px]", input: "px-3.5 py-2.5 text-lg", icon: "size-6", text: "text-lg", floatLabel: { focus: "text-sm", base: "text-lg" } };
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
</script>
|
|
@@ -45,21 +45,46 @@ const sizeClasses = computed(() => {
|
|
|
45
45
|
<label class="text-sm font-medium duration-100" :for="id">{{ label }}</label>
|
|
46
46
|
</div>
|
|
47
47
|
|
|
48
|
-
<div :class="[
|
|
48
|
+
<div :class="[sizeClasses.container]" class="relative">
|
|
49
49
|
<!-- leading icon -->
|
|
50
|
-
<Icon v-if="leadingIcon" :icon="leadingIcon" :class="[sizeClasses.icon, iconClass]" class="text-muted absolute
|
|
50
|
+
<Icon v-if="leadingIcon" :icon="leadingIcon" :class="[sizeClasses.icon, iconClass]" class="text-muted absolute top-1/2 left-3 -translate-y-1/2" />
|
|
51
51
|
<!-- trailing icon -->
|
|
52
|
-
<Icon v-if="trailingIcon" :icon="trailingIcon" :class="[sizeClasses.icon, iconClass]" class="text-muted absolute
|
|
52
|
+
<Icon v-if="trailingIcon" :icon="trailingIcon" :class="[sizeClasses.icon, iconClass]" class="text-muted absolute top-1/2 right-3 -translate-y-1/2" />
|
|
53
53
|
|
|
54
54
|
<!-- input -->
|
|
55
|
-
<input
|
|
55
|
+
<input
|
|
56
|
+
:type="type === 'password' && isPasswordVisible ? 'text' : type"
|
|
57
|
+
v-model="model"
|
|
58
|
+
:class="[
|
|
59
|
+
sizeClasses.input,
|
|
60
|
+
sizeClasses.text,
|
|
61
|
+
{ 'pr-12': props.type === 'password' },
|
|
62
|
+
{ 'pl-10': leadingIcon && props.size === 'md' },
|
|
63
|
+
{ 'pl-9': leadingIcon && props.size === 'sm' },
|
|
64
|
+
{ 'pl-11': leadingIcon && props.size === 'lg' },
|
|
65
|
+
{ 'pl-12': leadingIcon && props.size === 'xl' },
|
|
66
|
+
{ 'pr-10': trailingIcon && props.type !== 'password' && props.size === 'md' },
|
|
67
|
+
{ 'pr-9': trailingIcon && props.type !== 'password' && props.size === 'sm' },
|
|
68
|
+
{ 'pr-11': trailingIcon && props.type !== 'password' && props.size === 'lg' },
|
|
69
|
+
{ 'pr-12': trailingIcon && props.type !== 'password' && props.size === 'xl' },
|
|
70
|
+
]"
|
|
71
|
+
class="outline-primary dark:placeholder:text-muted focus:border-primary/75 peer h-full w-full rounded border duration-200 outline-none"
|
|
72
|
+
:id="id"
|
|
73
|
+
:placeholder="labelStyle === 'float' ? ' ' : placeholder"
|
|
74
|
+
@focus="isFocused = true"
|
|
75
|
+
@blur="isFocused = false"
|
|
76
|
+
/>
|
|
56
77
|
<!-- floating label -->
|
|
57
|
-
<div
|
|
78
|
+
<div
|
|
79
|
+
v-if="labelStyle === 'float'"
|
|
80
|
+
:class="[model || isFocused ? `-top-1.5 px-0.5 ${sizeClasses.floatLabel.focus}` : `top-0 bottom-0 my-auto ${sizeClasses.floatLabel.base}`]"
|
|
81
|
+
class="bg-background dark:text-muted absolute left-2.5 h-fit rounded leading-none text-neutral-400 duration-100"
|
|
82
|
+
>
|
|
58
83
|
{{ placeholder }}
|
|
59
84
|
</div>
|
|
60
85
|
|
|
61
86
|
<!-- password toggle -->
|
|
62
|
-
<div v-if="type === 'password'" class="absolute
|
|
87
|
+
<div v-if="type === 'password'" class="absolute top-1/2 right-4 -translate-y-1/2 cursor-pointer" @click="togglePasswordVisibility">
|
|
63
88
|
<Icon :icon="isPasswordVisible ? EyeOff : Eye" :class="sizeClasses.icon" class="text-muted" />
|
|
64
89
|
</div>
|
|
65
90
|
</div>
|
|
@@ -1,50 +1,64 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="containerClasses" class="w-full sm:w-auto">
|
|
2
|
+
<div :class="containerClasses" class="w-full sm:w-auto" :id="containerId">
|
|
3
3
|
<AnimatePresence>
|
|
4
|
-
<Toast
|
|
4
|
+
<Toast
|
|
5
|
+
v-for="(toast, index) in toasts"
|
|
6
|
+
:key="toast.id"
|
|
7
|
+
:icon="toast.icon"
|
|
8
|
+
class="pointer-events-auto"
|
|
9
|
+
:style="{ zIndex: index + 1 }"
|
|
10
|
+
:id="toast.id"
|
|
11
|
+
:message="toast.message"
|
|
12
|
+
:severity="toast.severity"
|
|
13
|
+
:duration="toast.duration"
|
|
14
|
+
:closable="toast.closable"
|
|
15
|
+
:position="position"
|
|
16
|
+
@close="removeToast"
|
|
17
|
+
/>
|
|
5
18
|
</AnimatePresence>
|
|
6
19
|
</div>
|
|
7
20
|
</template>
|
|
8
21
|
|
|
9
22
|
<script setup lang="ts">
|
|
10
|
-
import { ref, computed, onMounted, type Ref } from
|
|
11
|
-
import { AnimatePresence } from
|
|
12
|
-
import Toast from
|
|
13
|
-
import { setToastContainer } from
|
|
14
|
-
import type { ToastItem } from
|
|
15
|
-
import { useRandomId } from
|
|
23
|
+
import { ref, computed, onMounted, onUnmounted, type Ref } from "vue";
|
|
24
|
+
import { AnimatePresence } from "motion-v";
|
|
25
|
+
import Toast from "./Toast.vue";
|
|
26
|
+
import { setToastContainer } from "../../exports/toast";
|
|
27
|
+
import type { ToastItem } from "../../exports/toast";
|
|
28
|
+
import { useRandomId } from "../../exports/utils";
|
|
16
29
|
|
|
17
30
|
const props = defineProps({
|
|
18
|
-
position: { type: String as () =>
|
|
31
|
+
position: { type: String as () => "top-center" | "bottom-center" | "top-right" | "top-left" | "bottom-right" | "bottom-left", default: "top-right" },
|
|
19
32
|
maxToasts: { type: Number, default: 5 },
|
|
33
|
+
containerId: { type: String, default: "default-toast-container" },
|
|
20
34
|
});
|
|
21
35
|
|
|
22
36
|
const toasts: Ref<ToastItem[]> = ref<ToastItem[]>([]);
|
|
23
37
|
|
|
24
38
|
const containerClasses = computed(() => {
|
|
25
|
-
const baseClasses =
|
|
39
|
+
const baseClasses = "fixed z-[9999] flex flex-col gap-3 p-4 pointer-events-none";
|
|
26
40
|
const positionClasses = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
"top-left": "top-0 left-0",
|
|
42
|
+
"top-right": "top-0 right-0",
|
|
43
|
+
"top-center": "top-0 left-1/2 -translate-x-1/2",
|
|
44
|
+
"bottom-left": "bottom-0 left-0",
|
|
45
|
+
"bottom-right": "bottom-0 right-0",
|
|
46
|
+
"bottom-center": "bottom-0 left-1/2 -translate-x-1/2",
|
|
33
47
|
};
|
|
34
|
-
return `${baseClasses} ${positionClasses[props.position] || positionClasses[
|
|
48
|
+
return `${baseClasses} ${positionClasses[props.position] || positionClasses["top-right"]}`;
|
|
35
49
|
});
|
|
36
50
|
|
|
37
51
|
const addToast = (toast: ToastItem): void => {
|
|
38
52
|
const newToast: ToastItem = {
|
|
39
53
|
id: toast.id || useRandomId(),
|
|
40
54
|
message: toast.message,
|
|
41
|
-
severity: toast.severity ||
|
|
55
|
+
severity: toast.severity || "info",
|
|
42
56
|
icon: toast.icon,
|
|
43
57
|
duration: toast.duration ?? 5000,
|
|
44
58
|
closable: toast.closable ?? true,
|
|
45
59
|
};
|
|
46
60
|
|
|
47
|
-
if (props.position.includes(
|
|
61
|
+
if (props.position.includes("top")) {
|
|
48
62
|
toasts.value.unshift(newToast);
|
|
49
63
|
} else {
|
|
50
64
|
toasts.value.push(newToast);
|
|
@@ -68,7 +82,11 @@ const clearAll = (): void => {
|
|
|
68
82
|
};
|
|
69
83
|
|
|
70
84
|
onMounted(() => {
|
|
71
|
-
setToastContainer({ addToast, removeToast, clearAll, toasts });
|
|
85
|
+
setToastContainer({ addToast, removeToast, clearAll, toasts }, props.containerId);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
onUnmounted(() => {
|
|
89
|
+
setToastContainer(null, props.containerId);
|
|
72
90
|
});
|
|
73
91
|
|
|
74
92
|
defineExpose<{
|
package/composables/useToast.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Severity } from
|
|
2
|
-
import type { Component } from
|
|
3
|
-
import { useRandomId } from
|
|
1
|
+
import type { Severity } from "../exports/types";
|
|
2
|
+
import type { Component } from "vue";
|
|
3
|
+
import { useRandomId } from "../exports/utils";
|
|
4
4
|
|
|
5
5
|
export interface ToastItem {
|
|
6
6
|
id: string;
|
|
@@ -17,6 +17,7 @@ export interface ToastOptions {
|
|
|
17
17
|
icon?: Component;
|
|
18
18
|
duration?: number;
|
|
19
19
|
closable?: boolean;
|
|
20
|
+
containerId?: string;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
interface ToastContainerMethods {
|
|
@@ -26,54 +27,70 @@ interface ToastContainerMethods {
|
|
|
26
27
|
toasts: any;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
let
|
|
30
|
+
let toastContainerId: string = "default-toast-container";
|
|
31
|
+
const toastContainerInstances = new Map<string, ToastContainerMethods>();
|
|
30
32
|
|
|
31
|
-
export const setToastContainer = (instance: ToastContainerMethods | null) => {
|
|
32
|
-
|
|
33
|
+
export const setToastContainer = (instance: ToastContainerMethods | null, containerId: string) => {
|
|
34
|
+
toastContainerId = containerId;
|
|
35
|
+
|
|
36
|
+
if (instance) {
|
|
37
|
+
toastContainerInstances.set(containerId, instance);
|
|
38
|
+
} else {
|
|
39
|
+
toastContainerInstances.delete(containerId);
|
|
40
|
+
}
|
|
33
41
|
};
|
|
34
42
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
const getToastContainer = (containerId?: string): ToastContainerMethods | null => {
|
|
44
|
+
const id = containerId || toastContainerId;
|
|
45
|
+
return toastContainerInstances.get(id) || null;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const showToast = (options: ToastOptions & { containerId?: string }) => {
|
|
49
|
+
const containerId = options.containerId || toastContainerId;
|
|
50
|
+
const container = getToastContainer(containerId);
|
|
51
|
+
|
|
52
|
+
if (!container) {
|
|
53
|
+
console.warn(`Toast container with ID "${containerId}" not initialized. Make sure to add <ToastContainer> to your app.`);
|
|
38
54
|
return;
|
|
39
55
|
}
|
|
40
56
|
|
|
41
57
|
const toastItem: ToastItem = {
|
|
42
58
|
id: useRandomId(),
|
|
43
59
|
message: options.message,
|
|
44
|
-
severity: options.severity ||
|
|
60
|
+
severity: options.severity || "info",
|
|
45
61
|
icon: options.icon,
|
|
46
62
|
duration: options.duration ?? 5000,
|
|
47
63
|
closable: options.closable ?? true,
|
|
48
64
|
};
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
container.addToast(toastItem);
|
|
51
67
|
};
|
|
52
68
|
|
|
53
|
-
export const useToast = () => {
|
|
54
|
-
const success = (message: string, options?: Omit<ToastOptions,
|
|
55
|
-
return showToast({ ...options, message, severity:
|
|
69
|
+
export const useToast = (containerId?: string) => {
|
|
70
|
+
const success = (message: string, options?: Omit<ToastOptions, "message" | "severity"> & { containerId?: string }) => {
|
|
71
|
+
return showToast({ ...options, message, severity: "success", containerId: options?.containerId || containerId });
|
|
56
72
|
};
|
|
57
73
|
|
|
58
|
-
const error = (message: string, options?: Omit<ToastOptions,
|
|
59
|
-
return showToast({ ...options, message, severity:
|
|
74
|
+
const error = (message: string, options?: Omit<ToastOptions, "message" | "severity"> & { containerId?: string }) => {
|
|
75
|
+
return showToast({ ...options, message, severity: "error", containerId: options?.containerId || containerId });
|
|
60
76
|
};
|
|
61
77
|
|
|
62
|
-
const warning = (message: string, options?: Omit<ToastOptions,
|
|
63
|
-
return showToast({ ...options, message, severity:
|
|
78
|
+
const warning = (message: string, options?: Omit<ToastOptions, "message" | "severity"> & { containerId?: string }) => {
|
|
79
|
+
return showToast({ ...options, message, severity: "warning", containerId: options?.containerId || containerId });
|
|
64
80
|
};
|
|
65
81
|
|
|
66
|
-
const info = (message: string, options?: Omit<ToastOptions,
|
|
67
|
-
return showToast({ ...options, message, severity:
|
|
82
|
+
const info = (message: string, options?: Omit<ToastOptions, "message" | "severity"> & { containerId?: string }) => {
|
|
83
|
+
return showToast({ ...options, message, severity: "info", containerId: options?.containerId || containerId });
|
|
68
84
|
};
|
|
69
85
|
|
|
70
|
-
const show = (message: string, options?: ToastOptions) => {
|
|
71
|
-
return showToast({ ...options, message });
|
|
86
|
+
const show = (message: string, options?: Omit<ToastOptions, "message"> & { containerId?: string }) => {
|
|
87
|
+
return showToast({ ...options, message, containerId: options?.containerId || containerId });
|
|
72
88
|
};
|
|
73
89
|
|
|
74
90
|
const clear = () => {
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
const container = getToastContainer(containerId);
|
|
92
|
+
if (container) {
|
|
93
|
+
container.clearAll();
|
|
77
94
|
}
|
|
78
95
|
};
|
|
79
96
|
|
package/package.json
CHANGED
package/styles/index.css
CHANGED
package/styles/utilities.css
CHANGED
|
@@ -16,6 +16,5 @@
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
@utility text-highlight {
|
|
19
|
-
|
|
20
|
-
/* @apply inline-table rounded bg-neutral-100 px-1.5 outline outline-neutral-200/75 dark:bg-neutral-800 dark:outline-neutral-700/75; */
|
|
19
|
+
@apply inline-table rounded bg-neutral-100 px-1.5 outline outline-neutral-200/75 dark:bg-neutral-800 dark:outline-neutral-700/75;
|
|
21
20
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type Component } from
|
|
2
|
-
import { type Variant, type Severity, type Position, type Size, type FontWeight } from
|
|
1
|
+
import { type Component } from "vue";
|
|
2
|
+
import { type Variant, type Severity, type Position, type Size, type FontWeight } from "../exports/types";
|
|
3
3
|
declare var __VLS_1: {};
|
|
4
4
|
type __VLS_Slots = {} & {
|
|
5
5
|
default?: (props: typeof __VLS_1) => any;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type Component } from
|
|
2
|
-
type CheckboxSize =
|
|
3
|
-
type CheckboxVariant =
|
|
1
|
+
import { type Component } from "vue";
|
|
2
|
+
type CheckboxSize = "sm" | "md" | "lg";
|
|
3
|
+
type CheckboxVariant = "primary" | "secondary" | "success" | "info" | "error" | "warning";
|
|
4
4
|
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
5
5
|
label: {
|
|
6
6
|
type: StringConstructor;
|
|
@@ -26,6 +26,10 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
26
26
|
type: () => Component;
|
|
27
27
|
default: () => import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
28
28
|
};
|
|
29
|
+
iconClass: {
|
|
30
|
+
type: StringConstructor;
|
|
31
|
+
default: string;
|
|
32
|
+
};
|
|
29
33
|
disabled: {
|
|
30
34
|
type: BooleanConstructor;
|
|
31
35
|
default: boolean;
|
|
@@ -61,6 +65,10 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
61
65
|
type: () => Component;
|
|
62
66
|
default: () => import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
63
67
|
};
|
|
68
|
+
iconClass: {
|
|
69
|
+
type: StringConstructor;
|
|
70
|
+
default: string;
|
|
71
|
+
};
|
|
64
72
|
disabled: {
|
|
65
73
|
type: BooleanConstructor;
|
|
66
74
|
default: boolean;
|
|
@@ -77,6 +85,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
77
85
|
size: CheckboxSize;
|
|
78
86
|
disabled: boolean;
|
|
79
87
|
variant: CheckboxVariant;
|
|
88
|
+
iconClass: string;
|
|
80
89
|
labelClass: string;
|
|
81
90
|
checkboxClass: string;
|
|
82
91
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type Component } from
|
|
2
|
-
import { type Size } from
|
|
1
|
+
import { type Component } from "vue";
|
|
2
|
+
import { type Size } from "../exports/types";
|
|
3
3
|
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
4
4
|
leadingIcon: {
|
|
5
5
|
type: () => Component;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type Ref } from
|
|
2
|
-
import type { ToastItem } from
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
import type { ToastItem } from "../../exports/toast";
|
|
3
3
|
declare const toasts: Ref<ToastItem[]>;
|
|
4
4
|
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
5
5
|
position: {
|
|
@@ -10,6 +10,10 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
10
10
|
type: NumberConstructor;
|
|
11
11
|
default: number;
|
|
12
12
|
};
|
|
13
|
+
containerId: {
|
|
14
|
+
type: StringConstructor;
|
|
15
|
+
default: string;
|
|
16
|
+
};
|
|
13
17
|
}>, {
|
|
14
18
|
addToast: (toast: ToastItem) => void;
|
|
15
19
|
removeToast: (id: string) => void;
|
|
@@ -24,9 +28,14 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
24
28
|
type: NumberConstructor;
|
|
25
29
|
default: number;
|
|
26
30
|
};
|
|
31
|
+
containerId: {
|
|
32
|
+
type: StringConstructor;
|
|
33
|
+
default: string;
|
|
34
|
+
};
|
|
27
35
|
}>> & Readonly<{}>, {
|
|
28
36
|
position: "top-left" | "top-right" | "top-center" | "bottom-left" | "bottom-right" | "bottom-center";
|
|
29
37
|
maxToasts: number;
|
|
38
|
+
containerId: string;
|
|
30
39
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
31
40
|
declare const _default: typeof __VLS_export;
|
|
32
41
|
export default _default;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Severity } from
|
|
2
|
-
import type { Component } from
|
|
1
|
+
import type { Severity } from "../exports/types";
|
|
2
|
+
import type { Component } from "vue";
|
|
3
3
|
export interface ToastItem {
|
|
4
4
|
id: string;
|
|
5
5
|
message: string;
|
|
@@ -14,6 +14,7 @@ export interface ToastOptions {
|
|
|
14
14
|
icon?: Component;
|
|
15
15
|
duration?: number;
|
|
16
16
|
closable?: boolean;
|
|
17
|
+
containerId?: string;
|
|
17
18
|
}
|
|
18
19
|
interface ToastContainerMethods {
|
|
19
20
|
addToast: (toast: ToastItem) => void;
|
|
@@ -21,13 +22,23 @@ interface ToastContainerMethods {
|
|
|
21
22
|
clearAll: () => void;
|
|
22
23
|
toasts: any;
|
|
23
24
|
}
|
|
24
|
-
export declare const setToastContainer: (instance: ToastContainerMethods | null) => void;
|
|
25
|
-
export declare const useToast: () => {
|
|
26
|
-
success: (message: string, options?: Omit<ToastOptions, "message" | "severity">
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
export declare const setToastContainer: (instance: ToastContainerMethods | null, containerId: string) => void;
|
|
26
|
+
export declare const useToast: (containerId?: string) => {
|
|
27
|
+
success: (message: string, options?: Omit<ToastOptions, "message" | "severity"> & {
|
|
28
|
+
containerId?: string;
|
|
29
|
+
}) => void;
|
|
30
|
+
error: (message: string, options?: Omit<ToastOptions, "message" | "severity"> & {
|
|
31
|
+
containerId?: string;
|
|
32
|
+
}) => void;
|
|
33
|
+
warning: (message: string, options?: Omit<ToastOptions, "message" | "severity"> & {
|
|
34
|
+
containerId?: string;
|
|
35
|
+
}) => void;
|
|
36
|
+
info: (message: string, options?: Omit<ToastOptions, "message" | "severity"> & {
|
|
37
|
+
containerId?: string;
|
|
38
|
+
}) => void;
|
|
39
|
+
show: (message: string, options?: Omit<ToastOptions, "message"> & {
|
|
40
|
+
containerId?: string;
|
|
41
|
+
}) => void;
|
|
31
42
|
clear: () => void;
|
|
32
43
|
};
|
|
33
44
|
export {};
|