@witchcraft/ui 0.3.24 → 0.3.25

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "witchcraftUi",
3
3
  "configKey": "witchcraftUi",
4
- "version": "0.3.24",
4
+ "version": "0.3.25",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -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)}}}
@@ -36,16 +36,16 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<Props
36
36
  }> & Readonly<{
37
37
  "onUpdate:modelValue"?: ((value: RgbaColor) => any) | undefined;
38
38
  onCancel?: (() => any) | undefined;
39
- onSave?: (() => any) | undefined;
40
39
  "onUpdate:tempValue"?: ((value: RgbaColor | undefined) => any) | undefined;
40
+ onSave?: (() => any) | undefined;
41
41
  }>, {
42
42
  border: boolean;
43
43
  allowAlpha: boolean;
44
+ copyTransform: (val: HsvaColor, stringVal: string) => any;
44
45
  stringPrecision: number;
45
46
  customRepresentation: {
46
47
  fromHsvaToString: (hsva: HsvaColor, includeAlpha: boolean) => string;
47
48
  };
48
- copyTransform: (val: HsvaColor, stringVal: string) => any;
49
49
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
50
50
  default?: (props: {
51
51
  stringColor: string;
@@ -36,16 +36,16 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<Props
36
36
  }> & Readonly<{
37
37
  "onUpdate:modelValue"?: ((value: RgbaColor) => any) | undefined;
38
38
  onCancel?: (() => any) | undefined;
39
- onSave?: (() => any) | undefined;
40
39
  "onUpdate:tempValue"?: ((value: RgbaColor | undefined) => any) | undefined;
40
+ onSave?: (() => any) | undefined;
41
41
  }>, {
42
42
  border: boolean;
43
43
  allowAlpha: boolean;
44
+ copyTransform: (val: HsvaColor, stringVal: string) => any;
44
45
  stringPrecision: number;
45
46
  customRepresentation: {
46
47
  fromHsvaToString: (hsva: HsvaColor, includeAlpha: boolean) => string;
47
48
  };
48
- copyTransform: (val: HsvaColor, stringVal: string) => any;
49
49
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
50
50
  default?: (props: {
51
51
  stringColor: string;
@@ -40,18 +40,18 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
40
40
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
41
41
  "onUpdate:modelValue"?: ((value: RgbaColor) => any) | undefined;
42
42
  onCancel?: (() => any) | undefined;
43
- onSave?: ((val: RgbaColor) => any) | undefined;
44
43
  "onUpdate:tempValue"?: ((value: RgbaColor | undefined) => any) | undefined;
44
+ onSave?: ((val: RgbaColor) => any) | undefined;
45
45
  }>, {
46
46
  border: boolean;
47
- valid: boolean;
48
47
  allowAlpha: boolean;
48
+ copyTransform: (val: HsvaColor, stringVal: string) => any;
49
49
  stringPrecision: number;
50
50
  customRepresentation: {
51
51
  fromHsvaToString: (hsva: HsvaColor, includeAlpha: boolean) => string;
52
52
  fromStringToHsva?: (string: string) => HsvaColor | undefined;
53
53
  };
54
- copyTransform: (val: HsvaColor, stringVal: string) => any;
54
+ valid: boolean;
55
55
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
56
56
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
57
57
  declare const _default: typeof __VLS_export;
@@ -40,18 +40,18 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
40
40
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
41
41
  "onUpdate:modelValue"?: ((value: RgbaColor) => any) | undefined;
42
42
  onCancel?: (() => any) | undefined;
43
- onSave?: ((val: RgbaColor) => any) | undefined;
44
43
  "onUpdate:tempValue"?: ((value: RgbaColor | undefined) => any) | undefined;
44
+ onSave?: ((val: RgbaColor) => any) | undefined;
45
45
  }>, {
46
46
  border: boolean;
47
- valid: boolean;
48
47
  allowAlpha: boolean;
48
+ copyTransform: (val: HsvaColor, stringVal: string) => any;
49
49
  stringPrecision: number;
50
50
  customRepresentation: {
51
51
  fromHsvaToString: (hsva: HsvaColor, includeAlpha: boolean) => string;
52
52
  fromStringToHsva?: (string: string) => HsvaColor | undefined;
53
53
  };
54
- copyTransform: (val: HsvaColor, stringVal: string) => any;
54
+ valid: boolean;
55
55
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
56
56
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
57
57
  declare const _default: typeof __VLS_export;
@@ -112,8 +112,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<Props
112
112
  input: (val: InputEvent) => any;
113
113
  blur: (val: FocusEvent) => any;
114
114
  submit: (val: string, suggestion?: any) => any;
115
- keydown: (val: KeyboardEvent) => any;
116
115
  focus: (val: FocusEvent) => any;
116
+ keydown: (val: KeyboardEvent) => any;
117
117
  indicatorClick: (val: MouseEvent) => any;
118
118
  }, string, import("vue").PublicProps, Readonly<Props & {
119
119
  values?: string[] | undefined;
@@ -124,10 +124,10 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<Props
124
124
  onBlur?: ((val: FocusEvent) => any) | undefined;
125
125
  onSubmit?: ((val: string, suggestion?: any) => any) | undefined;
126
126
  "onUpdate:modelValue"?: ((value: string) => any) | undefined;
127
+ onFocus?: ((val: FocusEvent) => any) | undefined;
128
+ onKeydown?: ((val: KeyboardEvent) => any) | undefined;
127
129
  "onUpdate:inputValue"?: ((value: string) => any) | undefined;
128
130
  "onUpdate:values"?: ((value: string[] | undefined) => any) | undefined;
129
- onKeydown?: ((val: KeyboardEvent) => any) | undefined;
130
- onFocus?: ((val: FocusEvent) => any) | undefined;
131
131
  onIndicatorClick?: ((val: MouseEvent) => any) | undefined;
132
132
  }>, {
133
133
  disabled: boolean;
@@ -112,8 +112,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<Props
112
112
  input: (val: InputEvent) => any;
113
113
  blur: (val: FocusEvent) => any;
114
114
  submit: (val: string, suggestion?: any) => any;
115
- keydown: (val: KeyboardEvent) => any;
116
115
  focus: (val: FocusEvent) => any;
116
+ keydown: (val: KeyboardEvent) => any;
117
117
  indicatorClick: (val: MouseEvent) => any;
118
118
  }, string, import("vue").PublicProps, Readonly<Props & {
119
119
  values?: string[] | undefined;
@@ -124,10 +124,10 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<Props
124
124
  onBlur?: ((val: FocusEvent) => any) | undefined;
125
125
  onSubmit?: ((val: string, suggestion?: any) => any) | undefined;
126
126
  "onUpdate:modelValue"?: ((value: string) => any) | undefined;
127
+ onFocus?: ((val: FocusEvent) => any) | undefined;
128
+ onKeydown?: ((val: KeyboardEvent) => any) | undefined;
127
129
  "onUpdate:inputValue"?: ((value: string) => any) | undefined;
128
130
  "onUpdate:values"?: ((value: string[] | undefined) => any) | undefined;
129
- onKeydown?: ((val: KeyboardEvent) => any) | undefined;
130
- onFocus?: ((val: FocusEvent) => any) | undefined;
131
131
  onIndicatorClick?: ((val: MouseEvent) => any) | undefined;
132
132
  }>, {
133
133
  disabled: boolean;
@@ -1,8 +1,9 @@
1
1
  <template>
2
2
  <div
3
3
  v-if="notification"
4
- :class="twMerge(
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
- $attrs.class
25
- )"
26
- v-bind="{ ...$attrs, class: void 0 }"
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
- max-h-[80dvh]
82
- top-[50%]
83
- left-[50%]
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
- max-w-[700px]
87
- max-sm:bottom-2
86
+ p-2
87
+ max-sm:bottom-0
88
88
  max-sm:top-[unset]
89
- max-sm:left-2
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-w-full
100
- max-h-full
98
+ max-h-[80dvh]
101
99
  top-notification
102
100
  text-md
103
101
  gap-2
@@ -24,12 +24,12 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<Props
24
24
  "onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
25
25
  onClose?: (() => any) | undefined;
26
26
  }>, {
27
- canClose: boolean;
28
27
  useDialogForBackdrop: false;
29
28
  useBackdrop: boolean;
30
29
  preferredHorizontal: ("center" | "right" | "left" | "either" | "center-screen" | "right-most" | "left-most" | "center-most")[] | import("../../main.lib.js").PopupPositioner;
31
30
  preferredVertical: ("top" | "bottom" | "center" | "either" | "center-screen" | "top-most" | "bottom-most" | "center-most")[] | import("../../main.lib.js").PopupPositioner;
32
31
  avoidRepositioning: boolean;
32
+ canClose: boolean;
33
33
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
34
34
  button?: (props: {
35
35
  extractEl: (_: any) => any;
@@ -24,12 +24,12 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<Props
24
24
  "onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
25
25
  onClose?: (() => any) | undefined;
26
26
  }>, {
27
- canClose: boolean;
28
27
  useDialogForBackdrop: false;
29
28
  useBackdrop: boolean;
30
29
  preferredHorizontal: ("center" | "right" | "left" | "either" | "center-screen" | "right-most" | "left-most" | "center-most")[] | import("../../main.lib.js").PopupPositioner;
31
30
  preferredVertical: ("top" | "bottom" | "center" | "either" | "center-screen" | "top-most" | "bottom-most" | "center-most")[] | import("../../main.lib.js").PopupPositioner;
32
31
  avoidRepositioning: boolean;
32
+ canClose: boolean;
33
33
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
34
34
  button?: (props: {
35
35
  extractEl: (_: any) => any;
@@ -32,18 +32,36 @@ 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
- /** @default false if cancellable, otherwise the default timeout */
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 messageClasses. Both will be overriden if you set them on componentProps. */
56
+ /** Props for the custom component. By default the component is passed the message and the messageClasses. Both will be overriden if you set them on componentProps. */
46
57
  componentProps?: Record<string, any>;
58
+ /**
59
+ * Props for the notification component itself. They are bound to the root of the element and the class property is merged with twMerge.
60
+ *
61
+ * 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.
62
+ *
63
+ */
64
+ notificationProps?: Record<string, any>;
47
65
  };
48
66
  export type NotificationEntry<TRawEntry extends RawNotificationEntry<any, any> = RawNotificationEntry<any, any>> = Omit<MakeRequired<TRawEntry, "options" | "requiresAction" | "default" | "dangerous">, "cancellable"> & {
49
67
  promise: NotificationPromise;
@@ -85,7 +85,6 @@ export class NotificationHandler {
85
85
  requiresAction: false,
86
86
  options: ["Ok", "Cancel"],
87
87
  default: "Ok",
88
- cancellable: rawEntry.cancellable,
89
88
  ...rawEntry,
90
89
  component: rawEntry.component && typeof rawEntry.component !== "string" ? markRaw(rawEntry.component) : void 0,
91
90
  dangerous: rawEntry.dangerous ?? [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@witchcraft/ui",
3
- "version": "0.3.24",
3
+ "version": "0.3.25",
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.18",
53
+ "tailwindcss": "^4.2.1",
54
54
  "unplugin-icons": "^22.5.0",
55
- "vue": "^3.5.27"
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.2",
67
- "@iconify/json": "^2.2.437",
68
- "@nuxt/kit": "^4.3.1",
69
- "@nuxt/schema": "^4.3.1",
66
+ "@alanscodelog/utils": "^6.1.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.18",
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.8.0",
79
- "tailwind-merge": "^3.4.0",
78
+ "reka-ui": "^2.9.2",
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"
@@ -88,55 +88,55 @@
88
88
  "@alanscodelog/tsconfigs": "^6.2.0",
89
89
  "@alanscodelog/vite-config": "^0.0.7",
90
90
  "@chromatic-com/storybook": "^3.2.7",
91
- "@commitlint/cli": "^20.4.1",
92
- "@internationalized/date": "^3.11.0",
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.14.0",
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": "^1.54.0",
97
+ "@playwright/test": "^1.58.2",
98
98
  "@rollup/plugin-node-resolve": "^16.0.3",
99
- "@storybook/addon-a11y": "^8.6.15",
100
- "@storybook/addon-actions": "^8.6.15",
101
- "@storybook/addon-essentials": "^8.6.14",
102
- "@storybook/addon-interactions": "^8.6.14",
103
- "@storybook/addon-links": "^8.6.15",
104
- "@storybook/addon-storysource": "^8.6.14",
105
- "@storybook/blocks": "^8.6.14",
106
- "@storybook/manager-api": "^8.6.14",
107
- "@storybook/test": "^8.6.15",
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.15",
110
- "@storybook/vue3-vite": "^8.6.15",
111
- "@tanstack/vue-virtual": "^3.13.18",
112
- "@tailwindcss/cli": "^4.1.18",
113
- "@tailwindcss/postcss": "^4.1.18",
114
- "@types/node": "^24.10.12",
115
- "@vitejs/plugin-vue": "^6.0.4",
116
- "@vue/runtime-core": "^3.5.27",
117
- "@vue/runtime-dom": "^3.5.27",
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.24",
120
+ "autoprefixer": "^10.4.27",
121
121
  "concurrently": "^9.2.1",
122
- "eslint": "^9.39.2",
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.3.1",
128
- "playwright": "^1.54.0",
129
- "playwright-core": "^1.54.0",
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.15",
131
+ "storybook": "^8.6.18",
132
132
  "storybook-dark-mode": "^4.0.2",
133
- "tailwindcss": "^4.1.18",
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.0",
139
- "vue": "^3.5.27",
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
 
@@ -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
- v-bind="{ ...$attrs, class: undefined }"
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
- max-h-[80dvh]
82
- top-[50%]
83
- left-[50%]
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
- max-w-[700px]
87
- max-sm:bottom-2
86
+ p-2
87
+ max-sm:bottom-0
88
88
  max-sm:top-[unset]
89
- max-sm:left-2
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-w-full
100
- max-h-full
98
+ max-h-[80dvh]
101
99
  top-notification
102
100
  text-md
103
101
  gap-2
@@ -97,7 +97,6 @@ export class NotificationHandler<
97
97
  requiresAction: false,
98
98
  options: ["Ok", "Cancel"],
99
99
  default: "Ok",
100
- cancellable: rawEntry.cancellable,
101
100
  ...rawEntry,
102
101
  component: rawEntry.component && typeof rawEntry.component !== "string" ? markRaw(rawEntry.component) : undefined,
103
102
  dangerous: rawEntry.dangerous ?? [],
@@ -218,18 +217,36 @@ export type RawNotificationEntry<
218
217
  options?: TOptions
219
218
  /** @default false */
220
219
  requiresAction?: boolean
220
+ /**
221
+ * 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.).
222
+ *
223
+ * This also enables cancelling via those secondary methods, otherwise the notification won't allow itself to be dismissed.
224
+ *
225
+ * @default undefined / false
226
+ */
221
227
  cancellable?: TCancellable
222
228
  /** @default "Ok" */
223
229
  default?: TOptions[number]
224
230
  /** @default [] */
225
231
  dangerous?: TOptions[number][]
226
- /** @default false if cancellable, otherwise the default timeout */
232
+ /**
233
+ * Overrides the default timeout, can be set to true to just enable it. An entry must be cancellable to have a timeout.
234
+ *
235
+ * @default global timeout / false if cancellable is false
236
+ */
227
237
  timeout?: number | boolean
228
238
  icon?: string
229
239
  message: string
230
240
  component?: string | Component
231
- /** By default the component is passed the message and the messageClasses. Both will be overriden if you set them on componentProps. */
241
+ /** Props for the custom component. By default the component is passed the message and the messageClasses. Both will be overriden if you set them on componentProps. */
232
242
  componentProps?: Record<string, any>
243
+ /**
244
+ * Props for the notification component itself. They are bound to the root of the element and the class property is merged with twMerge.
245
+ *
246
+ * 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.
247
+ *
248
+ */
249
+ notificationProps?: Record<string, any>
233
250
  }
234
251
 
235
252
  export type NotificationEntry<