varsel 0.5.1 → 0.5.4

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.
Files changed (50) hide show
  1. package/dist/VarselItem.svelte +900 -0
  2. package/dist/VarselItem.svelte.d.ts +23 -0
  3. package/dist/VarselItem.svelte.d.ts.map +1 -0
  4. package/dist/VarselManager.svelte +451 -0
  5. package/dist/VarselManager.svelte.d.ts +18 -0
  6. package/dist/VarselManager.svelte.d.ts.map +1 -0
  7. package/dist/VarselToaster.svelte +104 -0
  8. package/dist/VarselToaster.svelte.d.ts +32 -0
  9. package/dist/VarselToaster.svelte.d.ts.map +1 -0
  10. package/dist/core/accessibility.d.ts +6 -0
  11. package/dist/core/accessibility.d.ts.map +1 -0
  12. package/dist/core/accessibility.js +12 -0
  13. package/dist/core/animations.d.ts +29 -0
  14. package/dist/core/animations.d.ts.map +1 -0
  15. package/dist/core/animations.js +28 -0
  16. package/dist/core/positions.d.ts +71 -0
  17. package/dist/core/positions.d.ts.map +1 -0
  18. package/dist/core/positions.js +30 -0
  19. package/dist/core/swipe.d.ts +20 -0
  20. package/dist/core/swipe.d.ts.map +1 -0
  21. package/dist/core/swipe.js +30 -0
  22. package/dist/core/toast-factory.d.ts +3 -0
  23. package/dist/core/toast-factory.d.ts.map +1 -0
  24. package/dist/core/toast-factory.js +144 -0
  25. package/dist/core/toast-state.d.ts +49 -0
  26. package/dist/core/toast-state.d.ts.map +1 -0
  27. package/dist/core/toast-state.js +80 -0
  28. package/dist/core/toaster-instances.d.ts +28 -0
  29. package/dist/core/toaster-instances.d.ts.map +1 -0
  30. package/dist/core/toaster-instances.js +46 -0
  31. package/dist/core/types.d.ts +144 -0
  32. package/dist/core/types.d.ts.map +1 -0
  33. package/dist/core/types.js +1 -0
  34. package/dist/core/utils.d.ts +10 -0
  35. package/dist/core/utils.d.ts.map +1 -0
  36. package/dist/core/utils.js +9 -0
  37. package/dist/core/variants.d.ts +18 -0
  38. package/dist/core/variants.d.ts.map +1 -0
  39. package/dist/core/variants.js +56 -0
  40. package/dist/index.d.ts +10 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +8 -0
  43. package/dist/internals.d.ts +16 -0
  44. package/dist/internals.d.ts.map +1 -0
  45. package/dist/internals.js +14 -0
  46. package/dist/styles.css +195 -0
  47. package/dist/variant-icons.d.ts +108 -0
  48. package/dist/variant-icons.d.ts.map +1 -0
  49. package/dist/variant-icons.js +45 -0
  50. package/package.json +7 -4
