@witchcraft/ui 0.3.24 → 0.3.26
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/animations.css +1 -1
- package/dist/runtime/assets/utils.css +1 -1
- package/dist/runtime/components/LibNotifications/LibNotification.vue +8 -5
- package/dist/runtime/components/LibNotifications/LibNotifications.vue +9 -11
- package/dist/runtime/helpers/NotificationHandler.d.ts +25 -3
- package/dist/runtime/helpers/NotificationHandler.js +5 -9
- package/package.json +43 -43
- package/src/runtime/assets/animations.css +2 -2
- package/src/runtime/assets/utils.css +43 -0
- package/src/runtime/components/LibNotifications/LibNotification.stories.ts +15 -0
- package/src/runtime/components/LibNotifications/LibNotification.vue +5 -2
- package/src/runtime/components/LibNotifications/LibNotifications.stories.ts +10 -6
- package/src/runtime/components/LibNotifications/LibNotifications.vue +9 -11
- package/src/runtime/helpers/NotificationHandler.ts +26 -11
package/dist/module.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@utility animate-from-*{--animate-from:--value([length,percentage]);--animate-from:calc(var(--spacing) * --value(integer))}@utility -animate-from-*{--animate-from:--value([length,percentage]);--animate-from:calc(var(--spacing) * -1 * --value(integer))}@theme{--animate-blinkInf:blink 1s linear infinite;@keyframes blink{0%{opacity:0}25%{opacity:1}75%{opacity:1}to{opacity:0}}--animate-slideBgInf:slide-bg 10s ease-in-out linear-infinite;@keyframes slide{0%{background-position:0}to{background-position:100%}}--animate-hide:hide 500ms ease-in;@keyframes hide{0%{opacity:1}to{opacity:0}}--animate-slideInLeft:slideInLeft 500ms cubic-bezier(0.16,1,0.3,1);@keyframes slideInLeft{0%{opacity:0;transform:translateX(var(--animate-from,100%))}to{opacity:1;transform:translateX(0)}}--animate-slideInRight:slideInLeft 500ms cubic-bezier(0.16,1,0.3,1);@keyframes slideInRight{0%{opacity:0;transform:translateX(var(--animate-from,-100%))}to{opacity:1;transform:translateX(0)}}--animate-slideInUp:slideInUp 500ms cubic-bezier(0.16,1,0.3,1);@keyframes slideInUp{0%{opacity:0;transform:translateY(var(--animate-from,100%))}to{opacity:1;transform:translateY(0)}}--animate-slideInDown:slideInDown 500ms cubic-bezier(0.16,1,0.3,1);@keyframes slideInDown{0%{opacity:0;transform:translateY(var(--animate-from,-100%))}to{opacity:1;transform:translateY(0)}}--animate-overlayShow:overlayShow 500ms cubic-bezier(0.16,1,0.3,1);@keyframes overlayShow{0%{opacity:0}to{opacity:1}}--animate-contentShow:contentShow 500ms cubic-bezier(0.16,1,0.3,1);@keyframes contentShow{0%{opacity:0;transform:translateY(-10%) scale(.96)}to{opacity:1;transform:scale(1)}}}
|
|
1
|
+
@utility animate-from-*{--animate-from:--value([length],[percentage]);--animate-from:calc(var(--spacing) * --value(integer))}@utility -animate-from-*{--animate-from:--value([length],[percentage]);--animate-from:calc(var(--spacing) * -1 * --value(integer))}@theme{--animate-blinkInf:blink 1s linear infinite;@keyframes blink{0%{opacity:0}25%{opacity:1}75%{opacity:1}to{opacity:0}}--animate-slideBgInf:slide-bg 10s ease-in-out linear-infinite;@keyframes slide{0%{background-position:0}to{background-position:100%}}--animate-hide:hide 500ms ease-in;@keyframes hide{0%{opacity:1}to{opacity:0}}--animate-slideInLeft:slideInLeft 500ms cubic-bezier(0.16,1,0.3,1);@keyframes slideInLeft{0%{opacity:0;transform:translateX(var(--animate-from,100%))}to{opacity:1;transform:translateX(0)}}--animate-slideInRight:slideInLeft 500ms cubic-bezier(0.16,1,0.3,1);@keyframes slideInRight{0%{opacity:0;transform:translateX(var(--animate-from,-100%))}to{opacity:1;transform:translateX(0)}}--animate-slideInUp:slideInUp 500ms cubic-bezier(0.16,1,0.3,1);@keyframes slideInUp{0%{opacity:0;transform:translateY(var(--animate-from,100%))}to{opacity:1;transform:translateY(0)}}--animate-slideInDown:slideInDown 500ms cubic-bezier(0.16,1,0.3,1);@keyframes slideInDown{0%{opacity:0;transform:translateY(var(--animate-from,-100%))}to{opacity:1;transform:translateY(0)}}--animate-overlayShow:overlayShow 500ms cubic-bezier(0.16,1,0.3,1);@keyframes overlayShow{0%{opacity:0}to{opacity:1}}--animate-contentShow:contentShow 500ms cubic-bezier(0.16,1,0.3,1);@keyframes contentShow{0%{opacity:0;transform:translateY(-10%) scale(.96)}to{opacity:1;transform:scale(1)}}}
|
|
@@ -1 +1 @@
|
|
|
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}@utility no-truncate{overflow:visible;text-overflow:unset;white-space:normal}
|
|
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 mix-from-*{--mix-from:--value(--color-*);--mix:color-mix(in srgb,var(--mix-from),var(--mix-to,transparent) var(--mix-percentage,50%))}@utility mix-to-*{--mix-to:--value(--color-*);--mix-percentage:calc(--modifier(integer) * 1%);--mix:color-mix(in srgb,var(--mix-from),var(--mix-to,transparent) var(--mix-percentage,50%))}@utility tint-*{--mix-from:--value(--color-*);--mix-to:#fff;--mix-percentage:calc(--modifier(integer) * 1%);--mix:color-mix(in srgb,var(--mix-from),var(--mix-to) var(--mix-percentage,20%))}@utility shade-*{--mix-from:--value(--color-*);--mix-to:#000;--mix-percentage:calc(--modifier(integer) * 1%);--mix:color-mix(in srgb,var(--mix-from),var(--mix-to) var(--mix-percentage))}@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}@utility no-truncate{overflow:visible;text-overflow:unset;white-space:normal}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
v-if="notification"
|
|
4
|
-
:class="
|
|
5
|
-
|
|
4
|
+
:class="
|
|
5
|
+
twMerge(
|
|
6
|
+
`
|
|
6
7
|
notification
|
|
7
8
|
bg-neutral-50
|
|
8
9
|
dark:bg-neutral-900
|
|
@@ -21,9 +22,11 @@
|
|
|
21
22
|
focus:border-accent-500
|
|
22
23
|
focus-within:border-accent-500
|
|
23
24
|
`,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
$attrs.class,
|
|
26
|
+
notification.notificationProps?.class
|
|
27
|
+
)
|
|
28
|
+
"
|
|
29
|
+
v-bind="{ ...$attrs, ...notification?.notificationProps ?? {}, class: void 0 }"
|
|
27
30
|
tabindex="0"
|
|
28
31
|
:data-id="notification.id"
|
|
29
32
|
ref="notificationEl"
|
|
@@ -77,27 +77,25 @@
|
|
|
77
77
|
data-[state=open]:animate-contentShow
|
|
78
78
|
max-sm:data-[state=open]:animate-slideInUp
|
|
79
79
|
fixed
|
|
80
|
-
flex
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
flex justify-center
|
|
81
|
+
top-1/2
|
|
82
|
+
left-1/2
|
|
83
|
+
w-full
|
|
84
84
|
sm:translate-x-[-50%]
|
|
85
85
|
sm:translate-y-[-50%]
|
|
86
|
-
|
|
87
|
-
max-sm:bottom-
|
|
86
|
+
p-2
|
|
87
|
+
max-sm:bottom-0
|
|
88
88
|
max-sm:top-[unset]
|
|
89
|
-
max-sm:left-
|
|
90
|
-
max-sm:right-2
|
|
91
|
-
max-sm:w-[calc(100%-var(--spacing)*4)]
|
|
89
|
+
max-sm:left-0
|
|
92
90
|
z-100
|
|
93
91
|
"
|
|
92
|
+
@interact-outside="topNotifications[0] && NotificationHandler.dismiss(topNotifications[0])"
|
|
94
93
|
>
|
|
95
94
|
<lib-notification
|
|
96
95
|
class="
|
|
97
96
|
w-full
|
|
98
97
|
sm:max-w-[700px]
|
|
99
|
-
max-
|
|
100
|
-
max-h-full
|
|
98
|
+
max-h-[80dvh]
|
|
101
99
|
top-notification
|
|
102
100
|
text-md
|
|
103
101
|
gap-2
|
|
@@ -32,18 +32,40 @@ export type RawNotificationEntry<TOptions extends string[] = ["Ok", "Cancel"], T
|
|
|
32
32
|
options?: TOptions;
|
|
33
33
|
/** @default false */
|
|
34
34
|
requiresAction?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* If true or a string (the cancel option) ensures the option exists and that is the "default" cancel action when a notification is dismissed in some manner that is not clicking one of the options (escaped, background click, etc.).
|
|
37
|
+
*
|
|
38
|
+
* This also enables cancelling via those secondary methods, otherwise the notification won't allow itself to be dismissed.
|
|
39
|
+
*
|
|
40
|
+
* @default undefined / false
|
|
41
|
+
*/
|
|
35
42
|
cancellable?: TCancellable;
|
|
36
43
|
/** @default "Ok" */
|
|
37
44
|
default?: TOptions[number];
|
|
38
45
|
/** @default [] */
|
|
39
46
|
dangerous?: TOptions[number][];
|
|
40
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Overrides the default timeout, can be set to true to just enable it. An entry must be cancellable to have a timeout.
|
|
49
|
+
*
|
|
50
|
+
* @default global timeout / false if cancellable is false
|
|
51
|
+
*/
|
|
41
52
|
timeout?: number | boolean;
|
|
42
53
|
icon?: string;
|
|
43
54
|
message: string;
|
|
44
55
|
component?: string | Component;
|
|
45
|
-
/** By default the component is passed the message and the
|
|
46
|
-
componentProps?: Record<string, any
|
|
56
|
+
/** Props for the custom component. By default the component is passed the message, the messageClasses, and the full notification. Both will be overriden if you set them on componentProps. */
|
|
57
|
+
componentProps?: Record<string, any> & {
|
|
58
|
+
notification: NotificationEntry;
|
|
59
|
+
message: string;
|
|
60
|
+
messageClasses: string;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Props for the notification component itself. They are bound to the root of the element and the class property is merged with twMerge.
|
|
64
|
+
*
|
|
65
|
+
* The most likely use is needing to adjust the width of fullscreen notifications, but fullscreen notifications have two widths (one for big screens and one for small ones (sm). You will usually want to do something like `{notificationProps: {class: 'sm:max-w-[90dvw]'}}` to change only the large one.
|
|
66
|
+
*
|
|
67
|
+
*/
|
|
68
|
+
notificationProps?: Record<string, any>;
|
|
47
69
|
};
|
|
48
70
|
export type NotificationEntry<TRawEntry extends RawNotificationEntry<any, any> = RawNotificationEntry<any, any>> = Omit<MakeRequired<TRawEntry, "options" | "requiresAction" | "default" | "dangerous">, "cancellable"> & {
|
|
49
71
|
promise: NotificationPromise;
|
|
@@ -57,13 +57,6 @@ export class NotificationHandler {
|
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
if (entry.timeout !== void 0 && !entry.cancellable) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
crop`Cannot timeout notification that is not cancellable:
|
|
63
|
-
${indent(pretty(entry), 5)}
|
|
64
|
-
`
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
60
|
if (entry.timeout !== void 0 && entry.requiresAction) {
|
|
68
61
|
throw new Error(
|
|
69
62
|
crop`Cannot timeout notification that requires action:
|
|
@@ -85,7 +78,6 @@ export class NotificationHandler {
|
|
|
85
78
|
requiresAction: false,
|
|
86
79
|
options: ["Ok", "Cancel"],
|
|
87
80
|
default: "Ok",
|
|
88
|
-
cancellable: rawEntry.cancellable,
|
|
89
81
|
...rawEntry,
|
|
90
82
|
component: rawEntry.component && typeof rawEntry.component !== "string" ? markRaw(rawEntry.component) : void 0,
|
|
91
83
|
dangerous: rawEntry.dangerous ?? [],
|
|
@@ -153,7 +145,11 @@ export class NotificationHandler {
|
|
|
153
145
|
const remaining = notification.timeout - notification._timer.elapsedBeforePause;
|
|
154
146
|
clearTimeout(notification._timer.id);
|
|
155
147
|
notification._timer.id = setTimeout(() => {
|
|
156
|
-
|
|
148
|
+
if (notification.cancellable) {
|
|
149
|
+
notification.resolve(notification.cancellable);
|
|
150
|
+
} else {
|
|
151
|
+
notification.resolve(notification.default);
|
|
152
|
+
}
|
|
157
153
|
}, remaining);
|
|
158
154
|
}
|
|
159
155
|
static resolveToDefault(notification) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@witchcraft/ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.26",
|
|
4
4
|
"description": "Vue component library.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/runtime/main.lib.js",
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"failOnWarn": false
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"tailwindcss": "^4.1
|
|
53
|
+
"tailwindcss": "^4.2.1",
|
|
54
54
|
"unplugin-icons": "^22.5.0",
|
|
55
|
-
"vue": "^3.5.
|
|
55
|
+
"vue": "^3.5.30"
|
|
56
56
|
},
|
|
57
57
|
"peerDependenciesMeta": {
|
|
58
58
|
"tailwindcss": {
|
|
@@ -63,20 +63,20 @@
|
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@alanscodelog/utils": "^6.0
|
|
67
|
-
"@iconify/json": "^2.2.
|
|
68
|
-
"@nuxt/kit": "^4.
|
|
69
|
-
"@nuxt/schema": "^4.
|
|
66
|
+
"@alanscodelog/utils": "^6.2.0",
|
|
67
|
+
"@iconify/json": "^2.2.450",
|
|
68
|
+
"@nuxt/kit": "^4.4.2",
|
|
69
|
+
"@nuxt/schema": "^4.4.2",
|
|
70
70
|
"@nuxt/types": "^2.18.1",
|
|
71
|
-
"@tailwindcss/vite": "^4.1
|
|
71
|
+
"@tailwindcss/vite": "^4.2.1",
|
|
72
72
|
"@witchcraft/nuxt-utils": "^0.3.6",
|
|
73
73
|
"colord": "^2.9.3",
|
|
74
74
|
"colorjs.io": "0.6.0-alpha.1",
|
|
75
75
|
"defu": "^6.1.4",
|
|
76
76
|
"fast-glob": "^3.3.3",
|
|
77
77
|
"metamorphosis": "^0.6.1",
|
|
78
|
-
"reka-ui": "^2.
|
|
79
|
-
"tailwind-merge": "^3.
|
|
78
|
+
"reka-ui": "^2.9.5",
|
|
79
|
+
"tailwind-merge": "^3.5.0",
|
|
80
80
|
"unplugin-icons": "^22.5.0",
|
|
81
81
|
"unplugin-vue-components": "^28.8.0",
|
|
82
82
|
"vue-component-type-helpers": "^2.2.12"
|
|
@@ -85,58 +85,58 @@
|
|
|
85
85
|
"@alanscodelog/commitlint-config": "^3.1.2",
|
|
86
86
|
"@alanscodelog/eslint-config": "^6.3.1",
|
|
87
87
|
"@alanscodelog/semantic-release-config": "^6.0.2",
|
|
88
|
-
"@alanscodelog/tsconfigs": "^6.
|
|
88
|
+
"@alanscodelog/tsconfigs": "^6.3.0",
|
|
89
89
|
"@alanscodelog/vite-config": "^0.0.7",
|
|
90
90
|
"@chromatic-com/storybook": "^3.2.7",
|
|
91
|
-
"@commitlint/cli": "^20.
|
|
92
|
-
"@internationalized/date": "^3.
|
|
91
|
+
"@commitlint/cli": "^20.5.0",
|
|
92
|
+
"@internationalized/date": "^3.12.0",
|
|
93
93
|
"@faker-js/faker": "^10.3.0",
|
|
94
|
-
"@nuxt/eslint-config": "^1.
|
|
94
|
+
"@nuxt/eslint-config": "^1.15.2",
|
|
95
95
|
"@nuxt/module-builder": "^1.0.2",
|
|
96
96
|
"@nuxtjs/i18n": "^9.5.6",
|
|
97
|
-
"@playwright/test": "
|
|
97
|
+
"@playwright/test": "=1.58.2",
|
|
98
98
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
99
|
-
"@storybook/addon-a11y": "^8.6.
|
|
100
|
-
"@storybook/addon-actions": "^8.6.
|
|
101
|
-
"@storybook/addon-essentials": "^8.6.
|
|
102
|
-
"@storybook/addon-interactions": "^8.6.
|
|
103
|
-
"@storybook/addon-links": "^8.6.
|
|
104
|
-
"@storybook/addon-storysource": "^8.6.
|
|
105
|
-
"@storybook/blocks": "^8.6.
|
|
106
|
-
"@storybook/manager-api": "^8.6.
|
|
107
|
-
"@storybook/test": "^8.6.
|
|
99
|
+
"@storybook/addon-a11y": "^8.6.18",
|
|
100
|
+
"@storybook/addon-actions": "^8.6.18",
|
|
101
|
+
"@storybook/addon-essentials": "^8.6.18",
|
|
102
|
+
"@storybook/addon-interactions": "^8.6.18",
|
|
103
|
+
"@storybook/addon-links": "^8.6.18",
|
|
104
|
+
"@storybook/addon-storysource": "^8.6.18",
|
|
105
|
+
"@storybook/blocks": "^8.6.18",
|
|
106
|
+
"@storybook/manager-api": "^8.6.18",
|
|
107
|
+
"@storybook/test": "^8.6.18",
|
|
108
108
|
"@storybook/test-runner": "^0.22.1",
|
|
109
|
-
"@storybook/vue3": "^8.6.
|
|
110
|
-
"@storybook/vue3-vite": "^8.6.
|
|
111
|
-
"@tanstack/vue-virtual": "^3.13.
|
|
112
|
-
"@tailwindcss/cli": "^4.1
|
|
113
|
-
"@tailwindcss/postcss": "^4.1
|
|
114
|
-
"@types/node": "^24.
|
|
115
|
-
"@vitejs/plugin-vue": "^6.0.
|
|
116
|
-
"@vue/runtime-core": "^3.5.
|
|
117
|
-
"@vue/runtime-dom": "^3.5.
|
|
109
|
+
"@storybook/vue3": "^8.6.18",
|
|
110
|
+
"@storybook/vue3-vite": "^8.6.18",
|
|
111
|
+
"@tanstack/vue-virtual": "^3.13.23",
|
|
112
|
+
"@tailwindcss/cli": "^4.2.1",
|
|
113
|
+
"@tailwindcss/postcss": "^4.2.1",
|
|
114
|
+
"@types/node": "^24.12.0",
|
|
115
|
+
"@vitejs/plugin-vue": "^6.0.5",
|
|
116
|
+
"@vue/runtime-core": "^3.5.30",
|
|
117
|
+
"@vue/runtime-dom": "^3.5.30",
|
|
118
118
|
"@vueuse/components": "^13.9.0",
|
|
119
119
|
"@vueuse/core": "^13.9.0",
|
|
120
|
-
"autoprefixer": "^10.4.
|
|
120
|
+
"autoprefixer": "^10.4.27",
|
|
121
121
|
"concurrently": "^9.2.1",
|
|
122
|
-
"eslint": "^9.39.
|
|
122
|
+
"eslint": "^9.39.4",
|
|
123
123
|
"http-server": "^14.1.1",
|
|
124
124
|
"husky": "^9.1.7",
|
|
125
125
|
"indexit": "2.1.0-beta.3",
|
|
126
126
|
"madge": "^7.0.0",
|
|
127
|
-
"nuxt": "^4.
|
|
128
|
-
"playwright": "
|
|
129
|
-
"playwright-core": "
|
|
127
|
+
"nuxt": "^4.4.2",
|
|
128
|
+
"playwright": "=1.58.2",
|
|
129
|
+
"playwright-core": "=1.58.2",
|
|
130
130
|
"semantic-release": "^24.2.9",
|
|
131
|
-
"storybook": "^8.6.
|
|
131
|
+
"storybook": "^8.6.18",
|
|
132
132
|
"storybook-dark-mode": "^4.0.2",
|
|
133
|
-
"tailwindcss": "^4.1
|
|
133
|
+
"tailwindcss": "^4.2.1",
|
|
134
134
|
"ts-node": "^10.9.2",
|
|
135
135
|
"typescript": "^5.9.3",
|
|
136
136
|
"unbuild": "^3.6.1",
|
|
137
137
|
"vite": "^7.3.1",
|
|
138
|
-
"vite-tsconfig-paths": "^6.1.
|
|
139
|
-
"vue": "^3.5.
|
|
138
|
+
"vite-tsconfig-paths": "^6.1.1",
|
|
139
|
+
"vue": "^3.5.30",
|
|
140
140
|
"vue-tsc": "3.2.4",
|
|
141
141
|
"wait-on": "^8.0.5"
|
|
142
142
|
},
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
"build:only": "nuxt-module-build build",
|
|
177
177
|
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
178
178
|
"dev": "nuxi dev playground",
|
|
179
|
-
"storybook": "BROWSER=none storybook dev -p 6006",
|
|
179
|
+
"storybook": "BROWSER=none storybook dev -p 6006 --no-open",
|
|
180
180
|
"storybook:clear-cache": "BROWSER=none storybook dev -p 6006 --no-manager-cache",
|
|
181
181
|
"storybook:build": "pnpm nuxt prepare && storybook build -o docs/storybook",
|
|
182
182
|
"storybook:test": "pnpm storybook:build && pnpm concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"pnpm http-server docs/storybook --port 6006 --silent\" \"pnpm wait-on tcp:6006 && pnpm test-storybook --excludeTags 'skip-smoke-test'\"",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
@utility animate-from-* {
|
|
2
|
-
--animate-from: --value([length, percentage]);
|
|
2
|
+
--animate-from: --value([length], [percentage]);
|
|
3
3
|
--animate-from: calc(var(--spacing) * --value(integer));
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
@utility -animate-from-* {
|
|
7
|
-
--animate-from: --value([length, percentage]);
|
|
7
|
+
--animate-from: --value([length], [percentage]);
|
|
8
8
|
--animate-from: calc(var(--spacing) * -1 * --value(integer));
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -115,6 +115,49 @@
|
|
|
115
115
|
--bars-fg-width: calc(--value(integer) * 1%, 50%);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
/* Mix utils can be used like bg-(--mix) mix-from-red-500 mix-to-blue-500/20 (where 20 is the percentage of "to"). It mixes with transparent if no from/to. There are also tint-* and shade-* variants to mix with white and black respectively. */
|
|
119
|
+
@utility mix-from-* {
|
|
120
|
+
--mix-from: --value(--color-*);
|
|
121
|
+
--mix: color-mix(
|
|
122
|
+
in srgb,
|
|
123
|
+
var(--mix-from),
|
|
124
|
+
var(--mix-to, transparent) var(--mix-percentage, 50%)
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@utility mix-to-* {
|
|
129
|
+
--mix-to: --value(--color-*);
|
|
130
|
+
--mix-percentage: calc(--modifier(integer) * 1%);
|
|
131
|
+
--mix: color-mix(
|
|
132
|
+
in srgb,
|
|
133
|
+
var(--mix-from),
|
|
134
|
+
var(--mix-to, transparent) var(--mix-percentage, 50%)
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@utility tint-* {
|
|
139
|
+
--mix-from: --value(--color-*);
|
|
140
|
+
--mix-to: white;
|
|
141
|
+
--mix-percentage: calc(--modifier(integer) * 1%);
|
|
142
|
+
--mix: color-mix(
|
|
143
|
+
in srgb,
|
|
144
|
+
var(--mix-from),
|
|
145
|
+
var(--mix-to) var(--mix-percentage, 20%)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@utility shade-* {
|
|
150
|
+
--mix-from: --value(--color-*);
|
|
151
|
+
--mix-to: black;
|
|
152
|
+
--mix-percentage: calc(--modifier(integer) * 1%);
|
|
153
|
+
--mix: color-mix(
|
|
154
|
+
in srgb,
|
|
155
|
+
var(--mix-from),
|
|
156
|
+
var(--mix-to) var(--mix-percentage)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
118
161
|
@utility scrollbar-hidden {
|
|
119
162
|
/* IE and Edge */
|
|
120
163
|
-ms-overflow-style: none;
|
|
@@ -157,3 +157,18 @@ export const CustomMessageComponent: Story = {
|
|
|
157
157
|
})
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
|
+
|
|
161
|
+
export const CustomNotificationProps: Story = {
|
|
162
|
+
...Primary,
|
|
163
|
+
args: {
|
|
164
|
+
...Primary.args,
|
|
165
|
+
// @ts-expect-error calling protected method
|
|
166
|
+
notification: handler._createEntry({
|
|
167
|
+
...Primary.args!.notification,
|
|
168
|
+
message: "Should be 300px wide",
|
|
169
|
+
notificationProps: {
|
|
170
|
+
class: "w-[300px]!"
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -20,8 +20,11 @@
|
|
|
20
20
|
focus:border-accent-500
|
|
21
21
|
focus-within:border-accent-500
|
|
22
22
|
`,
|
|
23
|
-
($attrs as any).class
|
|
24
|
-
|
|
23
|
+
($attrs as any).class,
|
|
24
|
+
notification.notificationProps?.class
|
|
25
|
+
)
|
|
26
|
+
"
|
|
27
|
+
v-bind="{ ...$attrs, ...(notification?.notificationProps ?? {}), class: undefined }"
|
|
25
28
|
tabindex="0"
|
|
26
29
|
:data-id="notification.id"
|
|
27
30
|
ref="notificationEl"
|
|
@@ -34,14 +34,16 @@ export const Primary: Story = {
|
|
|
34
34
|
const paragraphs = `\n Simulating lots of text:\n${faker.lorem.paragraphs(20)}`
|
|
35
35
|
const extraText = computed(() => lotsOfText.value ? paragraphs : "")
|
|
36
36
|
|
|
37
|
-
const notifyRequiresAction = () => {
|
|
37
|
+
const notifyRequiresAction = (options: any) => {
|
|
38
38
|
count++
|
|
39
39
|
void handler.notify({
|
|
40
40
|
title: withTitle.value ? `Notification(${count})` : undefined,
|
|
41
|
-
message: `This is a notification that requires action. Pick an option:${extraText.value}`,
|
|
41
|
+
message: `This is a cancellable notification that requires action. Pick an option:${extraText.value}`,
|
|
42
42
|
requiresAction: true,
|
|
43
43
|
options: ["Ok", "Default Answer", "Cancel"],
|
|
44
|
-
default: "Default Answer"
|
|
44
|
+
default: "Default Answer",
|
|
45
|
+
cancellable: true,
|
|
46
|
+
...options
|
|
45
47
|
})
|
|
46
48
|
}
|
|
47
49
|
|
|
@@ -49,8 +51,9 @@ export const Primary: Story = {
|
|
|
49
51
|
count++
|
|
50
52
|
void handler.notify({
|
|
51
53
|
title: withTitle.value ? `Notification(${count})` : undefined,
|
|
52
|
-
message: `This is a notification that has a dangerous option. Pick an option:${extraText.value}`,
|
|
54
|
+
message: `This is a cancellable notification that has a dangerous option. Pick an option:${extraText.value}`,
|
|
53
55
|
options: ["Ok", "Default Answer", "Dangerous Option", "Cancel"],
|
|
56
|
+
cancellable: true,
|
|
54
57
|
default: "Default Answer",
|
|
55
58
|
dangerous: ["Dangerous Option"]
|
|
56
59
|
})
|
|
@@ -105,9 +108,10 @@ export const Primary: Story = {
|
|
|
105
108
|
template: `
|
|
106
109
|
<lib-root :outline="args.outline" :notification-handler="handler">
|
|
107
110
|
<lib-button :label="'Notify Timeoutable'" @click="notifyTimeoutable()"></lib-button>
|
|
108
|
-
<lib-button :label="'Notify RequiresAction'" @click="notifyRequiresAction()"></lib-button>
|
|
111
|
+
<lib-button :label="'Notify RequiresAction (Cancellable)'" @click="notifyRequiresAction()"></lib-button>
|
|
112
|
+
<lib-button :label="'Notify RequiresAction (Cancellable) - Custom Width'" @click="notifyRequiresAction({cancellable:true,notificationProps: {class: 'sm:max-w-[90dvw]'}})"></lib-button>
|
|
109
113
|
<lib-button :label="'Notify Non-Cancellable that RequiresAction'" @click="notifyNonCancellableRequiresAction()"></lib-button>
|
|
110
|
-
<lib-button :label="'Notify With Dangerous Option'" @click="notifyWithDangerousOption()"></lib-button>
|
|
114
|
+
<lib-button :label="'Notify With Dangerous Option (Cancellable)'" @click="notifyWithDangerousOption()"></lib-button>
|
|
111
115
|
<lib-button :label="'Notify Non-Cancellable'" @click="notifyNonCancellable()"></lib-button>
|
|
112
116
|
<lib-checkbox v-model="lotsOfText">Use lots of text</lib-checkbox>
|
|
113
117
|
<lib-checkbox v-model="disableTimeout">Disable Timeout</lib-checkbox>
|
|
@@ -77,27 +77,25 @@
|
|
|
77
77
|
data-[state=open]:animate-contentShow
|
|
78
78
|
max-sm:data-[state=open]:animate-slideInUp
|
|
79
79
|
fixed
|
|
80
|
-
flex
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
flex justify-center
|
|
81
|
+
top-1/2
|
|
82
|
+
left-1/2
|
|
83
|
+
w-full
|
|
84
84
|
sm:translate-x-[-50%]
|
|
85
85
|
sm:translate-y-[-50%]
|
|
86
|
-
|
|
87
|
-
max-sm:bottom-
|
|
86
|
+
p-2
|
|
87
|
+
max-sm:bottom-0
|
|
88
88
|
max-sm:top-[unset]
|
|
89
|
-
max-sm:left-
|
|
90
|
-
max-sm:right-2
|
|
91
|
-
max-sm:w-[calc(100%-var(--spacing)*4)]
|
|
89
|
+
max-sm:left-0
|
|
92
90
|
z-100
|
|
93
91
|
"
|
|
92
|
+
@interact-outside="topNotifications[0] && NotificationHandler.dismiss(topNotifications[0])"
|
|
94
93
|
>
|
|
95
94
|
<lib-notification
|
|
96
95
|
class="
|
|
97
96
|
w-full
|
|
98
97
|
sm:max-w-[700px]
|
|
99
|
-
max-
|
|
100
|
-
max-h-full
|
|
98
|
+
max-h-[80dvh]
|
|
101
99
|
top-notification
|
|
102
100
|
text-md
|
|
103
101
|
gap-2
|
|
@@ -71,12 +71,6 @@ export class NotificationHandler<
|
|
|
71
71
|
`)
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
if (entry.timeout !== undefined && !entry.cancellable) {
|
|
75
|
-
throw new Error(
|
|
76
|
-
crop`Cannot timeout notification that is not cancellable:
|
|
77
|
-
${indent(pretty(entry), 5)}
|
|
78
|
-
`)
|
|
79
|
-
}
|
|
80
74
|
if (entry.timeout !== undefined && entry.requiresAction) {
|
|
81
75
|
throw new Error(
|
|
82
76
|
crop`Cannot timeout notification that requires action:
|
|
@@ -97,7 +91,6 @@ export class NotificationHandler<
|
|
|
97
91
|
requiresAction: false,
|
|
98
92
|
options: ["Ok", "Cancel"],
|
|
99
93
|
default: "Ok",
|
|
100
|
-
cancellable: rawEntry.cancellable,
|
|
101
94
|
...rawEntry,
|
|
102
95
|
component: rawEntry.component && typeof rawEntry.component !== "string" ? markRaw(rawEntry.component) : undefined,
|
|
103
96
|
dangerous: rawEntry.dangerous ?? [],
|
|
@@ -178,7 +171,11 @@ export class NotificationHandler<
|
|
|
178
171
|
const remaining = notification.timeout - notification._timer.elapsedBeforePause
|
|
179
172
|
clearTimeout(notification._timer.id)
|
|
180
173
|
notification._timer.id = setTimeout(() => {
|
|
181
|
-
|
|
174
|
+
if (notification.cancellable) {
|
|
175
|
+
notification.resolve(notification.cancellable)
|
|
176
|
+
} else {
|
|
177
|
+
notification.resolve(notification.default)
|
|
178
|
+
}
|
|
182
179
|
}, remaining)
|
|
183
180
|
}
|
|
184
181
|
|
|
@@ -218,18 +215,36 @@ export type RawNotificationEntry<
|
|
|
218
215
|
options?: TOptions
|
|
219
216
|
/** @default false */
|
|
220
217
|
requiresAction?: boolean
|
|
218
|
+
/**
|
|
219
|
+
* If true or a string (the cancel option) ensures the option exists and that is the "default" cancel action when a notification is dismissed in some manner that is not clicking one of the options (escaped, background click, etc.).
|
|
220
|
+
*
|
|
221
|
+
* This also enables cancelling via those secondary methods, otherwise the notification won't allow itself to be dismissed.
|
|
222
|
+
*
|
|
223
|
+
* @default undefined / false
|
|
224
|
+
*/
|
|
221
225
|
cancellable?: TCancellable
|
|
222
226
|
/** @default "Ok" */
|
|
223
227
|
default?: TOptions[number]
|
|
224
228
|
/** @default [] */
|
|
225
229
|
dangerous?: TOptions[number][]
|
|
226
|
-
/**
|
|
230
|
+
/**
|
|
231
|
+
* Overrides the default timeout, can be set to true to just enable it. An entry must be cancellable to have a timeout.
|
|
232
|
+
*
|
|
233
|
+
* @default global timeout / false if cancellable is false
|
|
234
|
+
*/
|
|
227
235
|
timeout?: number | boolean
|
|
228
236
|
icon?: string
|
|
229
237
|
message: string
|
|
230
238
|
component?: string | Component
|
|
231
|
-
/** By default the component is passed the message and the
|
|
232
|
-
componentProps?: Record<string, any>
|
|
239
|
+
/** Props for the custom component. By default the component is passed the message, the messageClasses, and the full notification. Both will be overriden if you set them on componentProps. */
|
|
240
|
+
componentProps?: Record<string, any> & { notification: NotificationEntry, message: string, messageClasses: string }
|
|
241
|
+
/**
|
|
242
|
+
* Props for the notification component itself. They are bound to the root of the element and the class property is merged with twMerge.
|
|
243
|
+
*
|
|
244
|
+
* The most likely use is needing to adjust the width of fullscreen notifications, but fullscreen notifications have two widths (one for big screens and one for small ones (sm). You will usually want to do something like `{notificationProps: {class: 'sm:max-w-[90dvw]'}}` to change only the large one.
|
|
245
|
+
*
|
|
246
|
+
*/
|
|
247
|
+
notificationProps?: Record<string, any>
|
|
233
248
|
}
|
|
234
249
|
|
|
235
250
|
export type NotificationEntry<
|