react-snackbar-glass 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -6,13 +6,41 @@ import { ReactNode, CSSProperties } from 'react';
6
6
  * icon and accessible live-region behaviour.
7
7
  */
8
8
  type SnackbarVariant = 'neutral' | 'success' | 'error' | 'warning' | 'info' | 'loading' | 'custom';
9
- /** `glass` is the frosted default; `solid` paints the accent as the surface. */
10
- type SnackbarTone = 'glass' | 'solid';
9
+ /**
10
+ * Surface preset for a snackbar.
11
+ *
12
+ * - `glass` — frosted translucent default; the page shows through.
13
+ * - `solid` — the variant accent painted as the surface.
14
+ * - `paper` — opaque, matte, hairline border, no blur. Light/dark aware.
15
+ * - `graphite` — dark matte charcoal with light text, in both themes.
16
+ * - `neon` — near-black with an accent glow ring, in both themes.
17
+ */
18
+ type SnackbarTone = 'glass' | 'solid' | 'paper' | 'graphite' | 'neon';
11
19
  /**
12
20
  * Density and width of a snackbar. `md` is the default; `xs` is a compact
13
21
  * mini style, `lg` is an editorial width for richer content.
14
22
  */
15
23
  type SnackbarSize = 'xs' | 'sm' | 'md' | 'lg';
24
+ /**
25
+ * How much room a snackbar takes.
26
+ *
27
+ * - `card` — full card: title, message, action, countdown hairline.
28
+ * - `compact` — fully rounded single-line pill.
29
+ * - `inline` — message-only status line: content width, ~38px tall, never
30
+ * wraps and never shows a title or countdown.
31
+ */
32
+ type SnackbarLayout = 'card' | 'compact' | 'inline';
33
+ /**
34
+ * Enter/exit animation preset.
35
+ *
36
+ * - `slide` — spring slide from the edge with a soft blur (default).
37
+ * - `fade` — pure opacity cross-fade.
38
+ * - `scale` — zoom in/out from the center.
39
+ * - `pop` — bouncy overshoot.
40
+ * - `flip` — 3D flip on the X axis.
41
+ * - `none` — appears and disappears instantly.
42
+ */
43
+ type SnackbarAnimation = 'slide' | 'fade' | 'scale' | 'pop' | 'flip' | 'none';
16
44
  type SnackbarPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
17
45
  type SnackbarTheme = 'light' | 'dark' | 'auto';
18
46
  type SnackbarPhase = 'visible' | 'exiting';