@@ -0,0 +1,23 @@
1
+ import { type PositionedToast } from "./internals";
2
+ type $$ComponentProps = {
3
+ toast: PositionedToast;
4
+ onRemove: (id: string) => void;
5
+ isGroupHovered?: boolean;
6
+ expandedOffset?: number;
7
+ expandedGap?: number;
8
+ collapsedOffset?: number;
9
+ hiddenCollapsedOffset?: number;
10
+ onHeightChange?: (id: string, height: number) => void;
11
+ onGroupHoverEnter?: () => void;
12
+ onGroupHoldChange?: (holding: boolean) => void;
13
+ defaultDuration?: number;
14
+ defaultShowClose?: boolean;
15
+ pauseOnHover?: boolean;
16
+ offset?: number | string;
17
+ expand?: boolean;
18
+ visibleToasts?: number;
19
+ };
20
+ declare const VarselItem: import("svelte").Component<$$ComponentProps, {}, "">;
21
+ type VarselItem = ReturnType<typeof VarselItem>;
22
+ export default VarselItem;
23
+ //# sourceMappingURL=VarselItem.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VarselItem.svelte.d.ts","sourceRoot":"","sources":["../src/lib/VarselItem.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,EAYN,KAAK,eAAe,EAIpB,MAAM,aAAa,CAAC;AAUpB,KAAK,gBAAgB,GAAI;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAywBF,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -0,0 +1,451 @@
1
+ <script lang="ts">
2
+ /**
3
+ * @component
4
+ * @description
5
+ * Internal component responsible for grouping toasts by position and calculating
6
+ * their stacking offsets (both collapsed and expanded).
7
+ * It handles the "hover to expand" logic and manages the lifecycle of toast groups.
8
+ */
9
+ import VarselItem from "./VarselItem.svelte";
10
+ import {
11
+ ANIMATION_CONFIG,
12
+ type PositionedToast,
13
+ type ToastData,
14
+ type ToastPosition,
15
+ } from "./internals";
16
+
17
+ let {
18
+ toasts = [],
19
+ onRemove,
20
+ expandedGap = ANIMATION_CONFIG.EXPANDED_GAP,
21
+ position: defaultPosition = 'bottom-center',
22
+ visibleToasts = 3,
23
+ expand = true,
24
+ duration = 5000,
25
+ closeButton = true,
26
+ pauseOnHover = true,
27
+ offset = undefined,
28
+ dir = 'auto'
29
+ }: {
30
+ toasts?: ToastData[];
31
+ onRemove: (id: string) => void;
32
+ expandedGap?: number;
33
+ position?: ToastPosition;
34
+ visibleToasts?: number;
35
+ expand?: boolean;
36
+ duration?: number;
37
+ closeButton?: boolean;
38
+ pauseOnHover?: boolean;
39
+ offset?: number | string;
40
+ dir?: 'ltr' | 'rtl' | 'auto';
41
+ } = $props();
42
+
43
+ const createPositionMap = <T>(value: () => T): Record<ToastPosition, T> => ({
44
+ "top-left": value(),
45
+ "top-center": value(),
46
+ "top-right": value(),
47
+ "bottom-left": value(),
48
+ "bottom-center": value(),
49
+ "bottom-right": value(),
50
+ });
51
+
52
+ let heights = $state<Record<string, number>>({});
53
+ let hovered = $state<Record<ToastPosition, boolean>>(
54
+ createPositionMap(() => false),
55
+ );
56
+ let heldToasts = $state<Record<ToastPosition, Set<string>>>(
57
+ createPositionMap(() => new Set<string>()),
58
+ );
59
+
60
+ // Non-reactive internal state for "previous" values (mimicking legacy behavior)
61
+ let previousStackIndex: Record<string, number> = {};
62
+ let previousCollapsedOffsets: Record<string, number> = {};
63
+ let previousExpandedOffsets: Record<string, number> = {};
64
+
65
+ let toastsByPosition = $state<Record<ToastPosition, PositionedToast[]>>(
66
+ createPositionMap<PositionedToast[]>(() => []),
67
+ );
68
+
69
+ let collapsedOffsetData = $state<{
70
+ byPosition: Record<ToastPosition, number[]>;
71
+ byId: Record<string, number>;
72
+ }>({ byPosition: createPositionMap<number[]>(() => []), byId: {} });
73
+
74
+ let expandedOffsetData = $state<{
75
+ byPosition: Record<ToastPosition, number[]>;
76
+ byId: Record<string, number>;
77
+ }>({ byPosition: createPositionMap<number[]>(() => []), byId: {} });
78
+
79
+ let positionEntries = $derived(
80
+ Object.entries(toastsByPosition) as [ToastPosition, PositionedToast[]][],
81
+ );
82
+ let latestPositionEntries = $derived(positionEntries);
83
+ let latestHovered = $derived(hovered);
84
+
85
+ const updateHoldState = (
86
+ position: ToastPosition,
87
+ toastId: string,
88
+ isHolding: boolean,
89
+ ) => {
90
+ const current = heldToasts[position] ?? new Set<string>();
91
+ const next = new Set(current);
92
+ if (isHolding) {
93
+ next.add(toastId);
94
+ } else {
95
+ next.delete(toastId);
96
+ }
97
+ if (next.size !== current.size) {
98
+ heldToasts = { ...heldToasts, [position]: next };
99
+ }
100
+ };
101
+
102
+ // Calculate toastsByPosition based on toasts
103
+ $effect(() => {
104
+ const grouped = createPositionMap<ToastData[]>(() => []);
105
+ for (const toast of toasts) {
106
+ const pos = toast.position || defaultPosition;
107
+ grouped[pos].push(toast);
108
+ }
109
+
110
+ const nextStackIndices: Record<string, number> = {};
111
+ const positioned = createPositionMap<PositionedToast[]>(() => []);
112
+
113
+ for (const position of Object.keys(grouped) as ToastPosition[]) {
114
+ const list = grouped[position];
115
+ const activeToasts = list.filter(
116
+ (toast) => !toast.isLeaving && !toast.shouldClose,
117
+ );
118
+ const activeIndexMap = new Map<string, number>();
119
+ activeToasts.forEach((toast, activeIndex) => {
120
+ activeIndexMap.set(toast.id, activeIndex);
121
+ });
122
+
123
+ positioned[position] = list.map((toast, orderIndex) => {
124
+ let stackIndex =
125
+ activeIndexMap.get(toast.id) ?? previousStackIndex[toast.id];
126
+ if (stackIndex == null || Number.isNaN(stackIndex)) {
127
+ stackIndex = orderIndex;
128
+ }
129
+
130
+ nextStackIndices[toast.id] = stackIndex;
131
+
132
+ return {
133
+ ...toast,
134
+ position: position,
135
+ index: stackIndex,
136
+ renderIndex: orderIndex,
137
+ total: list.length,
138
+ };
139
+ }) as PositionedToast[];
140
+ }
141
+
142
+ previousStackIndex = nextStackIndices;
143
+ toastsByPosition = positioned;
144
+ });
145
+
146
+ // Update hovered state based on empty groups
147
+ $effect(() => {
148
+ const next = { ...hovered };
149
+ let changed = false;
150
+ for (const pos of Object.keys(hovered) as ToastPosition[]) {
151
+ const hasToast = (toastsByPosition[pos]?.length ?? 0) > 0;
152
+ if (!hasToast && next[pos]) {
153
+ next[pos] = false;
154
+ changed = true;
155
+ }
156
+ }
157
+ if (changed) {
158
+ hovered = next;
159
+ }
160
+ });
161
+
162
+ // Calculate collapsedOffsetData
163
+ $effect(() => {
164
+ const byPosition = createPositionMap<number[]>(() => []);
165
+ const byId: Record<string, number> = {};
166
+
167
+ for (const [pos, group] of positionEntries) {
168
+ const isTopPosition = pos.startsWith("top-");
169
+ const activeToasts = group.filter((toast) => !toast.shouldClose);
170
+ const offsetsForActive: number[] = [];
171
+
172
+ for (let i = 0; i < activeToasts.length; i++) {
173
+ if (i === 0) {
174
+ offsetsForActive.push(0);
175
+ continue;
176
+ }
177
+
178
+ const prevToast = activeToasts[i - 1];
179
+ const currentToast = activeToasts[i];
180
+ const prevOffset = offsetsForActive[i - 1] ?? 0;
181
+ if (!prevToast || !currentToast) {
182
+ offsetsForActive.push(prevOffset);
183
+ continue;
184
+ }
185
+ const prevHeight = heights[prevToast.id];
186
+ const currentHeight = heights[currentToast.id];
187
+ const fallbackOffset =
188
+ prevOffset + (isTopPosition ? 1 : -1) * ANIMATION_CONFIG.STACK_OFFSET;
189
+
190
+ if (
191
+ prevHeight == null ||
192
+ currentHeight == null ||
193
+ Number.isNaN(prevHeight) ||
194
+ Number.isNaN(currentHeight)
195
+ ) {
196
+ offsetsForActive.push(fallbackOffset);
197
+ continue;
198
+ }
199
+
200
+ if (isTopPosition) {
201
+ offsetsForActive.push(
202
+ prevOffset +
203
+ (prevHeight - currentHeight + ANIMATION_CONFIG.STACK_OFFSET),
204
+ );
205
+ } else {
206
+ offsetsForActive.push(
207
+ prevOffset +
208
+ (currentHeight - prevHeight - ANIMATION_CONFIG.STACK_OFFSET),
209
+ );
210
+ }
211
+ }
212
+
213
+ for (let i = 0; i < activeToasts.length; i++) {
214
+ const toast = activeToasts[i];
215
+ if (!toast) continue;
216
+ byId[toast.id] = offsetsForActive[i] ?? 0;
217
+ }
218
+
219
+ for (const toast of group) {
220
+ if (byId[toast.id] != null) continue;
221
+ const previousOffset = previousCollapsedOffsets[toast.id];
222
+ if (typeof previousOffset === "number") {
223
+ byId[toast.id] = previousOffset;
224
+ continue;
225
+ }
226
+
227
+ const defaultOffset = isTopPosition
228
+ ? toast.index * ANIMATION_CONFIG.STACK_OFFSET
229
+ : -(toast.index * ANIMATION_CONFIG.STACK_OFFSET);
230
+ byId[toast.id] = defaultOffset;
231
+ }
232
+
233
+ byPosition[pos] = group.map((toast) => byId[toast.id] ?? 0);
234
+ }
235
+
236
+ previousCollapsedOffsets = byId;
237
+ collapsedOffsetData = { byPosition, byId };
238
+ });
239
+
240
+ // Calculate expandedOffsetData
241
+ $effect(() => {
242
+ const byPosition = createPositionMap<number[]>(() => []);
243
+ const byId: Record<string, number> = {};
244
+
245
+ for (const [pos, group] of positionEntries) {
246
+ const offsets: number[] = [];
247
+ const activeToasts = group.filter((toast) => !toast.shouldClose);
248
+ let acc = 0;
249
+
250
+ for (let i = 0; i < activeToasts.length; i++) {
251
+ if (i === 0) {
252
+ offsets.push(0);
253
+ continue;
254
+ }
255
+ const prevToast = activeToasts[i - 1];
256
+ const prevHeight = prevToast ? (heights[prevToast.id] ?? 0) : 0;
257
+ acc += prevHeight + expandedGap;
258
+ offsets.push(acc);
259
+ }
260
+
261
+ for (let i = 0; i < activeToasts.length; i++) {
262
+ const toast = activeToasts[i];
263
+ if (!toast) continue;
264
+ byId[toast.id] = offsets[i] ?? 0;
265
+ }
266
+
267
+ for (const toast of group) {
268
+ if (byId[toast.id] != null) continue;
269
+
270
+ const previousOffset = previousExpandedOffsets[toast.id];
271
+ if (typeof previousOffset === "number") {
272
+ byId[toast.id] = previousOffset;
273
+ continue;
274
+ }
275
+
276
+ let fallback = 0;
277
+ for (const candidate of group) {
278
+ if (candidate.id === toast.id) break;
279
+ const height = heights[candidate.id] ?? 0;
280
+ fallback += height + expandedGap;
281
+ }
282
+ byId[toast.id] = fallback;
283
+ }
284
+
285
+ byPosition[pos] = group.map((toast) => byId[toast.id] ?? 0);
286
+ }
287
+
288
+ previousExpandedOffsets = byId;
289
+ expandedOffsetData = { byPosition, byId };
290
+ });
291
+
292
+ $effect(() => {
293
+ let hoverFrameId: number | null = null;
294
+ let pointerX = 0;
295
+ let pointerY = 0;
296
+
297
+ const updateHoverState = (x: number, y: number) => {
298
+ if (latestPositionEntries.length === 0) return;
299
+ const next: Record<ToastPosition, boolean> = {
300
+ ...latestHovered,
301
+ };
302
+ for (const [pos, group] of latestPositionEntries) {
303
+ let top = Number.POSITIVE_INFINITY;
304
+ let left = Number.POSITIVE_INFINITY;
305
+ let right = Number.NEGATIVE_INFINITY;
306
+ let bottom = Number.NEGATIVE_INFINITY;
307
+ let any = false;
308
+ for (const t of group) {
309
+ if (t.index >= visibleToasts) continue;
310
+ const el = document.querySelector(
311
+ `[data-toast-id="${t.id}"]`,
312
+ ) as HTMLElement | null;
313
+ if (!el) continue;
314
+ const rect = el.getBoundingClientRect();
315
+ top = Math.min(top, rect.top);
316
+ left = Math.min(left, rect.left);
317
+ right = Math.max(right, rect.right);
318
+ bottom = Math.max(bottom, rect.bottom);
319
+ any = true;
320
+ }
321
+
322
+ if (!any) {
323
+ next[pos] = false;
324
+ continue;
325
+ }
326
+
327
+ const inside = x >= left && x <= right && y >= top && y <= bottom;
328
+ next[pos] = inside;
329
+ }
330
+
331
+ const changed = (Object.keys(next) as ToastPosition[]).some(
332
+ (key) => next[key] !== hovered[key],
333
+ );
334
+ if (changed) {
335
+ hovered = next;
336
+ }
337
+ };
338
+
339
+ const flushHoverUpdate = () => {
340
+ hoverFrameId = null;
341
+ updateHoverState(pointerX, pointerY);
342
+ };
343
+
344
+ const handleMouseMove = (event: MouseEvent) => {
345
+ pointerX = event.clientX;
346
+ pointerY = event.clientY;
347
+ if (hoverFrameId == null) {
348
+ hoverFrameId = requestAnimationFrame(flushHoverUpdate);
349
+ }
350
+ };
351
+
352
+ const handleKeyDown = (event: KeyboardEvent) => {
353
+ if (event.key !== "Escape") return;
354
+ for (const [, group] of latestPositionEntries) {
355
+ const latestToast = group?.[0];
356
+ if (!latestToast) continue;
357
+ const container = document.querySelector(
358
+ `[data-toast-id="${latestToast.id}"]`,
359
+ ) as HTMLElement | null;
360
+ if (!container) continue;
361
+ const active = document.activeElement as HTMLElement | null;
362
+ if (active && container.contains(active)) {
363
+ const closeBtn = container.querySelector(
364
+ '[aria-label="Close toast"]',
365
+ ) as HTMLButtonElement | null;
366
+ if (closeBtn) {
367
+ event.preventDefault();
368
+ closeBtn.click();
369
+ }
370
+ }
371
+ }
372
+ };
373
+
374
+ document.addEventListener("mousemove", handleMouseMove);
375
+ document.addEventListener("keydown", handleKeyDown);
376
+ return () => {
377
+ if (hoverFrameId != null) {
378
+ cancelAnimationFrame(hoverFrameId);
379
+ hoverFrameId = null;
380
+ }
381
+ document.removeEventListener("mousemove", handleMouseMove);
382
+ document.removeEventListener("keydown", handleKeyDown);
383
+ };
384
+ });
385
+
386
+ const handleHeightChange = (id: string, height: number) => {
387
+ if (heights[id] === height) return;
388
+ heights = { ...heights, [id]: height };
389
+ };
390
+ </script>
391
+
392
+ {#if toasts.length > 0}
393
+ <div
394
+ class="pointer-events-none fixed inset-0 z-50"
395
+ {dir}
396
+ >
397
+ {#each positionEntries as [position, positionToasts]}
398
+ {@const pos = position}
399
+ {@const expandedOffsets = expandedOffsetData.byPosition[pos]}
400
+ {@const collapsedOffsets = collapsedOffsetData.byPosition[pos]}
401
+ {@const isHovered = hovered[pos]}
402
+ {@const isHeld = (heldToasts[pos]?.size ?? 0) > 0}
403
+ {@const isGroupActive = isHovered || isHeld}
404
+ {@const activeToasts = positionToasts.filter((toast) => !toast.shouldClose)}
405
+ {@const visibleStackLimit = Math.max(visibleToasts - 1, 0)}
406
+ {@const maxVisibleStackIndex = Math.min(
407
+ Math.max(activeToasts.length - 1, 0),
408
+ visibleStackLimit,
409
+ )}
410
+ {@const lastVisibleToastId = activeToasts[maxVisibleStackIndex]?.id}
411
+ {@const lastVisibleRenderIndex = lastVisibleToastId != null
412
+ ? positionToasts.findIndex(
413
+ (candidate) => candidate.id === lastVisibleToastId,
414
+ )
415
+ : -1}
416
+ {@const sharedHiddenCollapsedOffset =
417
+ lastVisibleRenderIndex >= 0
418
+ ? collapsedOffsets?.[lastVisibleRenderIndex]
419
+ : undefined}
420
+ {#each positionToasts as toast, idx (toast.id)}
421
+ {@const toastIsHidden =
422
+ toast.index >= visibleToasts}
423
+ {@const hiddenCollapsedOffset = toastIsHidden
424
+ ? sharedHiddenCollapsedOffset ?? collapsedOffsets?.[idx]
425
+ : collapsedOffsets?.[idx]}
426
+ {@const collapsedOffsetValue = collapsedOffsets?.[idx]}
427
+ <VarselItem
428
+ {toast}
429
+ {onRemove}
430
+ isGroupHovered={isGroupActive}
431
+ expandedOffset={expandedOffsets?.[idx] ?? 0}
432
+ {expandedGap}
433
+ onHeightChange={handleHeightChange}
434
+ onGroupHoverEnter={() => {
435
+ hovered = { ...hovered, [pos]: true };
436
+ }}
437
+ onGroupHoldChange={(holding) =>
438
+ updateHoldState(pos, toast.id, holding)}
439
+ collapsedOffset={collapsedOffsetValue}
440
+ hiddenCollapsedOffset={hiddenCollapsedOffset}
441
+ defaultDuration={duration}
442
+ defaultShowClose={closeButton}
443
+ {pauseOnHover}
444
+ {offset}
445
+ {expand}
446
+ {visibleToasts}
447
+ />
448
+ {/each}
449
+ {/each}
450
+ </div>
451
+ {/if}
@@ -0,0 +1,18 @@
1
+ import { type ToastData, type ToastPosition } from "./internals";
2
+ type $$ComponentProps = {
3
+ toasts?: ToastData[];
4
+ onRemove: (id: string) => void;
5
+ expandedGap?: number;
6
+ position?: ToastPosition;
7
+ visibleToasts?: number;
8
+ expand?: boolean;
9
+ duration?: number;
10
+ closeButton?: boolean;
11
+ pauseOnHover?: boolean;
12
+ offset?: number | string;
13
+ dir?: 'ltr' | 'rtl' | 'auto';
14
+ };
15
+ declare const VarselManager: import("svelte").Component<$$ComponentProps, {}, "">;
16
+ type VarselManager = ReturnType<typeof VarselManager>;
17
+ export default VarselManager;
18
+ //# sourceMappingURL=VarselManager.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VarselManager.svelte.d.ts","sourceRoot":"","sources":["../src/lib/VarselManager.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,EAGN,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,MAAM,aAAa,CAAC;AAEpB,KAAK,gBAAgB,GAAI;IACzB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;CAC7B,CAAC;AA4ZF,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -0,0 +1,104 @@
1
+ <script lang="ts" module>
2
+ /**
3
+ * Main module exports for the Varsel library.
4
+ */
5
+ export {
6
+ toast,
7
+ type ToastData,
8
+ type ToastInvoker,
9
+ type ToastPosition,
10
+ } from "./internals";
11
+ </script>
12
+
13
+ <script lang="ts">
14
+ /**
15
+ * @component
16
+ * @description
17
+ * The root component for the Varsel notification system.
18
+ * It subscribes to the global toast state and renders the `VarselManager`
19
+ * which handles the positioning and layout of individual toasts.
20
+ *
21
+ * Place this component once in your application's root layout (e.g., `+layout.svelte`).
22
+ */
23
+ import { onMount } from 'svelte';
24
+ import VarselManager from './VarselManager.svelte';
25
+ import {
26
+ toastState,
27
+ toasterInstanceManager,
28
+ type ToastData,
29
+ type ToastPosition,
30
+ } from './internals';
31
+
32
+ let {
33
+ expandedGap = undefined,
34
+ position = 'bottom-center',
35
+ visibleToasts = 3,
36
+ expand = true,
37
+ duration = 5000,
38
+ closeButton = true,
39
+ pauseOnHover = true,
40
+ offset = undefined,
41
+ dir = 'auto'
42
+ }: {
43
+ /**
44
+ * The gap (in pixels) between expanded toasts when hovering over the stack.
45
+ * If undefined, uses the default value from animation config.
46
+ */
47
+ expandedGap?: number;
48
+ /** Default position for toasts. */
49
+ position?: ToastPosition;
50
+ /** Maximum number of visible toasts in the stack. */
51
+ visibleToasts?: number;
52
+ /** Whether to expand the stack on hover. */
53
+ expand?: boolean;
54
+ /** Default duration in milliseconds. */
55
+ duration?: number;
56
+ /** Whether to show the close button by default. */
57
+ closeButton?: boolean;
58
+ /** Whether to pause the timer on hover. */
59
+ pauseOnHover?: boolean;
60
+ /** Offset from the edge of the screen. */
61
+ offset?: number | string;
62
+ /** Directionality of the text. */
63
+ dir?: 'ltr' | 'rtl' | 'auto';
64
+ } = $props();
65
+
66
+ let toasts = $state<ToastData[]>([]);
67
+ let instanceId = $state<string | null>(null);
68
+
69
+ const handleRemove = (id: string) => {
70
+ toastState.remove(id);
71
+ };
72
+
73
+ onMount(() => {
74
+ const registeredInstanceId = toasterInstanceManager.registerInstance();
75
+ instanceId = registeredInstanceId;
76
+ toasts = toastState.getToasts();
77
+ const unsubscribe = toastState.subscribe((value) => {
78
+ toasts = value;
79
+ });
80
+ return () => {
81
+ unsubscribe();
82
+ toasterInstanceManager.unregisterInstance(registeredInstanceId);
83
+ if (instanceId === registeredInstanceId) {
84
+ instanceId = null;
85
+ }
86
+ };
87
+ });
88
+ </script>
89
+
90
+ {#if instanceId && toasterInstanceManager.isActiveInstance(instanceId)}
91
+ <VarselManager
92
+ {toasts}
93
+ onRemove={handleRemove}
94
+ {expandedGap}
95
+ {position}
96
+ {visibleToasts}
97
+ {expand}
98
+ {duration}
99
+ {closeButton}
100
+ {pauseOnHover}
101
+ {offset}
102
+ {dir}
103
+ />
104
+ {/if}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Main module exports for the Varsel library.
3
+ */
4
+ export { toast, type ToastData, type ToastInvoker, type ToastPosition, } from "./internals";
5
+ import { type ToastPosition } from './internals';
6
+ type $$ComponentProps = {
7
+ /**
8
+ * The gap (in pixels) between expanded toasts when hovering over the stack.
9
+ * If undefined, uses the default value from animation config.
10
+ */
11
+ expandedGap?: number;
12
+ /** Default position for toasts. */
13
+ position?: ToastPosition;
14
+ /** Maximum number of visible toasts in the stack. */
15
+ visibleToasts?: number;
16
+ /** Whether to expand the stack on hover. */
17
+ expand?: boolean;
18
+ /** Default duration in milliseconds. */
19
+ duration?: number;
20
+ /** Whether to show the close button by default. */
21
+ closeButton?: boolean;
22
+ /** Whether to pause the timer on hover. */
23
+ pauseOnHover?: boolean;
24
+ /** Offset from the edge of the screen. */
25
+ offset?: number | string;
26
+ /** Directionality of the text. */
27
+ dir?: 'ltr' | 'rtl' | 'auto';
28
+ };
29
+ declare const VarselToaster: import("svelte").Component<$$ComponentProps, {}, "">;
30
+ type VarselToaster = ReturnType<typeof VarselToaster>;
31
+ export default VarselToaster;
32
+ //# sourceMappingURL=VarselToaster.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VarselToaster.svelte.d.ts","sourceRoot":"","sources":["../src/lib/VarselToaster.svelte.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,OAAO,EACN,KAAK,EACL,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,aAAa,GAClB,MAAM,aAAa,CAAC;AAcrB,OAAO,EAIL,KAAK,aAAa,EAClB,MAAM,aAAa,CAAC;AAErB,KAAK,gBAAgB,GAAI;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2CAA2C;IAC3C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,kCAAkC;IAClC,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;CAC7B,CAAC;AAmDH,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * CSS selectors used to identify focusable elements within a toast.
3
+ * Used for managing keyboard focus when interacting with toasts containing actions.
4
+ */
5
+ export declare const FOCUSABLE_SELECTORS: string;
6
+ //# sourceMappingURL=accessibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibility.d.ts","sourceRoot":"","sources":["../../src/lib/core/accessibility.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QAOpB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * CSS selectors used to identify focusable elements within a toast.
3
+ * Used for managing keyboard focus when interacting with toasts containing actions.
4
+ */
5
+ export const FOCUSABLE_SELECTORS = [
6
+ "button:not([disabled])",
7
+ "input:not([disabled])",
8
+ "textarea:not([disabled])",
9
+ "select:not([disabled])",
10
+ "a[href]",
11
+ '[tabindex]:not([tabindex="-1"])',
12
+ ].join(", ");
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Global configuration constants for toast animations and stacking behavior.
3
+ * These values control timing, spacing, scaling, and easing of toast transitions.
4
+ */
5
+ export declare const ANIMATION_CONFIG: {
6
+ /** Duration of the entry animation in seconds. */
7
+ readonly ENTER_DURATION: 0.75;
8
+ /** Duration of the exit animation in seconds. */
9
+ readonly EXIT_DURATION: 0.75;
10
+ /** Duration of the stack reorganization animation in seconds. */
11
+ readonly STACK_DURATION: 0.75;
12
+ /** Vertical offset (in pixels) between stacked toasts in collapsed state. */
13
+ readonly STACK_OFFSET: 16;
14
+ /** Vertical gap (in pixels) between toasts in expanded (hover) state. */
15
+ readonly EXPANDED_GAP: 12;
16
+ /** Scale reduction factor for each subsequent toast in the stack. */
17
+ readonly SCALE_FACTOR: 0.04;
18
+ /** Minimum scale value for the furthest toast in the stack. */
19
+ readonly MIN_SCALE: 0.92;
20
+ /** Maximum number of toasts visible in the stack at once. */
21
+ readonly MAX_VISIBLE_TOASTS: 3;
22
+ /** Base z-index for the toast layer. */
23
+ readonly Z_INDEX_BASE: 50;
24
+ /** Default cubic-bezier easing function for animations. */
25
+ readonly EASING_DEFAULT: "var(--ease-vs-toast)";
26
+ /** Easing function for exit animations. */
27
+ readonly EASING_EXIT: "var(--ease-vs-toast)";
28
+ };
29
+ //# sourceMappingURL=animations.d.ts.map