@witchcraft/ui 0.3.11 → 0.3.13
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/module.json +1 -1
- package/dist/runtime/assets/utils.css +1 -1
- package/dist/runtime/components/LibColorInput/LibColorInput.d.vue.ts +2 -2
- package/dist/runtime/components/LibColorInput/LibColorInput.vue.d.ts +2 -2
- package/dist/runtime/components/LibColorPicker/LibColorPicker.d.vue.ts +3 -3
- package/dist/runtime/components/LibColorPicker/LibColorPicker.vue.d.ts +3 -3
- package/dist/runtime/components/LibFileInput/LibFileInput.d.vue.ts +5 -3
- package/dist/runtime/components/LibFileInput/LibFileInput.vue +141 -84
- package/dist/runtime/components/LibFileInput/LibFileInput.vue.d.ts +5 -3
- package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.d.vue.ts +3 -3
- package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue.d.ts +3 -3
- package/dist/runtime/components/LibNotifications/LibNotification.vue +16 -1
- package/dist/runtime/components/LibNotifications/LibNotificationTestMessageComponent.d.vue.ts +6 -0
- package/dist/runtime/components/LibNotifications/LibNotificationTestMessageComponent.vue +29 -0
- package/dist/runtime/components/LibNotifications/LibNotificationTestMessageComponent.vue.d.ts +6 -0
- package/dist/runtime/components/LibPopup/LibPopup.d.vue.ts +1 -1
- package/dist/runtime/components/LibPopup/LibPopup.vue.d.ts +1 -1
- package/dist/runtime/helpers/NotificationHandler.d.ts +5 -2
- package/dist/runtime/helpers/NotificationHandler.js +2 -1
- package/dist/runtime/types/index.d.ts +4 -0
- package/dist/runtime/utils/notifyIfError.d.ts +3 -1
- package/dist/runtime/utils/notifyIfError.js +4 -2
- package/package.json +2 -2
- package/src/runtime/assets/utils.css +4 -4
- package/src/runtime/components/LibFileInput/LibFileInput.stories.ts +13 -3
- package/src/runtime/components/LibFileInput/LibFileInput.vue +154 -92
- package/src/runtime/components/LibNotifications/LibNotification.stories.ts +22 -1
- package/src/runtime/components/LibNotifications/LibNotification.vue +16 -1
- package/src/runtime/components/LibNotifications/LibNotificationTestMessageComponent.vue +27 -0
- package/src/runtime/helpers/NotificationHandler.ts +6 -2
- package/src/runtime/types/index.ts +5 -0
- package/src/runtime/utils/notifyIfError.ts +6 -2
package/dist/module.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@custom-variant dark (&:where(.dark, .dark *));@utility focus-outline-within{@
|
|
1
|
+
@custom-variant dark (&:where(.dark, .dark *));@utility focus-outline-within{@apply outlined-within:outline-2 outlined-within:outline-accent-500 outlined-within:outline-offset-2}@utility focus-outline{@apply outlined:outline-2 outlined:outline-accent-500 outlined:outline-offset-2}@utility focus-outline-no-offset{@apply outlined:outline-2 outlined:outline-accent-500}@utility focus-outline-hidden{@apply outlined:outline-none}@utility bg-squares-gradient{--_square:var(--squareSize,5px);--_double_square:calc(var(--_square)*2);--_light_square:var(--lightSquare,var(--color-white));--_dark_square:var(--darkSquare,var(--color-black));background-color:var(--_light_square);background:repeating-conic-gradient(var(--_dark_square) 0 25%,var(--_light_square) 0 50%) 50% /var(--_double_square) var(--_double_square)}@utility square-light-*{--lightSquare:--value(--color- *)}@utility square-dark-*{--darkSquare:--value(--color- *)}@utility square-size-*{--squareSize:calc(--value(integer) * 1px)}@utility bg-bars-gradient{--_bg_color:var(--bars-bg-color,var(--color-accent-700));--_fg_color:var(--bars-fg-color,var(--color-accent-800));--_angle:var(--bars-angle,45deg);--_fg_width:var(--bars-fg-width,50%);--_bg_width:calc(100% - var(--_fg_width));background-color:var(--_bg_color);--_pos_1:calc(var(--_bg_width)/2);--_pos_2:calc(var(--_bg_width)/2 + var(--_fg_width)/2);--_pos_3:calc(var(--_bg_width) + var(--_fg_width)/2);background-image:repeating-linear-gradient(var(--_angle),var(--_bg_color),var(--_bg_color) var(--_pos_1),var(--_fg_color) var(--_pos_1),var(--_fg_color) var(--_pos_2),var(--_bg_color) var(--_pos_2),var(--_bg_color) var(--_pos_3),var(--_fg_color) var(--_pos_3),var(--_fg_color))}@utility bars-angle-*{--bars-angle:var(--value(integer) * 1deg)}@utility bars-fg-*{--bars-fg-color:--value(--color-*)}@utility bars-bg-*{--bars-bg-color:--value(--color-*)}@utility bars-w-*{--bars-fg-width:calc(--value(integer) * 1%, 50%)}@utility scrollbar-hidden{-ms-overflow-style:none;scrollbar-width:none;&::-webkit-scrollbar{display:none}}@utility styled-scrollbar{--_scrollbar_width:var(--scrollbar-width,calc(var(--spacing)*3));--_scrollbar_border_width:var(--scrollbar-border-width,calc(var(--spacing)/2));--_scrollbar_color:var(--scrollbar-color,--alpha(var(--color-accent-500)/40%));--_scrollbar_hover_color:var(--scrollbar-hover-color,--alpha(var(--color-accent-500)/80%));--_scrollbar_bg_color:var(--scrollbar-bg-color,var(--color-bg));.dark &{--_scrollbar_bg_color:var(--scrollbar-bg-color,var(--color-fg))}&::-webkit-scrollbar{height:var(--_scrollbar_width);width:var(--_scrollbar_width)}&::-webkit-scrollbar-corner,&::-webkit-scrollbar-track{background-color:transparent}&::-webkit-scrollbar-thumb,&::-webkit-scrollbar-track{border-radius:var(--_scrollbar_width)}&::-webkit-scrollbar-thumb{background-color:var(--_scrollbar_color);border:var(--_scrollbar_border_width) solid var(--_scrollbar_bg_color)}&::-webkit-scrollbar-thumb:hover{cursor:pointer}&::-webkit-scrollbar-thumb:active,&::-webkit-scrollbar-thumb:hover{background-color:var(--_scrollbar_hover_color);border-radius:var(--_scrollbar_width)}}@utility styled-scrollbar-w-*{--scrollbar-width:--value(integer)}@utility styled-scrollbar-border-w-*{--scrollbar-border-width:--value(integer)}@utility styled-scrollbar-*{--scrollbar-color:--value(--color-*)}@utility styled-scrollbar-bg-*{--scrollbar-bg-color:--value(--color-*)}@utility styled-resizer{--_resizer_width:var(--resizer-width,8px);--_resizer_color:var(--resizer-color,var(--color-neutral-300));.dark &{--_resizer_color:var(--resizer-color,var(--color-neutral-700))}&::-webkit-resizer{border-bottom-color:var(--_resizer_color);border-left-color:transparent;border-right-color:var(--_resizer_color);border-style:solid;border-top-color:transparent;border-width:var(--_resizer_width)}}@utility styled-resizer-w-*{--resizer-width:--value(integer)}@utility styled-resizer-color-*{--resizer-color:--value(--color-*)}@utility content-vertical-holder{--tw-content:"\200b";content:var(--tw-content)}@utility no-touch-action{touch-action:none}@utility bg-transparency-squares{@apply bg-squares-gradient square-light-white square-dark-neutral-300 square-size-6}@utility link-like{@apply cursor-pointer hover:text-accent-500}
|
|
@@ -34,16 +34,16 @@ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props & {
|
|
|
34
34
|
}> & Readonly<{
|
|
35
35
|
"onUpdate:modelValue"?: ((value: RgbaColor) => any) | undefined;
|
|
36
36
|
onCancel?: (() => any) | undefined;
|
|
37
|
-
onSave?: (() => any) | undefined;
|
|
38
37
|
"onUpdate:tempValue"?: ((value: RgbaColor | undefined) => any) | undefined;
|
|
38
|
+
onSave?: (() => any) | undefined;
|
|
39
39
|
}>, {
|
|
40
40
|
border: boolean;
|
|
41
41
|
allowAlpha: boolean;
|
|
42
|
+
copyTransform: (val: HsvaColor, stringVal: string) => any;
|
|
42
43
|
stringPrecision: number;
|
|
43
44
|
customRepresentation: {
|
|
44
45
|
fromHsvaToString: (hsva: HsvaColor, includeAlpha: boolean) => string;
|
|
45
46
|
};
|
|
46
|
-
copyTransform: (val: HsvaColor, stringVal: string) => any;
|
|
47
47
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
48
48
|
default?: (props: {
|
|
49
49
|
stringColor: any;
|
|
@@ -34,16 +34,16 @@ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props & {
|
|
|
34
34
|
}> & Readonly<{
|
|
35
35
|
"onUpdate:modelValue"?: ((value: RgbaColor) => any) | undefined;
|
|
36
36
|
onCancel?: (() => any) | undefined;
|
|
37
|
-
onSave?: (() => any) | undefined;
|
|
38
37
|
"onUpdate:tempValue"?: ((value: RgbaColor | undefined) => any) | undefined;
|
|
38
|
+
onSave?: (() => any) | undefined;
|
|
39
39
|
}>, {
|
|
40
40
|
border: boolean;
|
|
41
41
|
allowAlpha: boolean;
|
|
42
|
+
copyTransform: (val: HsvaColor, stringVal: string) => any;
|
|
42
43
|
stringPrecision: number;
|
|
43
44
|
customRepresentation: {
|
|
44
45
|
fromHsvaToString: (hsva: HsvaColor, includeAlpha: boolean) => string;
|
|
45
46
|
};
|
|
46
|
-
copyTransform: (val: HsvaColor, stringVal: string) => any;
|
|
47
47
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
48
48
|
default?: (props: {
|
|
49
49
|
stringColor: any;
|
|
@@ -39,18 +39,18 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
|
|
|
39
39
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
40
40
|
"onUpdate:modelValue"?: ((value: RgbaColor) => any) | undefined;
|
|
41
41
|
onCancel?: (() => any) | undefined;
|
|
42
|
-
onSave?: ((val: RgbaColor) => any) | undefined;
|
|
43
42
|
"onUpdate:tempValue"?: ((value: RgbaColor | undefined) => any) | undefined;
|
|
43
|
+
onSave?: ((val: RgbaColor) => any) | undefined;
|
|
44
44
|
}>, {
|
|
45
45
|
border: boolean;
|
|
46
|
-
valid: boolean;
|
|
47
46
|
allowAlpha: boolean;
|
|
47
|
+
copyTransform: (val: HsvaColor, stringVal: string) => any;
|
|
48
48
|
stringPrecision: number;
|
|
49
49
|
customRepresentation: {
|
|
50
50
|
fromHsvaToString: (hsva: HsvaColor, includeAlpha: boolean) => string;
|
|
51
51
|
fromStringToHsva?: (string: string) => HsvaColor | undefined;
|
|
52
52
|
};
|
|
53
|
-
|
|
53
|
+
valid: boolean;
|
|
54
54
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
55
55
|
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
56
56
|
export default _default;
|
|
@@ -39,18 +39,18 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
|
|
|
39
39
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
40
40
|
"onUpdate:modelValue"?: ((value: RgbaColor) => any) | undefined;
|
|
41
41
|
onCancel?: (() => any) | undefined;
|
|
42
|
-
onSave?: ((val: RgbaColor) => any) | undefined;
|
|
43
42
|
"onUpdate:tempValue"?: ((value: RgbaColor | undefined) => any) | undefined;
|
|
43
|
+
onSave?: ((val: RgbaColor) => any) | undefined;
|
|
44
44
|
}>, {
|
|
45
45
|
border: boolean;
|
|
46
|
-
valid: boolean;
|
|
47
46
|
allowAlpha: boolean;
|
|
47
|
+
copyTransform: (val: HsvaColor, stringVal: string) => any;
|
|
48
48
|
stringPrecision: number;
|
|
49
49
|
customRepresentation: {
|
|
50
50
|
fromHsvaToString: (hsva: HsvaColor, includeAlpha: boolean) => string;
|
|
51
51
|
fromStringToHsva?: (string: string) => HsvaColor | undefined;
|
|
52
52
|
};
|
|
53
|
-
|
|
53
|
+
valid: boolean;
|
|
54
54
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
55
55
|
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
56
56
|
export default _default;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { type HTMLAttributes, type InputHTMLAttributes } from "vue";
|
|
2
2
|
import type { FileInputError } from "../../types/index.js";
|
|
3
3
|
import { type LinkableByIdProps, type TailwindClassProp, type WrapperProps } from "../shared/props.js";
|
|
4
|
-
declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props, {
|
|
5
|
-
|
|
4
|
+
declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props, {
|
|
5
|
+
clearFiles: () => void;
|
|
6
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
7
|
+
input: (val: File[], clearFiles: () => void) => any;
|
|
6
8
|
errors: (val: FileInputError[]) => any;
|
|
7
9
|
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
8
|
-
onInput?: ((val: File[]) => any) | undefined;
|
|
10
|
+
onInput?: ((val: File[], clearFiles: () => void) => any) | undefined;
|
|
9
11
|
onErrors?: ((val: FileInputError[]) => any) | undefined;
|
|
10
12
|
}>, {
|
|
11
13
|
multiple: boolean;
|
|
@@ -2,30 +2,52 @@
|
|
|
2
2
|
<!-- todo aria errors -->
|
|
3
3
|
<div
|
|
4
4
|
:class="twMerge(
|
|
5
|
-
`
|
|
5
|
+
`
|
|
6
|
+
file-input
|
|
6
7
|
justify-center
|
|
7
8
|
border-2
|
|
8
9
|
border-dashed
|
|
9
10
|
border-accent-500/80
|
|
10
11
|
focus-outline-within
|
|
11
12
|
transition-[border-color,box-shadow]
|
|
12
|
-
ease-out
|
|
13
|
+
ease-out
|
|
14
|
+
hover:bg-accent-500/10
|
|
15
|
+
outlined-focus-within
|
|
16
|
+
`,
|
|
13
17
|
compact && `rounded-sm`,
|
|
14
|
-
!compact && `
|
|
18
|
+
!compact && `
|
|
19
|
+
flex
|
|
20
|
+
w-full
|
|
21
|
+
flex-col
|
|
22
|
+
items-stretch
|
|
23
|
+
gap-2
|
|
24
|
+
rounded-xl
|
|
25
|
+
p-2
|
|
26
|
+
`,
|
|
15
27
|
errors.length > 0 && errorFlashing && `border-danger-400`,
|
|
28
|
+
isHovered && `bg-accent-500/10`,
|
|
16
29
|
$.wrapperAttrs.class
|
|
17
30
|
)"
|
|
18
31
|
v-bind="{ ...$.wrapperAttrs, class: void 0 }"
|
|
32
|
+
@drop="onDrop"
|
|
33
|
+
@dragover.prevent="isHovered = true"
|
|
34
|
+
@dragleave="isHovered = false"
|
|
19
35
|
>
|
|
20
36
|
<div
|
|
21
37
|
:class="twMerge(
|
|
22
38
|
`
|
|
23
|
-
|
|
24
|
-
|
|
39
|
+
file-input--wrapper
|
|
40
|
+
relative
|
|
41
|
+
justify-center
|
|
42
|
+
@container
|
|
43
|
+
`,
|
|
25
44
|
compact && `flex gap-2`,
|
|
26
|
-
!compact && `
|
|
27
|
-
|
|
28
|
-
|
|
45
|
+
!compact && `
|
|
46
|
+
file-input
|
|
47
|
+
flex
|
|
48
|
+
flex-col
|
|
49
|
+
items-center
|
|
50
|
+
`
|
|
29
51
|
)"
|
|
30
52
|
>
|
|
31
53
|
<label
|
|
@@ -36,7 +58,9 @@
|
|
|
36
58
|
flex
|
|
37
59
|
gap-1
|
|
38
60
|
items-center
|
|
61
|
+
justify-center
|
|
39
62
|
whitespace-nowrap
|
|
63
|
+
max-w-full
|
|
40
64
|
`)"
|
|
41
65
|
>
|
|
42
66
|
<slot
|
|
@@ -46,23 +70,37 @@
|
|
|
46
70
|
<icon><i-fa6-solid-arrow-up-from-bracket/></icon>
|
|
47
71
|
</slot>
|
|
48
72
|
<slot name="label">
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
73
|
+
<div class="text-ellipsis overflow-hidden shrink-1 hidden @min-[15ch]:block">
|
|
74
|
+
{{
|
|
75
|
+
compact ? multiple ? t("file-input.compact-choose-file-plural") : t("file-input.compact-choose-file") : multiple ? t("file-input.non-compact-choose-file-plural") : t("file-input.non-compact-choose-file")
|
|
76
|
+
}}
|
|
77
|
+
</div>
|
|
52
78
|
</slot>
|
|
53
|
-
<
|
|
79
|
+
<div
|
|
54
80
|
v-if="compact && multiple"
|
|
55
81
|
class="file-input--label-count"
|
|
56
82
|
>
|
|
57
83
|
{{ ` (${files.length})` }}
|
|
58
|
-
</
|
|
84
|
+
</div>
|
|
85
|
+
<div
|
|
86
|
+
v-if="compact && !multiple && files.length > 0"
|
|
87
|
+
class="file-input--label-name text-ellipsis overflow-hidden shrink-9999 hidden @3xs:block"
|
|
88
|
+
>
|
|
89
|
+
{{ ` (${files[0]?.file.name})` }}
|
|
90
|
+
</div>
|
|
91
|
+
<div
|
|
92
|
+
v-if="compact && !multiple && files.length > 0"
|
|
93
|
+
class="file-input--label-name text-ellipsis overflow-hidden shrink-9999 @3xs:hidden"
|
|
94
|
+
>
|
|
95
|
+
{{ ` (...)` }}
|
|
96
|
+
</div>
|
|
59
97
|
</label>
|
|
60
98
|
<label
|
|
61
99
|
v-if="!compact && formats?.length > 0"
|
|
62
|
-
class="file-input--formats-label flex
|
|
100
|
+
class="file-input--formats-label flex-col items-center text-sm max-w-full hidden @min-[15ch]:flex"
|
|
63
101
|
>
|
|
64
|
-
<slot name="formats">{{ t("file-input.accepted-formats") }}
|
|
65
|
-
<div class="file-input--formats-list">
|
|
102
|
+
<slot name="formats"><div class="text-ellipsis overflow-hidden max-w-full">{{ t("file-input.accepted-formats") }}:</div> </slot>
|
|
103
|
+
<div class="file-input--formats-list overflow-hidden text-ellipsis max-w-full">
|
|
66
104
|
{{ extensions.join(", ") }}
|
|
67
105
|
</div>
|
|
68
106
|
</label>
|
|
@@ -70,14 +108,14 @@
|
|
|
70
108
|
:id="id ?? fallbackId"
|
|
71
109
|
:class="twMerge(
|
|
72
110
|
`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
111
|
+
file-input--input
|
|
112
|
+
absolute
|
|
113
|
+
inset-[calc(var(--spacing)*-2)]
|
|
114
|
+
cursor-pointer
|
|
115
|
+
z-0
|
|
116
|
+
text-[0]
|
|
117
|
+
opacity-0
|
|
118
|
+
`,
|
|
81
119
|
$.inputAttrs?.class
|
|
82
120
|
)"
|
|
83
121
|
type="file"
|
|
@@ -94,7 +132,7 @@
|
|
|
94
132
|
v-if="!compact && files.length > 0"
|
|
95
133
|
:class="twMerge(
|
|
96
134
|
`file-input--previews
|
|
97
|
-
flex items-stretch justify-center gap-
|
|
135
|
+
flex items-stretch justify-center gap-4 flex-wrap
|
|
98
136
|
`,
|
|
99
137
|
multiple && `
|
|
100
138
|
w-full
|
|
@@ -102,32 +140,47 @@
|
|
|
102
140
|
$.previewsAttrs?.class
|
|
103
141
|
)"
|
|
104
142
|
>
|
|
105
|
-
<div class="file-input--preview-spacer flex-1"/>
|
|
106
143
|
<div
|
|
107
|
-
class="
|
|
144
|
+
class="
|
|
145
|
+
file-input--preview-wrapper
|
|
108
146
|
z-1
|
|
109
147
|
relative
|
|
110
148
|
flex
|
|
111
149
|
min-w-0
|
|
112
150
|
max-w-[150px]
|
|
113
151
|
flex-initial
|
|
114
|
-
flex-
|
|
152
|
+
flex-col
|
|
115
153
|
items-center
|
|
116
|
-
gap-
|
|
117
|
-
|
|
118
|
-
|
|
154
|
+
gap-1
|
|
155
|
+
p-1
|
|
156
|
+
rounded-sm
|
|
157
|
+
border
|
|
158
|
+
border-neutral-300
|
|
159
|
+
dark:border-neutral-800
|
|
160
|
+
shadow-md
|
|
161
|
+
shadow-neutral-800/30
|
|
162
|
+
bg-neutral-100
|
|
163
|
+
dark:bg-neutral-900
|
|
164
|
+
[&:hover_.file-input--remove-button]:opacity-100
|
|
119
165
|
"
|
|
120
166
|
v-for="entry of files"
|
|
121
167
|
:key="entry.file.name"
|
|
122
168
|
>
|
|
123
|
-
<div class="
|
|
169
|
+
<div class="flex flex-initial basis-full justify-start items-center max-w-full gap-2 px-1">
|
|
124
170
|
<lib-button
|
|
125
171
|
:border="false"
|
|
172
|
+
class="file-input--remove-button rounded-full p-0"
|
|
126
173
|
:aria-label="`Remove file ${entry.file.name}`"
|
|
127
174
|
@click="removeFile(entry)"
|
|
128
175
|
>
|
|
129
176
|
<icon><i-fa6-solid-xmark/></icon>
|
|
130
177
|
</lib-button>
|
|
178
|
+
<div
|
|
179
|
+
class="file-input--preview-filename min-w-0 flex-1 basis-0 truncate break-all rounded-sm text-sm"
|
|
180
|
+
:title="entry.file.name"
|
|
181
|
+
>
|
|
182
|
+
{{ entry.file.name }}
|
|
183
|
+
</div>
|
|
131
184
|
</div>
|
|
132
185
|
|
|
133
186
|
<div class="file-input--preview flex flex-initial basis-full justify-center">
|
|
@@ -154,25 +207,7 @@
|
|
|
154
207
|
<icon><i-fa6-regular-file class="text-4xl opacity-50"/></icon>
|
|
155
208
|
</div>
|
|
156
209
|
</div>
|
|
157
|
-
<div
|
|
158
|
-
class="
|
|
159
|
-
file-input--preview-filename
|
|
160
|
-
min-w-0
|
|
161
|
-
flex-1
|
|
162
|
-
basis-0
|
|
163
|
-
truncate
|
|
164
|
-
break-all
|
|
165
|
-
rounded-sm
|
|
166
|
-
p-1
|
|
167
|
-
text-sm
|
|
168
|
-
"
|
|
169
|
-
:title="entry.file.name"
|
|
170
|
-
>
|
|
171
|
-
{{ entry.file.name }}
|
|
172
|
-
</div>
|
|
173
210
|
</div>
|
|
174
|
-
|
|
175
|
-
<div class="flex-1"/>
|
|
176
211
|
</div>
|
|
177
212
|
</div>
|
|
178
213
|
</template>
|
|
@@ -193,8 +228,13 @@ const el = ref(null);
|
|
|
193
228
|
const files = shallowReactive([]);
|
|
194
229
|
const errors = shallowReactive([]);
|
|
195
230
|
const errorFlashing = ref(false);
|
|
231
|
+
const isHovered = ref(false);
|
|
232
|
+
function clearFiles() {
|
|
233
|
+
el.value.value = "";
|
|
234
|
+
files.splice(0, files.length);
|
|
235
|
+
}
|
|
196
236
|
watch(files, () => {
|
|
197
|
-
emits("input", files.map((entry) => entry.file));
|
|
237
|
+
emits("input", files.map((entry) => entry.file), clearFiles);
|
|
198
238
|
});
|
|
199
239
|
watch(errors, () => {
|
|
200
240
|
if (errors.length > 0) {
|
|
@@ -202,7 +242,8 @@ watch(errors, () => {
|
|
|
202
242
|
setTimeout(() => {
|
|
203
243
|
errorFlashing.value = false;
|
|
204
244
|
}, 500);
|
|
205
|
-
emits("errors", errors);
|
|
245
|
+
emits("errors", [...errors]);
|
|
246
|
+
errors.splice(0, errors.length);
|
|
206
247
|
}
|
|
207
248
|
});
|
|
208
249
|
defineOptions({
|
|
@@ -229,44 +270,60 @@ const removeFile = (entry) => {
|
|
|
229
270
|
files.splice(index, 1);
|
|
230
271
|
};
|
|
231
272
|
const extensionsList = computed(() => extensions.value.join(", "));
|
|
232
|
-
|
|
273
|
+
function onDrop(e) {
|
|
274
|
+
if ("dataTransfer" in e && e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
|
275
|
+
el.value.files = e.dataTransfer.files;
|
|
276
|
+
e.preventDefault();
|
|
277
|
+
isHovered.value = false;
|
|
278
|
+
return updateFiles(el.value.files);
|
|
279
|
+
}
|
|
280
|
+
return void 0;
|
|
281
|
+
}
|
|
282
|
+
async function inputFile(e) {
|
|
233
283
|
e.preventDefault();
|
|
234
284
|
if (el.value.files) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
} else {
|
|
257
|
-
files.splice(0, files.length, { file, isImg });
|
|
258
|
-
}
|
|
259
|
-
}
|
|
285
|
+
return updateFiles(el.value.files);
|
|
286
|
+
}
|
|
287
|
+
return void 0;
|
|
288
|
+
}
|
|
289
|
+
function updateFiles(filesList) {
|
|
290
|
+
const errs = [];
|
|
291
|
+
for (const file of filesList) {
|
|
292
|
+
const isImg = file.type.startsWith("image");
|
|
293
|
+
const byPassValidation = props.formats.length === 0;
|
|
294
|
+
const isValidMimeType = mimeTypes.value.find((_) => _.endsWith("/*") ? file.type.startsWith(_.slice(0, -2)) : _ === file.type) !== void 0;
|
|
295
|
+
const isValidExtension = extensions.value.find((_) => file.name.endsWith(_)) !== void 0;
|
|
296
|
+
if (!byPassValidation && (!isValidMimeType || !isValidExtension)) {
|
|
297
|
+
const extension = file.name.match(/.*(\..*)/)?.[1] ?? "Unknown";
|
|
298
|
+
const type = file.type === "" ? "" : ` (${file.type})`;
|
|
299
|
+
const message = `File type ${extension}${type} is not allowed. Allowed file types are: ${extensionsList.value}.`;
|
|
300
|
+
const err = new Error(message);
|
|
301
|
+
err.file = file;
|
|
302
|
+
err.isValidExtension = isValidExtension;
|
|
303
|
+
err.isValidMimeType = isValidMimeType;
|
|
304
|
+
errs.push(err);
|
|
305
|
+
continue;
|
|
260
306
|
}
|
|
261
|
-
if (errs.length > 0)
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
307
|
+
if (errs.length > 0) continue;
|
|
308
|
+
if (!files.find((_) => _.file === file)) {
|
|
309
|
+
if (props.multiple || files.length < 1) {
|
|
310
|
+
files.push({ file, isImg });
|
|
311
|
+
} else {
|
|
312
|
+
files.splice(0, files.length, { file, isImg });
|
|
313
|
+
}
|
|
266
314
|
}
|
|
267
315
|
}
|
|
316
|
+
if (errs.length > 0) {
|
|
317
|
+
errors.splice(0, errors.length, ...errs);
|
|
318
|
+
return false;
|
|
319
|
+
} else if (errors.length > 0) {
|
|
320
|
+
errors.splice(0, errors.length);
|
|
321
|
+
}
|
|
268
322
|
return void 0;
|
|
269
|
-
}
|
|
323
|
+
}
|
|
324
|
+
defineExpose({
|
|
325
|
+
clearFiles
|
|
326
|
+
});
|
|
270
327
|
</script>
|
|
271
328
|
|
|
272
329
|
<script>
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { type HTMLAttributes, type InputHTMLAttributes } from "vue";
|
|
2
2
|
import type { FileInputError } from "../../types/index.js";
|
|
3
3
|
import { type LinkableByIdProps, type TailwindClassProp, type WrapperProps } from "../shared/props.js";
|
|
4
|
-
declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props, {
|
|
5
|
-
|
|
4
|
+
declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props, {
|
|
5
|
+
clearFiles: () => void;
|
|
6
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
7
|
+
input: (val: File[], clearFiles: () => void) => any;
|
|
6
8
|
errors: (val: FileInputError[]) => any;
|
|
7
9
|
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
8
|
-
onInput?: ((val: File[]) => any) | undefined;
|
|
10
|
+
onInput?: ((val: File[], clearFiles: () => void) => any) | undefined;
|
|
9
11
|
onErrors?: ((val: FileInputError[]) => any) | undefined;
|
|
10
12
|
}>, {
|
|
11
13
|
multiple: boolean;
|
|
@@ -110,8 +110,8 @@ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props & {
|
|
|
110
110
|
blur: (val: FocusEvent) => any;
|
|
111
111
|
input: (val: InputEvent) => any;
|
|
112
112
|
submit: (val: string, suggestion?: any) => any;
|
|
113
|
-
keydown: (val: KeyboardEvent) => any;
|
|
114
113
|
focus: (val: FocusEvent) => any;
|
|
114
|
+
keydown: (val: KeyboardEvent) => any;
|
|
115
115
|
indicatorClick: (val: MouseEvent) => any;
|
|
116
116
|
}, string, import("vue").PublicProps, Readonly<Props & {
|
|
117
117
|
values?: string[] | undefined;
|
|
@@ -122,10 +122,10 @@ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props & {
|
|
|
122
122
|
onInput?: ((val: InputEvent) => any) | undefined;
|
|
123
123
|
onSubmit?: ((val: string, suggestion?: any) => any) | undefined;
|
|
124
124
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
125
|
+
onFocus?: ((val: FocusEvent) => any) | undefined;
|
|
126
|
+
onKeydown?: ((val: KeyboardEvent) => any) | undefined;
|
|
125
127
|
"onUpdate:inputValue"?: ((value: string) => any) | undefined;
|
|
126
128
|
"onUpdate:values"?: ((value: string[] | undefined) => any) | undefined;
|
|
127
|
-
onKeydown?: ((val: KeyboardEvent) => any) | undefined;
|
|
128
|
-
onFocus?: ((val: FocusEvent) => any) | undefined;
|
|
129
129
|
onIndicatorClick?: ((val: MouseEvent) => any) | undefined;
|
|
130
130
|
}>, {
|
|
131
131
|
disabled: boolean;
|
|
@@ -110,8 +110,8 @@ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props & {
|
|
|
110
110
|
blur: (val: FocusEvent) => any;
|
|
111
111
|
input: (val: InputEvent) => any;
|
|
112
112
|
submit: (val: string, suggestion?: any) => any;
|
|
113
|
-
keydown: (val: KeyboardEvent) => any;
|
|
114
113
|
focus: (val: FocusEvent) => any;
|
|
114
|
+
keydown: (val: KeyboardEvent) => any;
|
|
115
115
|
indicatorClick: (val: MouseEvent) => any;
|
|
116
116
|
}, string, import("vue").PublicProps, Readonly<Props & {
|
|
117
117
|
values?: string[] | undefined;
|
|
@@ -122,10 +122,10 @@ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props & {
|
|
|
122
122
|
onInput?: ((val: InputEvent) => any) | undefined;
|
|
123
123
|
onSubmit?: ((val: string, suggestion?: any) => any) | undefined;
|
|
124
124
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
125
|
+
onFocus?: ((val: FocusEvent) => any) | undefined;
|
|
126
|
+
onKeydown?: ((val: KeyboardEvent) => any) | undefined;
|
|
125
127
|
"onUpdate:inputValue"?: ((value: string) => any) | undefined;
|
|
126
128
|
"onUpdate:values"?: ((value: string[] | undefined) => any) | undefined;
|
|
127
|
-
onKeydown?: ((val: KeyboardEvent) => any) | undefined;
|
|
128
|
-
onFocus?: ((val: FocusEvent) => any) | undefined;
|
|
129
129
|
onIndicatorClick?: ((val: MouseEvent) => any) | undefined;
|
|
130
130
|
}>, {
|
|
131
131
|
disabled: boolean;
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
</div>
|
|
93
93
|
</div>
|
|
94
94
|
<slot
|
|
95
|
-
v-if="notification.message"
|
|
95
|
+
v-if="notification.message && !notification.component"
|
|
96
96
|
name="message"
|
|
97
97
|
v-bind="setSlotVar('message', {
|
|
98
98
|
class: `
|
|
@@ -112,6 +112,21 @@
|
|
|
112
112
|
{{ notification.message }}
|
|
113
113
|
</div>
|
|
114
114
|
</slot>
|
|
115
|
+
<Component
|
|
116
|
+
v-if="notification.component"
|
|
117
|
+
:is="notification.component"
|
|
118
|
+
v-bind="{
|
|
119
|
+
message: notification.message,
|
|
120
|
+
messageClasses: `
|
|
121
|
+
notification--message
|
|
122
|
+
whitespace-pre-wrap
|
|
123
|
+
text-neutral-800
|
|
124
|
+
dark:text-neutral-200
|
|
125
|
+
mb-1
|
|
126
|
+
`,
|
|
127
|
+
...notification.componentProps ?? {}
|
|
128
|
+
}"
|
|
129
|
+
/>
|
|
115
130
|
<div class="notification--footer flex items-end justify-between">
|
|
116
131
|
<div
|
|
117
132
|
v-if="notification.code"
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CustomNotificationComponentProps } from "../../types/index.js";
|
|
2
|
+
type __VLS_Props = CustomNotificationComponentProps & {
|
|
3
|
+
customProp: string;
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="border-2 border-accent-500 p-1 px-2 rounded-sm bg-accent-500/10">
|
|
3
|
+
<div class="text-lg">
|
|
4
|
+
Custom Message Component
|
|
5
|
+
</div>
|
|
6
|
+
<div class="font-bold">
|
|
7
|
+
Original message:
|
|
8
|
+
</div>
|
|
9
|
+
<div
|
|
10
|
+
:class="props.messageClasses"
|
|
11
|
+
>
|
|
12
|
+
{{ props.message }}
|
|
13
|
+
</div>
|
|
14
|
+
<div class="font-bold">
|
|
15
|
+
Custom Prop:
|
|
16
|
+
</div>
|
|
17
|
+
<div>
|
|
18
|
+
{{ props.customProp }}
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
const props = defineProps({
|
|
25
|
+
message: { type: String, required: true },
|
|
26
|
+
messageClasses: { type: String, required: false },
|
|
27
|
+
customProp: { type: String, required: true }
|
|
28
|
+
});
|
|
29
|
+
</script>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CustomNotificationComponentProps } from "../../types/index.js";
|
|
2
|
+
type __VLS_Props = CustomNotificationComponentProps & {
|
|
3
|
+
customProp: string;
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
6
|
+
export default _default;
|
|
@@ -22,12 +22,12 @@ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props & {
|
|
|
22
22
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
23
23
|
onClose?: (() => any) | undefined;
|
|
24
24
|
}>, {
|
|
25
|
-
canClose: boolean;
|
|
26
25
|
useDialogForBackdrop: false;
|
|
27
26
|
useBackdrop: boolean;
|
|
28
27
|
preferredHorizontal: ("center" | "right" | "left" | "either" | "center-screen" | "right-most" | "left-most" | "center-most")[] | import("../../main.lib.js").PopupPositioner;
|
|
29
28
|
preferredVertical: ("top" | "bottom" | "center" | "either" | "center-screen" | "top-most" | "bottom-most" | "center-most")[] | import("../../main.lib.js").PopupPositioner;
|
|
30
29
|
avoidRepositioning: boolean;
|
|
30
|
+
canClose: boolean;
|
|
31
31
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
32
32
|
button?: (props: {
|
|
33
33
|
extractEl: (_: any) => any;
|
|
@@ -22,12 +22,12 @@ declare const _default: __VLS_WithSlots<import("vue").DefineComponent<Props & {
|
|
|
22
22
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
23
23
|
onClose?: (() => any) | undefined;
|
|
24
24
|
}>, {
|
|
25
|
-
canClose: boolean;
|
|
26
25
|
useDialogForBackdrop: false;
|
|
27
26
|
useBackdrop: boolean;
|
|
28
27
|
preferredHorizontal: ("center" | "right" | "left" | "either" | "center-screen" | "right-most" | "left-most" | "center-most")[] | import("../../main.lib.js").PopupPositioner;
|
|
29
28
|
preferredVertical: ("top" | "bottom" | "center" | "either" | "center-screen" | "top-most" | "bottom-most" | "center-most")[] | import("../../main.lib.js").PopupPositioner;
|
|
30
29
|
avoidRepositioning: boolean;
|
|
30
|
+
canClose: boolean;
|
|
31
31
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
32
32
|
button?: (props: {
|
|
33
33
|
extractEl: (_: any) => any;
|