@@ -62,9 +90,27 @@ interface SnackbarOptions {
62
90
  /**
63
91
  * Single-line pill: no title, no countdown hairline and tighter padding.
64
92
  * Ideal for high-frequency, low-stakes messages.
93
+ *
94
+ * Sugar for `layout: 'compact'`.
65
95
  * @default false
66
96
  */
67
97
  compact?: boolean;
98
+ /**
99
+ * How much room the snackbar takes. `compact: true` is sugar for
100
+ * `layout: 'compact'`; `toast.single()` uses `'inline'`.
101
+ * @default 'card'
102
+ */
103
+ layout?: SnackbarLayout;
104
+ /**
105
+ * Enter/exit animation preset. Applies to both phases unless
106
+ * `enterAnimation` / `exitAnimation` override it.
107
+ * @default 'slide'
108
+ */
109
+ animation?: SnackbarAnimation;
110
+ /** Enter animation for this snackbar only. */
111
+ enterAnimation?: SnackbarAnimation;
112
+ /** Exit animation for this snackbar only. */
113
+ exitAnimation?: SnackbarAnimation;
68
114
  /** @default 'glass' */
69
115
  tone?: SnackbarTone;
70
116
  /** @default 'md' */
@@ -91,6 +137,10 @@ interface SnackbarRecord {
91
137
  readonly dismissible: boolean;
92
138
  readonly progress: boolean;
93
139
  readonly compact: boolean;
140
+ readonly layout: SnackbarLayout;
141
+ readonly animation: SnackbarAnimation;
142
+ readonly enterAnimation: SnackbarAnimation;
143
+ readonly exitAnimation: SnackbarAnimation;
94
144
  readonly className: string | undefined;
95
145
  readonly style: CSSProperties | undefined;
96
146
  readonly createdAt: number;
@@ -111,6 +161,14 @@ interface SnackbarStoreConfig {
111
161
  progress?: boolean;
112
162
  /** Default `compact` value for new snackbars. @default false */
113
163
  compact?: boolean;
164
+ /** Default layout for new snackbars. @default 'card' */
165
+ layout?: SnackbarLayout;
166
+ /** Default enter/exit animation. @default 'slide' */
167
+ animation?: SnackbarAnimation;
168
+ /** Default enter animation; falls back to `animation`. */
169
+ enterAnimation?: SnackbarAnimation;
170
+ /** Default exit animation; falls back to `animation`. */
171
+ exitAnimation?: SnackbarAnimation;
114
172
  /** @default 'glass' */
115
173
  tone?: SnackbarTone;
116
174
  /** Default size for new snackbars. @default 'md' */
@@ -124,6 +182,10 @@ interface ResolvedSnackbarStoreConfig {
124
182
  dismissible: boolean;
125
183
  progress: boolean;
126
184
  compact: boolean;
185
+ layout: SnackbarLayout;
186
+ animation: SnackbarAnimation;
187
+ enterAnimation: SnackbarAnimation;
188
+ exitAnimation: SnackbarAnimation;
127
189
  tone: SnackbarTone;
128
190
  size: SnackbarSize;
129
191
  maxVisible: number;
@@ -162,6 +224,8 @@ interface SnackbarStore {
162
224
  setMinimized(minimized: boolean): void;
163
225
  }
164
226
  type SnackbarPresetOptions = Omit<SnackbarOptions, 'message' | 'variant'>;
227
+ /** `toast.single()` options: everything except the forced inline layout. */
228
+ type ToastSingleOptions = Omit<SnackbarOptions, 'message' | 'layout'>;
165
229
  interface SnackbarApi {
166
230
  /** Queue a fully customised snackbar and return its id. */
167
231
  show(options: SnackbarOptions): string;
@@ -175,6 +239,12 @@ interface SnackbarApi {
175
239
  neutral(message: ReactNode, options?: SnackbarPresetOptions): string;
176
240
  loading(message: ReactNode, options?: SnackbarPresetOptions): string;
177
241
  custom(message: ReactNode, options?: SnackbarPresetOptions): string;
242
+ /**
243
+ * Message-only status line (`layout: 'inline'`): content width, one line,
244
+ * no title and no countdown. Ideal for instant feedback such as
245
+ * “Position set to top-center”.
246
+ */
247
+ single(message: ReactNode, options?: ToastSingleOptions): string;
178
248
  promise<T>(promise: Promise<T>, messages: SnackbarPromiseOptions<T>, options?: SnackbarOptions): Promise<T>;
179
249
  /** Collapse the visible stack into one summary pill. */
180
250
  minimize(): void;
@@ -207,6 +277,12 @@ interface ToastApi {
207
277
  neutral(message: ReactNode, options?: ToastPresetOptions): string;
208
278
  loading(message: ReactNode, options?: ToastPresetOptions): string;
209
279
  custom(message: ReactNode, options?: ToastPresetOptions): string;
280
+ /**
281
+ * Message-only status line (`layout: 'inline'`): content width, one line,
282
+ * no title and no countdown. Ideal for instant feedback such as
283
+ * “Position set to top-center”.
284
+ */
285
+ single(message: ReactNode, options?: ToastSingleOptions): string;
210
286
  promise<T>(promise: Promise<T>, messages: SnackbarPromiseOptions<T>, options?: SnackbarOptions): Promise<T>;
211
287
  /** Collapse the visible stack into one summary pill. */
212
288
  minimize(): void;
@@ -269,6 +345,14 @@ interface SnackbarProviderProps extends Omit<SnackbarHostProps, 'store'> {
269
345
  progress?: boolean;
270
346
  /** Render every snackbar as a single-line pill. @default false */
271
347
  compact?: boolean;
348
+ /** Default layout for new snackbars. @default 'card' */
349
+ layout?: SnackbarLayout;
350
+ /** Default enter/exit animation. @default 'slide' */
351
+ animation?: SnackbarAnimation;
352
+ /** Default enter animation; falls back to `animation`. */
353
+ enterAnimation?: SnackbarAnimation;
354
+ /** Default exit animation; falls back to `animation`. */
355
+ exitAnimation?: SnackbarAnimation;
272
356
  /** @default 'glass' */
273
357
  tone?: SnackbarTone;
274
358
  /** Default size for new snackbars. @default 'md' */
@@ -293,7 +377,7 @@ declare function setDefaultStore(store: SnackbarStore | null): void;
293
377
 
294
378
  declare function SnackbarHost({ store, maxVisible, offset, gap, width, theme, container, pauseOnHover, pauseOnFocus, pauseOnDocumentHidden, swipeToDismiss, swipeThreshold, icons, closeIcon, closeLabel, regionLabel, minimizedLabel, className, style, zIndex, dir, }: SnackbarHostProps): react.ReactPortal | null;
295
379
 
296
- declare function SnackbarProvider({ children, store: providedStore, position, duration, dismissible, progress, compact, tone, size, maxVisible, ...hostProps }: SnackbarProviderProps): react.JSX.Element;
380
+ declare function SnackbarProvider({ children, store: providedStore, position, duration, dismissible, progress, compact, layout, animation, enterAnimation, exitAnimation, tone, size, maxVisible, ...hostProps }: SnackbarProviderProps): react.JSX.Element;
297
381
  /** Imperative API for showing and managing snackbars. */
298
382
  declare function useSnackbar(): SnackbarApi;
299
383
  /** Low-level store access for subscriptions and advanced integrations. */
@@ -313,4 +397,4 @@ declare function useSnackbarStore(): SnackbarStore;
313
397
  */
314
398
  declare const toast: ToastApi;
315
399
 
316
- export { type ResolvedSnackbarStoreConfig, type SnackbarAction, type SnackbarApi, type SnackbarCloseReason, SnackbarHost, type SnackbarHostProps, type SnackbarOptions, type SnackbarPhase, type SnackbarPosition, type SnackbarPromiseContent, type SnackbarPromiseOptions, SnackbarProvider, type SnackbarProviderProps, type SnackbarRecord, type SnackbarSize, type SnackbarStore, type SnackbarStoreConfig, type SnackbarTheme, type SnackbarTone, type SnackbarVariant, type ToastApi, type ToastPresetOptions, createSnackbarStore, getDefaultStore, setDefaultStore, toast, useSnackbar, useSnackbarStore };
400
+ export { type ResolvedSnackbarStoreConfig, type SnackbarAction, type SnackbarAnimation, type SnackbarApi, type SnackbarCloseReason, SnackbarHost, type SnackbarHostProps, type SnackbarLayout, type SnackbarOptions, type SnackbarPhase, type SnackbarPosition, type SnackbarPromiseContent, type SnackbarPromiseOptions, SnackbarProvider, type SnackbarProviderProps, type SnackbarRecord, type SnackbarSize, type SnackbarStore, type SnackbarStoreConfig, type SnackbarTheme, type SnackbarTone, type SnackbarVariant, type ToastApi, type ToastPresetOptions, type ToastSingleOptions, createSnackbarStore, getDefaultStore, setDefaultStore, toast, useSnackbar, useSnackbarStore };
package/dist/index.d.ts CHANGED
@@ -6,13 +6,41 @@ import { ReactNode, CSSProperties } from 'react';
6
6
  * icon and accessible live-region behaviour.
7
7
  */
8
8
  type SnackbarVariant = 'neutral' | 'success' | 'error' | 'warning' | 'info' | 'loading' | 'custom';
9
- /** `glass` is the frosted default; `solid` paints the accent as the surface. */
10
- type SnackbarTone = 'glass' | 'solid';
9
+ /**
10
+ * Surface preset for a snackbar.
11
+ *
12
+ * - `glass` — frosted translucent default; the page shows through.
13
+ * - `solid` — the variant accent painted as the surface.
14
+ * - `paper` — opaque, matte, hairline border, no blur. Light/dark aware.
15
+ * - `graphite` — dark matte charcoal with light text, in both themes.
16
+ * - `neon` — near-black with an accent glow ring, in both themes.
17
+ */
18
+ type SnackbarTone = 'glass' | 'solid' | 'paper' | 'graphite' | 'neon';
11
19
  /**
12
20
  * Density and width of a snackbar. `md` is the default; `xs` is a compact
13
21
  * mini style, `lg` is an editorial width for richer content.
14
22
  */
15
23
  type SnackbarSize = 'xs' | 'sm' | 'md' | 'lg';
24
+ /**
25
+ * How much room a snackbar takes.
26
+ *
27
+ * - `card` — full card: title, message, action, countdown hairline.
28
+ * - `compact` — fully rounded single-line pill.
29
+ * - `inline` — message-only status line: content width, ~38px tall, never
30
+ * wraps and never shows a title or countdown.
31
+ */
32
+ type SnackbarLayout = 'card' | 'compact' | 'inline';
33
+ /**
34
+ * Enter/exit animation preset.
35
+ *
36
+ * - `slide` — spring slide from the edge with a soft blur (default).
37
+ * - `fade` — pure opacity cross-fade.
38
+ * - `scale` — zoom in/out from the center.
39
+ * - `pop` — bouncy overshoot.
40
+ * - `flip` — 3D flip on the X axis.
41
+ * - `none` — appears and disappears instantly.
42
+ */
43
+ type SnackbarAnimation = 'slide' | 'fade' | 'scale' | 'pop' | 'flip' | 'none';
16
44
  type SnackbarPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
17
45
  type SnackbarTheme = 'light' | 'dark' | 'auto';
18
46
  type SnackbarPhase = 'visible' | 'exiting';
@@ -62,9 +90,27 @@ interface SnackbarOptions {
62
90
  /**
63
91
  * Single-line pill: no title, no countdown hairline and tighter padding.
64
92
  * Ideal for high-frequency, low-stakes messages.
93
+ *
94
+ * Sugar for `layout: 'compact'`.
65
95
  * @default false
66
96
  */
67
97
  compact?: boolean;
98
+ /**
99
+ * How much room the snackbar takes. `compact: true` is sugar for
100
+ * `layout: 'compact'`; `toast.single()` uses `'inline'`.
101
+ * @default 'card'
102
+ */
103
+ layout?: SnackbarLayout;
104
+ /**
105
+ * Enter/exit animation preset. Applies to both phases unless
106
+ * `enterAnimation` / `exitAnimation` override it.
107
+ * @default 'slide'
108
+ */
109
+ animation?: SnackbarAnimation;
110
+ /** Enter animation for this snackbar only. */
111
+ enterAnimation?: SnackbarAnimation;
112
+ /** Exit animation for this snackbar only. */
113
+ exitAnimation?: SnackbarAnimation;
68
114
  /** @default 'glass' */
69
115
  tone?: SnackbarTone;
70
116
  /** @default 'md' */
@@ -91,6 +137,10 @@ interface SnackbarRecord {
91
137
  readonly dismissible: boolean;
92
138
  readonly progress: boolean;
93
139
  readonly compact: boolean;
140
+ readonly layout: SnackbarLayout;
141
+ readonly animation: SnackbarAnimation;
142
+ readonly enterAnimation: SnackbarAnimation;
143
+ readonly exitAnimation: SnackbarAnimation;
94
144
  readonly className: string | undefined;
95
145
  readonly style: CSSProperties | undefined;
96
146
  readonly createdAt: number;
@@ -111,6 +161,14 @@ interface SnackbarStoreConfig {
111
161
  progress?: boolean;
112
162
  /** Default `compact` value for new snackbars. @default false */
113
163
  compact?: boolean;
164
+ /** Default layout for new snackbars. @default 'card' */
165
+ layout?: SnackbarLayout;
166
+ /** Default enter/exit animation. @default 'slide' */
167
+ animation?: SnackbarAnimation;
168
+ /** Default enter animation; falls back to `animation`. */
169
+ enterAnimation?: SnackbarAnimation;
170
+ /** Default exit animation; falls back to `animation`. */
171
+ exitAnimation?: SnackbarAnimation;
114
172
  /** @default 'glass' */
115
173
  tone?: SnackbarTone;
116
174
  /** Default size for new snackbars. @default 'md' */
@@ -124,6 +182,10 @@ interface ResolvedSnackbarStoreConfig {
124
182
  dismissible: boolean;
125
183
  progress: boolean;
126
184
  compact: boolean;
185
+ layout: SnackbarLayout;
186
+ animation: SnackbarAnimation;
187
+ enterAnimation: SnackbarAnimation;
188
+ exitAnimation: SnackbarAnimation;
127
189
  tone: SnackbarTone;
128
190
  size: SnackbarSize;
129
191
  maxVisible: number;
@@ -162,6 +224,8 @@ interface SnackbarStore {
162
224
  setMinimized(minimized: boolean): void;
163
225
  }
164
226
  type SnackbarPresetOptions = Omit<SnackbarOptions, 'message' | 'variant'>;
227
+ /** `toast.single()` options: everything except the forced inline layout. */
228
+ type ToastSingleOptions = Omit<SnackbarOptions, 'message' | 'layout'>;
165
229
  interface SnackbarApi {
166
230
  /** Queue a fully customised snackbar and return its id. */
167
231
  show(options: SnackbarOptions): string;
@@ -175,6 +239,12 @@ interface SnackbarApi {
175
239
  neutral(message: ReactNode, options?: SnackbarPresetOptions): string;
176
240
  loading(message: ReactNode, options?: SnackbarPresetOptions): string;
177
241
  custom(message: ReactNode, options?: SnackbarPresetOptions): string;
242
+ /**
243
+ * Message-only status line (`layout: 'inline'`): content width, one line,
244
+ * no title and no countdown. Ideal for instant feedback such as
245
+ * “Position set to top-center”.
246
+ */
247
+ single(message: ReactNode, options?: ToastSingleOptions): string;
178
248
  promise<T>(promise: Promise<T>, messages: SnackbarPromiseOptions<T>, options?: SnackbarOptions): Promise<T>;
179
249
  /** Collapse the visible stack into one summary pill. */
180
250
  minimize(): void;
@@ -207,6 +277,12 @@ interface ToastApi {
207
277
  neutral(message: ReactNode, options?: ToastPresetOptions): string;
208
278
  loading(message: ReactNode, options?: ToastPresetOptions): string;
209
279
  custom(message: ReactNode, options?: ToastPresetOptions): string;
280
+ /**
281
+ * Message-only status line (`layout: 'inline'`): content width, one line,
282
+ * no title and no countdown. Ideal for instant feedback such as
283
+ * “Position set to top-center”.
284
+ */
285
+ single(message: ReactNode, options?: ToastSingleOptions): string;
210
286
  promise<T>(promise: Promise<T>, messages: SnackbarPromiseOptions<T>, options?: SnackbarOptions): Promise<T>;
211
287
  /** Collapse the visible stack into one summary pill. */
212
288
  minimize(): void;
@@ -269,6 +345,14 @@ interface SnackbarProviderProps extends Omit<SnackbarHostProps, 'store'> {
269
345
  progress?: boolean;
270
346
  /** Render every snackbar as a single-line pill. @default false */
271
347
  compact?: boolean;
348
+ /** Default layout for new snackbars. @default 'card' */
349
+ layout?: SnackbarLayout;
350
+ /** Default enter/exit animation. @default 'slide' */
351
+ animation?: SnackbarAnimation;
352
+ /** Default enter animation; falls back to `animation`. */
353
+ enterAnimation?: SnackbarAnimation;
354
+ /** Default exit animation; falls back to `animation`. */
355
+ exitAnimation?: SnackbarAnimation;
272
356
  /** @default 'glass' */
273
357
  tone?: SnackbarTone;
274
358
  /** Default size for new snackbars. @default 'md' */
@@ -293,7 +377,7 @@ declare function setDefaultStore(store: SnackbarStore | null): void;
293
377
 
294
378
  declare function SnackbarHost({ store, maxVisible, offset, gap, width, theme, container, pauseOnHover, pauseOnFocus, pauseOnDocumentHidden, swipeToDismiss, swipeThreshold, icons, closeIcon, closeLabel, regionLabel, minimizedLabel, className, style, zIndex, dir, }: SnackbarHostProps): react.ReactPortal | null;
295
379
 
296
- declare function SnackbarProvider({ children, store: providedStore, position, duration, dismissible, progress, compact, tone, size, maxVisible, ...hostProps }: SnackbarProviderProps): react.JSX.Element;
380
+ declare function SnackbarProvider({ children, store: providedStore, position, duration, dismissible, progress, compact, layout, animation, enterAnimation, exitAnimation, tone, size, maxVisible, ...hostProps }: SnackbarProviderProps): react.JSX.Element;
297
381
  /** Imperative API for showing and managing snackbars. */
298
382
  declare function useSnackbar(): SnackbarApi;
299
383
  /** Low-level store access for subscriptions and advanced integrations. */
@@ -313,4 +397,4 @@ declare function useSnackbarStore(): SnackbarStore;
313
397
  */
314
398
  declare const toast: ToastApi;
315
399
 
316
- export { type ResolvedSnackbarStoreConfig, type SnackbarAction, type SnackbarApi, type SnackbarCloseReason, SnackbarHost, type SnackbarHostProps, type SnackbarOptions, type SnackbarPhase, type SnackbarPosition, type SnackbarPromiseContent, type SnackbarPromiseOptions, SnackbarProvider, type SnackbarProviderProps, type SnackbarRecord, type SnackbarSize, type SnackbarStore, type SnackbarStoreConfig, type SnackbarTheme, type SnackbarTone, type SnackbarVariant, type ToastApi, type ToastPresetOptions, createSnackbarStore, getDefaultStore, setDefaultStore, toast, useSnackbar, useSnackbarStore };
400
+ export { type ResolvedSnackbarStoreConfig, type SnackbarAction, type SnackbarAnimation, type SnackbarApi, type SnackbarCloseReason, SnackbarHost, type SnackbarHostProps, type SnackbarLayout, type SnackbarOptions, type SnackbarPhase, type SnackbarPosition, type SnackbarPromiseContent, type SnackbarPromiseOptions, SnackbarProvider, type SnackbarProviderProps, type SnackbarRecord, type SnackbarSize, type SnackbarStore, type SnackbarStoreConfig, type SnackbarTheme, type SnackbarTone, type SnackbarVariant, type ToastApi, type ToastPresetOptions, type ToastSingleOptions, createSnackbarStore, getDefaultStore, setDefaultStore, toast, useSnackbar, useSnackbarStore };
package/dist/index.js CHANGED
@@ -9,7 +9,10 @@ var DEFAULT_CONFIG = {
9
9
  duration: 5e3,
10
10
  dismissible: true,
11
11
  progress: true,
12
- compact: false,
12
+ layout: "card",
13
+ animation: "slide",
14
+ enterAnimation: "slide",
15
+ exitAnimation: "slide",
13
16
  tone: "glass",
14
17
  size: "md",
15
18
  maxVisible: 3
@@ -37,23 +40,38 @@ function resolveContent(content, value) {
37
40
  const resolved = typeof content === "function" ? content(value) : content;
38
41
  return contentToOptions(resolved);
39
42
  }
40
- function createSnackbarStore(initialConfig = {}) {
41
- let config = {
42
- ...DEFAULT_CONFIG,
43
- ...initialConfig.position !== void 0 ? { position: initialConfig.position } : null,
44
- ...initialConfig.duration !== void 0 ? {
45
- duration: normalizeDuration(
46
- initialConfig.duration,
47
- DEFAULT_CONFIG.duration
48
- )
49
- } : null,
50
- ...initialConfig.dismissible !== void 0 ? { dismissible: initialConfig.dismissible } : null,
51
- ...initialConfig.progress !== void 0 ? { progress: initialConfig.progress } : null,
52
- ...initialConfig.compact !== void 0 ? { compact: initialConfig.compact } : null,
53
- ...initialConfig.tone !== void 0 ? { tone: initialConfig.tone } : null,
54
- ...initialConfig.size !== void 0 ? { size: initialConfig.size } : null,
55
- ...initialConfig.maxVisible !== void 0 ? { maxVisible: Math.max(1, Math.floor(initialConfig.maxVisible)) } : null
43
+ function resolveLayout(layout, compact, fallback) {
44
+ if (layout !== void 0) return layout;
45
+ if (compact !== void 0) return compact ? "compact" : "card";
46
+ return fallback;
47
+ }
48
+ function resolveLayoutPatch(record, options) {
49
+ if (options.layout === void 0 && options.compact === void 0) return {};
50
+ const layout = resolveLayout(options.layout, options.compact, record.layout);
51
+ return { layout, compact: layout === "compact" };
52
+ }
53
+ function mergeConfig(previous, patch) {
54
+ const layout = resolveLayout(patch.layout, patch.compact, previous.layout);
55
+ return {
56
+ position: patch.position ?? previous.position,
57
+ duration: patch.duration !== void 0 ? normalizeDuration(patch.duration, previous.duration) : previous.duration,
58
+ dismissible: patch.dismissible ?? previous.dismissible,
59
+ progress: patch.progress ?? previous.progress,
60
+ compact: layout === "compact",
61
+ layout,
62
+ animation: patch.animation ?? previous.animation,
63
+ enterAnimation: patch.enterAnimation ?? patch.animation ?? previous.enterAnimation,
64
+ exitAnimation: patch.exitAnimation ?? patch.animation ?? previous.exitAnimation,
65
+ tone: patch.tone ?? previous.tone,
66
+ size: patch.size ?? previous.size,
67
+ maxVisible: patch.maxVisible !== void 0 ? Math.max(1, Math.floor(patch.maxVisible)) : previous.maxVisible
56
68
  };
69
+ }
70
+ function createSnackbarStore(initialConfig = {}) {
71
+ let config = mergeConfig(
72
+ DEFAULT_CONFIG,
73
+ initialConfig
74
+ );
57
75
  let records = EMPTY;
58
76
  const listeners = /* @__PURE__ */ new Set();
59
77
  const timers = /* @__PURE__ */ new Map();
@@ -221,6 +239,7 @@ function createSnackbarStore(initialConfig = {}) {
221
239
  }
222
240
  return id;
223
241
  }
242
+ const layout = resolveLayout(options.layout, options.compact, config.layout);
224
243
  const record = {
225
244
  id,
226
245
  title: options.title,
@@ -234,7 +253,11 @@ function createSnackbarStore(initialConfig = {}) {
234
253
  action: options.action ?? null,
235
254
  dismissible: options.dismissible ?? config.dismissible,
236
255
  progress: options.progress ?? config.progress,
237
- compact: options.compact ?? config.compact,
256
+ compact: layout === "compact",
257
+ layout,
258
+ animation: options.animation ?? config.animation,
259
+ enterAnimation: options.enterAnimation ?? options.animation ?? config.enterAnimation,
260
+ exitAnimation: options.exitAnimation ?? options.animation ?? config.exitAnimation,
238
261
  className: options.className,
239
262
  style: options.style,
240
263
  createdAt: Date.now(),
@@ -263,7 +286,14 @@ function createSnackbarStore(initialConfig = {}) {
263
286
  ...options.action !== void 0 ? { action: options.action } : null,
264
287
  ...options.dismissible !== void 0 ? { dismissible: options.dismissible } : null,
265
288
  ...options.progress !== void 0 ? { progress: options.progress } : null,
266
- ...options.compact !== void 0 ? { compact: options.compact } : null,
289
+ ...resolveLayoutPatch(record, options),
290
+ ...options.animation !== void 0 ? {
291
+ animation: options.animation,
292
+ enterAnimation: options.animation,
293
+ exitAnimation: options.animation
294
+ } : null,
295
+ ...options.enterAnimation !== void 0 ? { enterAnimation: options.enterAnimation } : null,
296
+ ...options.exitAnimation !== void 0 ? { exitAnimation: options.exitAnimation } : null,
267
297
  ...options.className !== void 0 ? { className: options.className } : null,
268
298
  ...options.style !== void 0 ? { style: options.style } : null,
269
299
  ...options.onOpen !== void 0 ? { onOpen: options.onOpen } : null,
@@ -313,19 +343,7 @@ function createSnackbarStore(initialConfig = {}) {
313
343
  }
314
344
  };
315
345
  const setConfig = (patch) => {
316
- config = {
317
- ...config,
318
- ...patch.position !== void 0 ? { position: patch.position } : null,
319
- ...patch.duration !== void 0 ? {
320
- duration: normalizeDuration(patch.duration, config.duration)
321
- } : null,
322
- ...patch.dismissible !== void 0 ? { dismissible: patch.dismissible } : null,
323
- ...patch.progress !== void 0 ? { progress: patch.progress } : null,
324
- ...patch.compact !== void 0 ? { compact: patch.compact } : null,
325
- ...patch.tone !== void 0 ? { tone: patch.tone } : null,
326
- ...patch.size !== void 0 ? { size: patch.size } : null,
327
- ...patch.maxVisible !== void 0 ? { maxVisible: Math.max(1, Math.floor(patch.maxVisible)) } : null
328
- };
346
+ config = mergeConfig(config, patch);
329
347
  };
330
348
  const promise = (input, messages, options = {}) => {
331
349
  const loadingOptions = contentToOptions(messages.loading ?? "Loading\u2026");
@@ -628,7 +646,10 @@ function SnackbarItem({
628
646
  };
629
647
  const resolvedIcon = record.icon === void 0 ? icons?.[variant] ?? defaultIcons[variant] : record.icon;
630
648
  const showIcon = record.icon !== false;
631
- const showProgress = !record.compact && record.progress && Number.isFinite(duration) && duration > 0;
649
+ const isInline = record.layout === "inline";
650
+ const isTimed = Number.isFinite(duration) && duration > 0;
651
+ const showProgress = record.layout === "card" && record.progress && isTimed;
652
+ const showClose = record.dismissible && (!isInline || !isTimed);
632
653
  const style = {
633
654
  ...record.style,
634
655
  "--prs-drag-x": `${dragX}px`,
@@ -649,6 +670,9 @@ function SnackbarItem({
649
670
  "data-has-icon": showIcon ? "true" : "false",
650
671
  "data-dismissible": record.dismissible ? "true" : "false",
651
672
  "data-compact": record.compact ? "true" : "false",
673
+ "data-layout": record.layout,
674
+ "data-enter": record.enterAnimation,
675
+ "data-exit": record.exitAnimation,
652
676
  "data-prs-id": record.id,
653
677
  "data-position": record.position,
654
678
  style,
@@ -697,7 +721,7 @@ function SnackbarItem({
697
721
  className: "prs-item__content",
698
722
  "data-has-title": title !== void 0 && title !== null ? "true" : "false",
699
723
  children: [
700
- title !== void 0 && title !== null ? /* @__PURE__ */ jsx("div", { className: "prs-item__title", children: title }) : null,
724
+ title !== void 0 && title !== null && !isInline ? /* @__PURE__ */ jsx("div", { className: "prs-item__title", children: title }) : null,
701
725
  message !== void 0 && message !== null ? /* @__PURE__ */ jsx("div", { className: "prs-item__message", children: message }) : null,
702
726
  action ? /* @__PURE__ */ jsx("div", { className: "prs-item__actions", children: /* @__PURE__ */ jsxs(
703
727
  "button",
@@ -716,7 +740,7 @@ function SnackbarItem({
716
740
  ]
717
741
  }
718
742
  ),
719
- record.dismissible ? /* @__PURE__ */ jsx(
743
+ showClose ? /* @__PURE__ */ jsx(
720
744
  "button",
721
745
  {
722
746
  type: "button",
@@ -936,6 +960,10 @@ function SnackbarProvider({
936
960
  dismissible,
937
961
  progress,
938
962
  compact,
963
+ layout,
964
+ animation,
965
+ enterAnimation,
966
+ exitAnimation,
939
967
  tone,
940
968
  size,
941
969
  maxVisible,
@@ -958,6 +986,10 @@ function SnackbarProvider({
958
986
  dismissible,
959
987
  progress,
960
988
  compact,
989
+ layout,
990
+ animation,
991
+ enterAnimation,
992
+ exitAnimation,
961
993
  tone,
962
994
  size,
963
995
  maxVisible
@@ -969,6 +1001,10 @@ function SnackbarProvider({
969
1001
  dismissible,
970
1002
  progress,
971
1003
  compact,
1004
+ layout,
1005
+ animation,
1006
+ enterAnimation,
1007
+ exitAnimation,
972
1008
  tone,
973
1009
  size,
974
1010
  maxVisible
@@ -987,6 +1023,7 @@ function SnackbarProvider({
987
1023
  info: preset2("info"),
988
1024
  neutral: preset2("neutral"),
989
1025
  custom: preset2("custom"),
1026
+ single: (message, options = {}) => store.show({ ...options, message, layout: "inline" }),
990
1027
  loading: (message, options = {}) => store.show({
991
1028
  ...options,
992
1029
  message,
@@ -1053,6 +1090,7 @@ function createToast() {
1053
1090
  toast2.info = preset("info");
1054
1091
  toast2.neutral = preset("neutral");
1055
1092
  toast2.custom = preset("custom");
1093
+ toast2.single = (message, options = {}) => getDefaultStore().show({ ...options, message, layout: "inline" });
1056
1094
  toast2.loading = (message, options = {}) => getDefaultStore().show({
1057
1095
  ...options,
1058
1096
  message,