varsel 0.2.1 → 0.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.
@@ -39,34 +39,36 @@ let {
39
39
  onHeightChange = undefined,
40
40
  onGroupHoverEnter = undefined,
41
41
  onGroupHoldChange = undefined,
42
+ defaultDuration = 5000,
43
+ defaultShowClose = true,
44
+ pauseOnHover = true,
45
+ offset = undefined,
46
+ expand = true,
47
+ visibleToasts = ANIMATION_CONFIG.MAX_VISIBLE_TOASTS
42
48
  }: {
43
- /** The toast data object containing all content and state. */
44
49
  toast: PositionedToast;
45
- /** Callback to remove the toast from the DOM after exit animation. */
46
50
  onRemove: (id: string) => void;
47
- /** Whether the parent group (stack) is currently hovered. */
48
51
  isGroupHovered?: boolean;
49
- /** The vertical offset for this toast when the stack is expanded. */
50
52
  expandedOffset?: number;
51
- /** The gap between toasts when expanded. */
52
53
  expandedGap?: number;
53
- /** The vertical offset for this toast when the stack is collapsed. */
54
54
  collapsedOffset?: number;
55
- /** The offset to use when the toast is hidden in the stack. */
56
55
  hiddenCollapsedOffset?: number;
57
- /** Callback to report the height of the toast to the manager. */
58
56
  onHeightChange?: (id: string, height: number) => void;
59
- /** Callback to notify the manager that the user has entered the toast area. */
60
57
  onGroupHoverEnter?: () => void;
61
- /** Callback to notify the manager that the user is interacting (holding) the toast. */
62
58
  onGroupHoldChange?: (holding: boolean) => void;
59
+ defaultDuration?: number;
60
+ defaultShowClose?: boolean;
61
+ pauseOnHover?: boolean;
62
+ offset?: number | string;
63
+ expand?: boolean;
64
+ visibleToasts?: number;
63
65
  } = $props();
64
66
 
65
67
  let id = $derived(toast.id);
66
68
  let title = $derived(toast.title);
67
69
  let description = $derived(toast.description);
68
70
  let variant = $derived(toast.variant || "default");
69
- let duration = $derived(toast.duration || 5000);
71
+ let duration = $derived(toast.duration || defaultDuration);
70
72
  let action = $derived(toast.action);
71
73
  let isLoading = $derived(toast.isLoading || false);
72
74
  let index = $derived(toast.index);
@@ -75,7 +77,7 @@ let shouldClose = $derived(toast.shouldClose);
75
77
  let position = $derived(toast.position || "bottom-center");
76
78
  let className = $derived(toast.className || "");
77
79
  let onClose = $derived(toast.onClose);
78
- let showClose = $derived(toast.showClose ?? true);
80
+ let showClose = $derived(toast.showClose ?? defaultShowClose);
79
81
 
80
82
  let toastRef = $state<HTMLDivElement | null>(null);
81
83
  let isItemHovered = $state(false);
@@ -312,8 +314,9 @@ $effect(() => {
312
314
  remainingTime = duration;
313
315
  }
314
316
 
317
+ const isHovering = isGroupHovered || isItemHovered;
315
318
  const isPaused =
316
- isGroupHovered || isItemHovered || isSwiping || hiddenByStacking;
319
+ (pauseOnHover && isHovering) || isSwiping || hiddenByStacking;
317
320
 
318
321
  if (isPaused) {
319
322
  if (timeoutRef) {
@@ -520,7 +523,7 @@ const zIndexBase = Number(ANIMATION_CONFIG.Z_INDEX_BASE);
520
523
 
521
524
  let isTopPosition = $derived(position?.startsWith("top-") ?? false);
522
525
  let maxVisibleIndex = $derived(
523
- Math.max(0, ANIMATION_CONFIG.MAX_VISIBLE_TOASTS - 1),
526
+ Math.max(0, visibleToasts - 1),
524
527
  );
525
528
  let visibleIndex = $derived(Math.min(index, maxVisibleIndex));
526
529
  let defaultCollapsedOffset = $derived(
@@ -549,7 +552,7 @@ let visibleScale = $derived(
549
552
  ),
550
553
  );
551
554
  let zIndex = $derived(zIndexBase - renderIndex);
552
- let stackHidden = $derived(index >= ANIMATION_CONFIG.MAX_VISIBLE_TOASTS);
555
+ let stackHidden = $derived(index >= visibleToasts);
553
556
  let hiddenByStacking = $derived(stackHidden && animationState !== "exiting");
554
557
  let isStackLeader = $derived(index === 0);
555
558
  let isLatest = $derived(isStackLeader && !shouldClose);
@@ -581,12 +584,12 @@ let transformStyle = $derived.by(() => {
581
584
  let opacityValue = stackHidden ? 0 : 1;
582
585
 
583
586
  if (stackHidden) {
584
- if (isGroupHovered && animationState !== "exiting") {
587
+ if (expand && isGroupHovered && animationState !== "exiting") {
585
588
  translateX = 0;
586
589
  translateY = hiddenExpandedTranslateY;
587
590
  scaleValue = 1;
588
591
  }
589
- } else if (isGroupHovered && animationState !== "exiting") {
592
+ } else if (expand && isGroupHovered && animationState !== "exiting") {
590
593
  translateX = 0;
591
594
  translateY = expandedTranslateY;
592
595
  scaleValue = 1;
@@ -684,6 +687,14 @@ let livePoliteness = $derived(
684
687
  (variant === "destructive" ? "assertive" : "polite") as "assertive" | "polite",
685
688
  );
686
689
 
690
+ let offsetStyle = $derived.by(() => {
691
+ if (offset === undefined) return undefined;
692
+ const val = typeof offset === "number" ? `${offset}px` : offset;
693
+ if (position.startsWith("top")) return `top: ${val};`;
694
+ if (position.startsWith("bottom")) return `bottom: ${val};`;
695
+ return undefined;
696
+ });
697
+
687
698
  const handleBlurCapture = (event: FocusEvent) => {
688
699
  const next = event.relatedTarget as Node | null;
689
700
  if (!toastRef || !next || !toastRef.contains(next)) {
@@ -709,6 +720,7 @@ const handleBlurCapture = (event: FocusEvent) => {
709
720
  : `transform ${transitionDuration} ${transitionTimingFunction}, opacity ${transitionDuration} ${transitionTimingFunction}`}
710
721
  style:transform={transformStyle.transform}
711
722
  style:opacity={transformStyle.opacity}
723
+ style={offsetStyle}
712
724
  role={stackHidden ? undefined : liveRole}
713
725
  aria-live={stackHidden ? undefined : livePoliteness}
714
726
  aria-atomic={stackHidden ? undefined : "true"}
@@ -720,7 +732,7 @@ const handleBlurCapture = (event: FocusEvent) => {
720
732
  >
721
733
  <div
722
734
  role="presentation"
723
- class={cn(swipeCursorClass)}
735
+ class={cn(swipeCursorClass, "touch-none")}
724
736
  aria-busy={isLoading ? "true" : undefined}
725
737
  onpointerdown={handlePointerDown}
726
738
  onpointermove={handlePointerMove}
@@ -734,141 +746,146 @@ const handleBlurCapture = (event: FocusEvent) => {
734
746
  onfocuscapture={() => (isItemHovered = true)}
735
747
  onblurcapture={handleBlurCapture}
736
748
  >
737
- <div class={cn(toastContentVariants({ variant }))}>
738
- {#if showClose}
739
- <button
740
- type="button"
741
- onclick={handleClose}
742
- class={cn(
743
- "absolute top-2 right-2 cursor-pointer rounded-vs-sm p-1 text-vs-foreground/45 hover:bg-vs-popover-muted hover:text-vs-foreground/70 transition-[background-color,color,box-shadow] ease-vs-button duration-100 focus-visible:ring-1 focus-visible:ring-vs-ring/50 focus-visible:outline-none",
744
- )}
745
- aria-label="Close toast"
746
- >
747
- <svg
748
- aria-hidden="true"
749
- class="h-4 w-4"
750
- viewBox="0 0 24 24"
751
- fill="none"
752
- stroke="currentColor"
753
- stroke-width="2"
754
- stroke-linecap="round"
755
- stroke-linejoin="round"
756
- >
757
- <line x1="18" x2="6" y1="6" y2="18" />
758
- <line x1="6" x2="18" y1="6" y2="18" />
759
- </svg>
760
- </button>
761
- {/if}
762
-
763
- <div class="p-4 pr-8">
764
- <div class="flex gap-3">
765
- {#if showStatusIcon}
766
- <span class="relative inline-flex h-4 w-4 shrink-0 items-center justify-center">
767
- {#if shouldRenderSpinner}
768
- <span
769
- class={cn(
770
- "vs-spinner absolute inset-0",
771
- spinnerState === "loading"
772
- ? "vs-spinner--active"
773
- : "vs-spinner--finish",
774
- )}
775
- role={spinnerState === "loading" ? "status" : undefined}
776
- aria-label={spinnerState === "loading" ? "Loading..." : undefined}
777
- aria-live={spinnerState === "loading" ? "assertive" : undefined}
778
- onanimationend={handleSpinnerAnimationEnd}
779
- >
780
- <svg
781
- viewBox="0 0 256 256"
782
- fill="none"
783
- stroke="currentColor"
784
- stroke-width="24"
785
- stroke-linecap="round"
786
- stroke-linejoin="round"
787
- >
788
- <line x1="128" y1="32" x2="128" y2="64" />
789
- <line x1="195.9" y1="60.1" x2="173.3" y2="82.7" />
790
- <line x1="224" y1="128" x2="192" y2="128" />
791
- <line x1="195.9" y1="195.9" x2="173.3" y2="173.3" />
792
- <line x1="128" y1="224" x2="128" y2="192" />
793
- <line x1="60.1" y1="195.9" x2="82.7" y2="173.3" />
794
- <line x1="32" y1="128" x2="64" y2="128" />
795
- <line x1="60.1" y1="60.1" x2="82.7" y2="82.7" />
796
- </svg>
797
- </span>
798
- {/if}
799
- {#if iconConfig}
800
- <span
801
- class={cn(
802
- "vs-icon absolute inset-0 flex items-center justify-center",
803
- iconStateClass,
804
- )}
805
- aria-hidden="true"
806
- >
807
- <svg
808
- viewBox={iconConfig.viewBox}
809
- fill="none"
810
- stroke="currentColor"
811
- stroke-width="2"
812
- stroke-linecap="round"
813
- stroke-linejoin="round"
814
- >
815
- {#each iconConfig.elements as element, elementIndex (elementIndex)}
816
- {#if element.tag === "path"}
817
- <path d={element.d} />
818
- {:else if element.tag === "line"}
819
- <line
820
- x1={element.x1}
821
- y1={element.y1}
822
- x2={element.x2}
823
- y2={element.y2}
824
- />
825
- {:else if element.tag === "circle"}
826
- <circle
827
- cx={element.cx}
828
- cy={element.cy}
829
- r={element.r}
830
- />
831
- {/if}
832
- {/each}
833
- </svg>
834
- </span>
835
- {/if}
836
- </span>
837
- {/if}
838
- <div class="min-w-0">
839
- {#if title}
840
- <div
841
- id={titleId}
842
- class="mb-1 text-sm leading-none font-medium select-none"
843
- >
844
- {title}
845
- </div>
846
- {/if}
847
- {#if description}
848
- <div
849
- id={descriptionId}
850
- class="text-sm leading-snug text-vs-foreground/70 text-balance select-none"
851
- >
852
- {description}
853
- </div>
854
- {/if}
855
- {#if action}
856
- <div class="mt-3">
857
- <button
858
- type="button"
859
- onclick={() => {
860
- action.onClick();
861
- handleClose();
862
- }}
863
- class="relative inline-flex cursor-pointer items-center justify-center rounded-vs-md px-3 py-1.5 text-sm font-medium bg-vs-foreground text-vs-popover shadow-vs-button transition-[background-color,color,box-shadow] ease-vs-button duration-100 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:ring-offset-vs-ring-offset/50 focus-visible:outline-none focus-visible:ring-vs-ring/50"
864
- >
865
- {action.label}
866
- </button>
867
- </div>
868
- {/if}
869
- </div>
870
- </div>
871
- </div>
872
- </div>
749
+ {#if toast.component}
750
+ {@const Component = toast.component}
751
+ <Component {id} {toast} {...toast.componentProps} />
752
+ {:else}
753
+ <div class={cn(toastContentVariants({ variant }))}>
754
+ {#if showClose}
755
+ <button
756
+ type="button"
757
+ onclick={handleClose}
758
+ class={cn(
759
+ "absolute top-2 end-2 cursor-pointer rounded-vs-sm p-1 text-vs-foreground/45 hover:bg-vs-popover-muted hover:text-vs-foreground/70 transition-[background-color,color,box-shadow] ease-vs-button duration-100 focus-visible:ring-1 focus-visible:ring-vs-ring/50 focus-visible:outline-none",
760
+ )}
761
+ aria-label="Close toast"
762
+ >
763
+ <svg
764
+ aria-hidden="true"
765
+ class="h-4 w-4"
766
+ viewBox="0 0 24 24"
767
+ fill="none"
768
+ stroke="currentColor"
769
+ stroke-width="2"
770
+ stroke-linecap="round"
771
+ stroke-linejoin="round"
772
+ >
773
+ <line x1="18" x2="6" y1="6" y2="18" />
774
+ <line x1="6" x2="18" y1="6" y2="18" />
775
+ </svg>
776
+ </button>
777
+ {/if}
778
+
779
+ <div class="p-4 pe-8">
780
+ <div class="flex gap-3">
781
+ {#if showStatusIcon}
782
+ <span class="relative inline-flex h-4 w-4 shrink-0 items-center justify-center">
783
+ {#if shouldRenderSpinner}
784
+ <span
785
+ class={cn(
786
+ "vs-spinner absolute inset-0",
787
+ spinnerState === "loading"
788
+ ? "vs-spinner--active"
789
+ : "vs-spinner--finish",
790
+ )}
791
+ role={spinnerState === "loading" ? "status" : undefined}
792
+ aria-label={spinnerState === "loading" ? "Loading..." : undefined}
793
+ aria-live={spinnerState === "loading" ? "assertive" : undefined}
794
+ onanimationend={handleSpinnerAnimationEnd}
795
+ >
796
+ <svg
797
+ viewBox="0 0 256 256"
798
+ fill="none"
799
+ stroke="currentColor"
800
+ stroke-width="24"
801
+ stroke-linecap="round"
802
+ stroke-linejoin="round"
803
+ >
804
+ <line x1="128" y1="32" x2="128" y2="64" />
805
+ <line x1="195.9" y1="60.1" x2="173.3" y2="82.7" />
806
+ <line x1="224" y1="128" x2="192" y2="128" />
807
+ <line x1="195.9" y1="195.9" x2="173.3" y2="173.3" />
808
+ <line x1="128" y1="224" x2="128" y2="192" />
809
+ <line x1="60.1" y1="195.9" x2="82.7" y2="173.3" />
810
+ <line x1="32" y1="128" x2="64" y2="128" />
811
+ <line x1="60.1" y1="60.1" x2="82.7" y2="82.7" />
812
+ </svg>
813
+ </span>
814
+ {/if}
815
+ {#if iconConfig}
816
+ <span
817
+ class={cn(
818
+ "vs-icon absolute inset-0 flex items-center justify-center",
819
+ iconStateClass,
820
+ )}
821
+ aria-hidden="true"
822
+ >
823
+ <svg
824
+ viewBox={iconConfig.viewBox}
825
+ fill="none"
826
+ stroke="currentColor"
827
+ stroke-width="2"
828
+ stroke-linecap="round"
829
+ stroke-linejoin="round"
830
+ >
831
+ {#each iconConfig.elements as element, elementIndex (elementIndex)}
832
+ {#if element.tag === "path"}
833
+ <path d={element.d} />
834
+ {:else if element.tag === "line"}
835
+ <line
836
+ x1={element.x1}
837
+ y1={element.y1}
838
+ x2={element.x2}
839
+ y2={element.y2}
840
+ />
841
+ {:else if element.tag === "circle"}
842
+ <circle
843
+ cx={element.cx}
844
+ cy={element.cy}
845
+ r={element.r}
846
+ />
847
+ {/if}
848
+ {/each}
849
+ </svg>
850
+ </span>
851
+ {/if}
852
+ </span>
853
+ {/if}
854
+ <div class="min-w-0">
855
+ {#if title}
856
+ <div
857
+ id={titleId}
858
+ class="mb-1 text-sm leading-none font-medium select-none"
859
+ >
860
+ {title}
861
+ </div>
862
+ {/if}
863
+ {#if description}
864
+ <div
865
+ id={descriptionId}
866
+ class="text-sm leading-snug text-vs-foreground/70 text-balance select-none"
867
+ >
868
+ {description}
869
+ </div>
870
+ {/if}
871
+ {#if action}
872
+ <div class="mt-3">
873
+ <button
874
+ type="button"
875
+ onclick={() => {
876
+ action.onClick();
877
+ handleClose();
878
+ }}
879
+ class="relative inline-flex cursor-pointer items-center justify-center rounded-vs-md px-3 py-1.5 text-sm font-medium bg-vs-foreground text-vs-popover shadow-vs-button transition-[background-color,color,box-shadow] ease-vs-button duration-100 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:ring-offset-vs-ring-offset/50 focus-visible:outline-none focus-visible:ring-vs-ring/50"
880
+ >
881
+ {action.label}
882
+ </button>
883
+ </div>
884
+ {/if}
885
+ </div>
886
+ </div>
887
+ </div>
888
+ </div>
889
+ {/if}
873
890
  </div>
874
891
  </div>
@@ -1,25 +1,21 @@
1
1
  import { type PositionedToast } from "./internals";
2
2
  type $$ComponentProps = {
3
- /** The toast data object containing all content and state. */
4
3
  toast: PositionedToast;
5
- /** Callback to remove the toast from the DOM after exit animation. */
6
4
  onRemove: (id: string) => void;
7
- /** Whether the parent group (stack) is currently hovered. */
8
5
  isGroupHovered?: boolean;
9
- /** The vertical offset for this toast when the stack is expanded. */
10
6
  expandedOffset?: number;
11
- /** The gap between toasts when expanded. */
12
7
  expandedGap?: number;
13
- /** The vertical offset for this toast when the stack is collapsed. */
14
8
  collapsedOffset?: number;
15
- /** The offset to use when the toast is hidden in the stack. */
16
9
  hiddenCollapsedOffset?: number;
17
- /** Callback to report the height of the toast to the manager. */
18
10
  onHeightChange?: (id: string, height: number) => void;
19
- /** Callback to notify the manager that the user has entered the toast area. */
20
11
  onGroupHoverEnter?: () => void;
21
- /** Callback to notify the manager that the user is interacting (holding) the toast. */
22
12
  onGroupHoldChange?: (holding: boolean) => void;
13
+ defaultDuration?: number;
14
+ defaultShowClose?: boolean;
15
+ pauseOnHover?: boolean;
16
+ offset?: number | string;
17
+ expand?: boolean;
18
+ visibleToasts?: number;
23
19
  };
24
20
  declare const VarselItem: import("svelte").Component<$$ComponentProps, {}, "">;
25
21
  type VarselItem = ReturnType<typeof VarselItem>;
@@ -1 +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;AAQpB,KAAK,gBAAgB,GAAI;IACzB,8DAA8D;IAC9D,KAAK,EAAE,eAAe,CAAC;IACvB,sEAAsE;IACtE,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,6DAA6D;IAC7D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,iEAAiE;IACjE,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,uFAAuF;IACvF,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/C,CAAC;AA6uBF,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
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;AAQpB,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;AAiwBF,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -18,13 +18,26 @@ let {
18
18
  toasts = [],
19
19
  onRemove,
20
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'
21
29
  }: {
22
- /** The list of all active toasts from the global state. */
23
30
  toasts?: ToastData[];
24
- /** Callback to remove a toast from the state. */
25
31
  onRemove: (id: string) => void;
26
- /** The gap in pixels between toasts when expanded. */
27
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';
28
41
  } = $props();
29
42
 
30
43
  const createPositionMap = <T>(value: () => T): Record<ToastPosition, T> => ({
@@ -90,7 +103,7 @@ const updateHoldState = (
90
103
  $effect(() => {
91
104
  const grouped = createPositionMap<ToastData[]>(() => []);
92
105
  for (const toast of toasts) {
93
- const pos = toast.position || "bottom-center";
106
+ const pos = toast.position || defaultPosition;
94
107
  grouped[pos].push(toast);
95
108
  }
96
109
 
@@ -118,6 +131,7 @@ $effect(() => {
118
131
 
119
132
  return {
120
133
  ...toast,
134
+ position: position,
121
135
  index: stackIndex,
122
136
  renderIndex: orderIndex,
123
137
  total: list.length,
@@ -289,7 +303,7 @@ $effect(() => {
289
303
  let bottom = Number.NEGATIVE_INFINITY;
290
304
  let any = false;
291
305
  for (const t of group) {
292
- if (t.index >= ANIMATION_CONFIG.MAX_VISIBLE_TOASTS) continue;
306
+ if (t.index >= visibleToasts) continue;
293
307
  const el = document.querySelector(
294
308
  `[data-toast-id="${t.id}"]`,
295
309
  ) as HTMLElement | null;
@@ -356,7 +370,10 @@ const handleHeightChange = (id: string, height: number) => {
356
370
  </script>
357
371
 
358
372
  {#if toasts.length > 0}
359
- <div class="pointer-events-none fixed inset-0 z-50">
373
+ <div
374
+ class="pointer-events-none fixed inset-0 z-50"
375
+ {dir}
376
+ >
360
377
  {#each positionEntries as [position, positionToasts]}
361
378
  {@const pos = position}
362
379
  {@const expandedOffsets = expandedOffsetData.byPosition[pos]}
@@ -365,7 +382,7 @@ const handleHeightChange = (id: string, height: number) => {
365
382
  {@const isHeld = (heldToasts[pos]?.size ?? 0) > 0}
366
383
  {@const isGroupActive = isHovered || isHeld}
367
384
  {@const activeToasts = positionToasts.filter((toast) => !toast.shouldClose)}
368
- {@const visibleStackLimit = Math.max(ANIMATION_CONFIG.MAX_VISIBLE_TOASTS - 1, 0)}
385
+ {@const visibleStackLimit = Math.max(visibleToasts - 1, 0)}
369
386
  {@const maxVisibleStackIndex = Math.min(
370
387
  Math.max(activeToasts.length - 1, 0),
371
388
  visibleStackLimit,
@@ -382,7 +399,7 @@ const handleHeightChange = (id: string, height: number) => {
382
399
  : undefined}
383
400
  {#each positionToasts as toast, idx (toast.id)}
384
401
  {@const toastIsHidden =
385
- toast.index >= ANIMATION_CONFIG.MAX_VISIBLE_TOASTS}
402
+ toast.index >= visibleToasts}
386
403
  {@const hiddenCollapsedOffset = toastIsHidden
387
404
  ? sharedHiddenCollapsedOffset ?? collapsedOffsets?.[idx]
388
405
  : collapsedOffsets?.[idx]}
@@ -401,6 +418,12 @@ const handleHeightChange = (id: string, height: number) => {
401
418
  updateHoldState(pos, toast.id, holding)}
402
419
  collapsedOffset={collapsedOffsetValue}
403
420
  hiddenCollapsedOffset={hiddenCollapsedOffset}
421
+ defaultDuration={duration}
422
+ defaultShowClose={closeButton}
423
+ {pauseOnHover}
424
+ {offset}
425
+ {expand}
426
+ {visibleToasts}
404
427
  />
405
428
  {/each}
406
429
  {/each}
@@ -1,11 +1,16 @@
1
- import { type ToastData } from "./internals";
1
+ import { type ToastData, type ToastPosition } from "./internals";
2
2
  type $$ComponentProps = {
3
- /** The list of all active toasts from the global state. */
4
3
  toasts?: ToastData[];
5
- /** Callback to remove a toast from the state. */
6
4
  onRemove: (id: string) => void;
7
- /** The gap in pixels between toasts when expanded. */
8
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';
9
14
  };
10
15
  declare const VarselManager: import("svelte").Component<$$ComponentProps, {}, "">;
11
16
  type VarselManager = ReturnType<typeof VarselManager>;
@@ -1 +1 @@
1
- {"version":3,"file":"VarselManager.svelte.d.ts","sourceRoot":"","sources":["../src/lib/VarselManager.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,EAGN,KAAK,SAAS,EAEd,MAAM,aAAa,CAAC;AAEpB,KAAK,gBAAgB,GAAI;IACzB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,iDAAiD;IACjD,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AA8XF,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
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;AAuYF,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -25,14 +25,41 @@ export {
25
25
  toastState,
26
26
  toasterInstanceManager,
27
27
  type ToastData,
28
+ type ToastPosition,
28
29
  } from './internals';
29
30
 
30
- let { expandedGap = undefined }: {
31
+ let {
32
+ expandedGap = undefined,
33
+ position = 'bottom-center',
34
+ visibleToasts = 3,
35
+ expand = true,
36
+ duration = 5000,
37
+ closeButton = true,
38
+ pauseOnHover = true,
39
+ offset = undefined,
40
+ dir = 'auto'
41
+ }: {
31
42
  /**
32
43
  * The gap (in pixels) between expanded toasts when hovering over the stack.
33
44
  * If undefined, uses the default value from animation config.
34
45
  */
35
- expandedGap?: number
46
+ expandedGap?: number;
47
+ /** Default position for toasts. */
48
+ position?: ToastPosition;
49
+ /** Maximum number of visible toasts in the stack. */
50
+ visibleToasts?: number;
51
+ /** Whether to expand the stack on hover. */
52
+ expand?: boolean;
53
+ /** Default duration in milliseconds. */
54
+ duration?: number;
55
+ /** Whether to show the close button by default. */
56
+ closeButton?: boolean;
57
+ /** Whether to pause the timer on hover. */
58
+ pauseOnHover?: boolean;
59
+ /** Offset from the edge of the screen. */
60
+ offset?: number | string;
61
+ /** Directionality of the text. */
62
+ dir?: 'ltr' | 'rtl' | 'auto';
36
63
  } = $props();
37
64
 
38
65
  let toasts = $state<ToastData[]>([]);
@@ -55,9 +82,17 @@ export {
55
82
  </script>
56
83
 
57
84
  {#if toasterInstanceManager.isActiveInstance(instanceId)}
58
- {#if expandedGap === undefined}
59
- <VarselManager {toasts} onRemove={handleRemove} />
60
- {:else}
61
- <VarselManager {toasts} onRemove={handleRemove} {expandedGap} />
62
- {/if}
85
+ <VarselManager
86
+ {toasts}
87
+ onRemove={handleRemove}
88
+ {expandedGap}
89
+ {position}
90
+ {visibleToasts}
91
+ {expand}
92
+ {duration}
93
+ {closeButton}
94
+ {pauseOnHover}
95
+ {offset}
96
+ {dir}
97
+ />
63
98
  {/if}
@@ -2,12 +2,29 @@
2
2
  * Main module exports for the Varsel library.
3
3
  */
4
4
  export { toast, type ToastData, type ToastInvoker, type ToastPosition, } from "./internals";
5
+ import { type ToastPosition } from './internals';
5
6
  type $$ComponentProps = {
6
7
  /**
7
8
  * The gap (in pixels) between expanded toasts when hovering over the stack.
8
9
  * If undefined, uses the default value from animation config.
9
10
  */
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';
11
28
  };
12
29
  declare const VarselToaster: import("svelte").Component<$$ComponentProps, {}, "">;
13
30
  type VarselToaster = ReturnType<typeof VarselToaster>;
@@ -1 +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;AAmBpB,KAAK,gBAAgB,GAAI;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACpB,CAAC;AAuCH,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
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;AAarB,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;AA6CH,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"toast-factory.d.ts","sourceRoot":"","sources":["../../src/lib/core/toast-factory.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAGX,YAAY,EAEZ,MAAM,SAAS,CAAC;AAoIjB,eAAO,MAAM,KAAK,cAAc,CAAC"}
1
+ {"version":3,"file":"toast-factory.d.ts","sourceRoot":"","sources":["../../src/lib/core/toast-factory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGX,YAAY,EAEZ,MAAM,SAAS,CAAC;AAoJjB,eAAO,MAAM,KAAK,cAAc,CAAC"}
@@ -1,7 +1,3 @@
1
- /**
2
- * Factory module for creating and managing toast notifications.
3
- * Provides the main `toast` function and its variants (success, error, promise).
4
- */
5
1
  import { toastState } from "./toast-state";
6
2
  /**
7
3
  * Helper to normalize string input into a ToastData object.
@@ -16,8 +12,8 @@ const normalizeToastData = (data) => {
16
12
  * Resolves the state of a promise-based toast (success or error) into actual toast data.
17
13
  */
18
14
  const resolvePromiseState = async (value, state) => {
19
- const resolved = typeof state === "function" ? await state(value) : await state;
20
- return normalizeToastData(resolved);
15
+ const resolvedValue = typeof state === "function" ? await state(value) : await state;
16
+ return normalizeToastData(resolvedValue);
21
17
  };
22
18
  /**
23
19
  * The main entry point for creating toasts.
@@ -54,6 +50,19 @@ createToast.error = (data) => {
54
50
  }
55
51
  return toastState.add({ ...data, variant: "destructive" });
56
52
  };
53
+ /**
54
+ * Creates a custom component toast.
55
+ * @param component - The Svelte component to render.
56
+ * @param options - Additional options and props for the component.
57
+ */
58
+ createToast.custom = (component, // Type inferred from ToastInvoker
59
+ options) => {
60
+ return toastState.add({
61
+ ...(options ?? {}),
62
+ component: component,
63
+ variant: "custom",
64
+ });
65
+ };
57
66
  /**
58
67
  * Creates a toast that tracks a promise's lifecycle.
59
68
  * Updates automatically from loading -> success/error.
@@ -1,4 +1,5 @@
1
1
  import type { VariantProps } from "class-variance-authority";
2
+ import type { Component } from "svelte";
2
3
  import type { toastContainerVariants } from "./variants";
3
4
  import type { ToastPosition } from "./positions";
4
5
  import type { SwipeAxis, SwipeDirection } from "./swipe";
@@ -38,6 +39,10 @@ export interface ToastData extends VariantProps<typeof toastContainerVariants> {
38
39
  isLeaving?: boolean;
39
40
  /** The position on the screen where this toast should appear. */
40
41
  position?: ToastPosition;
42
+ /** Custom Svelte component to render instead of the default toast layout. */
43
+ component?: Component<any>;
44
+ /** Props to pass to the custom component. */
45
+ componentProps?: Record<string, any>;
41
46
  }
42
47
  /**
43
48
  * Represents the possible states for a promise-based toast.
@@ -77,6 +82,14 @@ export type ToastInvoker = {
77
82
  * Creates an error toast notification.
78
83
  */
79
84
  error: (data: Omit<ToastData, "id" | "variant"> | string) => string;
85
+ /**
86
+ * Creates a custom component toast.
87
+ * @param component - The Svelte component to render.
88
+ * @param options - Additional options and props for the component.
89
+ */
90
+ custom: <Props extends Record<string, any> = Record<string, any>>(component: Component<Props>, options?: Omit<ToastData, "id" | "component" | "variant" | "componentProps"> & {
91
+ componentProps?: Omit<Props, "id" | "toast">;
92
+ }) => string;
80
93
  /**
81
94
  * Creates a toast that updates based on the state of a Promise.
82
95
  * @param promise - The promise to track.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/core/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/core/types.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@
5
5
  */
6
6
  export declare const toastContainerVariants: (props?: ({
7
7
  position?: "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right" | null | undefined;
8
- variant?: "default" | "success" | "warning" | "destructive" | null | undefined;
8
+ variant?: "default" | "success" | "warning" | "destructive" | "custom" | null | undefined;
9
9
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
10
10
  /**
11
11
  * CVA definition for the inner content wrapper of the toast.
@@ -13,6 +13,6 @@ export declare const toastContainerVariants: (props?: ({
13
13
  * separate from the structural container.
14
14
  */
15
15
  export declare const toastContentVariants: (props?: ({
16
- variant?: "default" | "success" | "warning" | "destructive" | null | undefined;
16
+ variant?: "default" | "success" | "warning" | "destructive" | "custom" | null | undefined;
17
17
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
18
18
  //# sourceMappingURL=variants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"variants.d.ts","sourceRoot":"","sources":["../../src/lib/core/variants.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;8EAgClC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;8EAY/B,CAAC"}
1
+ {"version":3,"file":"variants.d.ts","sourceRoot":"","sources":["../../src/lib/core/variants.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;8EAqClC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;8EAa/B,CAAC"}
@@ -4,7 +4,7 @@ import { cva } from "class-variance-authority";
4
4
  * Handles positioning logic (absolute/fixed positioning coordinates)
5
5
  * and base theming (colors based on variant).
6
6
  */
7
- export const toastContainerVariants = cva("pointer-events-auto fixed rounded-vs-lg border shadow-vs-toast will-change-transform border-vs-border bg-vs-popover", {
7
+ export const toastContainerVariants = cva("pointer-events-auto fixed will-change-transform", {
8
8
  variants: {
9
9
  /**
10
10
  * Determines where the toast is anchored on the screen.
@@ -21,10 +21,11 @@ export const toastContainerVariants = cva("pointer-events-auto fixed rounded-vs-
21
21
  * Semantic variant of the toast affecting text colors.
22
22
  */
23
23
  variant: {
24
- default: "text-vs-foreground",
25
- success: "text-vs-success/90",
26
- warning: "text-vs-warning/90",
27
- destructive: "text-vs-destructive/90",
24
+ default: "rounded-vs-lg border shadow-vs-toast border-vs-border bg-vs-popover text-vs-foreground",
25
+ success: "rounded-vs-lg border shadow-vs-toast border-vs-border bg-vs-popover text-vs-success/90",
26
+ warning: "rounded-vs-lg border shadow-vs-toast border-vs-border bg-vs-popover text-vs-warning/90",
27
+ destructive: "rounded-vs-lg border shadow-vs-toast border-vs-border bg-vs-popover text-vs-destructive/90",
28
+ custom: "",
28
29
  },
29
30
  },
30
31
  defaultVariants: {
@@ -44,6 +45,7 @@ export const toastContentVariants = cva("relative overflow-hidden rounded-vs-lg"
44
45
  success: "",
45
46
  warning: "",
46
47
  destructive: "",
48
+ custom: "",
47
49
  },
48
50
  },
49
51
  defaultVariants: {
package/dist/styles.css CHANGED
@@ -1,2 +1,192 @@
1
- /*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--spacing:.25rem;--container-sm:24rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--font-weight-medium:500;--leading-snug:1.375;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-vs-popover:var(--vs-popover);--color-vs-popover-muted:var(--vs-popover-muted);--color-vs-foreground:var(--vs-foreground);--color-vs-border:var(--vs-border);--color-vs-ring:var(--vs-ring);--color-vs-ring-offset:var(--vs-ring-offset);--color-vs-destructive:var(--vs-destructive);--color-vs-warning:var(--vs-warning);--color-vs-success:var(--vs-success);--shadow-vs-button:var(--shadow-vs-button);--shadow-vs-toast:var(--shadow-vs-toast);--radius-vs-sm:calc(var(--radius-base)*2);--radius-vs-md:calc(var(--radius-base)*3);--radius-vs-lg:calc(var(--radius-base)*4);--ease-vs-button:var(--ease-vs-button);--ease-vs-toast:var(--ease-vs-toast)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing)*0)}.top-2{top:calc(var(--spacing)*2)}.top-4{top:calc(var(--spacing)*4)}.right-2{right:calc(var(--spacing)*2)}.right-4{right:calc(var(--spacing)*4)}.bottom-4{bottom:calc(var(--spacing)*4)}.left-1\/2{left:50%}.left-4{left:calc(var(--spacing)*4)}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mt-3{margin-top:calc(var(--spacing)*3)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.flex{display:flex}.hidden{display:none}.inline-flex{display:inline-flex}.h-4{height:calc(var(--spacing)*4)}.w-4{width:calc(var(--spacing)*4)}.w-full{width:100%}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:calc(var(--spacing)*0)}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x:calc(calc(1/2*100%)*-1);translate:var(--tw-translate-x)var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.cursor-grab{cursor:grab}.cursor-grabbing{cursor:grabbing}.cursor-pointer{cursor:pointer}.items-center{align-items:center}.justify-center{justify-content:center}.gap-3{gap:calc(var(--spacing)*3)}.overflow-hidden{overflow:hidden}.rounded-vs-lg{border-radius:var(--radius-vs-lg)}.rounded-vs-md{border-radius:var(--radius-vs-md)}.rounded-vs-sm{border-radius:var(--radius-vs-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-vs-border{border-color:var(--color-vs-border)}.bg-vs-foreground{background-color:var(--color-vs-foreground)}.bg-vs-popover{background-color:var(--color-vs-popover)}.p-1{padding:calc(var(--spacing)*1)}.p-4{padding:calc(var(--spacing)*4)}.px-3{padding-inline:calc(var(--spacing)*3)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.pr-8{padding-right:calc(var(--spacing)*8)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.leading-none{--tw-leading:1;line-height:1}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.text-balance{text-wrap:balance}.text-vs-destructive\/90{color:var(--color-vs-destructive)}@supports (color:color-mix(in lab, red, red)){.text-vs-destructive\/90{color:color-mix(in oklab,var(--color-vs-destructive)90%,transparent)}}.text-vs-foreground,.text-vs-foreground\/45{color:var(--color-vs-foreground)}@supports (color:color-mix(in lab, red, red)){.text-vs-foreground\/45{color:color-mix(in oklab,var(--color-vs-foreground)45%,transparent)}}.text-vs-foreground\/70{color:var(--color-vs-foreground)}@supports (color:color-mix(in lab, red, red)){.text-vs-foreground\/70{color:color-mix(in oklab,var(--color-vs-foreground)70%,transparent)}}.text-vs-popover{color:var(--color-vs-popover)}.text-vs-success\/90{color:var(--color-vs-success)}@supports (color:color-mix(in lab, red, red)){.text-vs-success\/90{color:color-mix(in oklab,var(--color-vs-success)90%,transparent)}}.text-vs-warning\/90{color:var(--color-vs-warning)}@supports (color:color-mix(in lab, red, red)){.text-vs-warning\/90{color:color-mix(in oklab,var(--color-vs-warning)90%,transparent)}}.shadow-vs-button{--tw-shadow:var(--shadow-vs-button);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-vs-toast{--tw-shadow:var(--shadow-vs-toast);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.transition-\[background-color\,color\,box-shadow\]{transition-property:background-color,color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.ease-vs-button{--tw-ease:var(--ease-vs-button);transition-timing-function:var(--ease-vs-button)}.will-change-transform{will-change:transform}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.hover\:bg-vs-popover-muted:hover{background-color:var(--color-vs-popover-muted)}.hover\:text-vs-foreground\/70:hover{color:var(--color-vs-foreground)}@supports (color:color-mix(in lab, red, red)){.hover\:text-vs-foreground\/70:hover{color:color-mix(in oklab,var(--color-vs-foreground)70%,transparent)}}}.focus-visible\:ring-1:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-vs-ring\/50:focus-visible{--tw-ring-color:var(--color-vs-ring)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-vs-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab,var(--color-vs-ring)50%,transparent)}}.focus-visible\:ring-offset-1:focus-visible{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.focus-visible\:ring-offset-vs-ring-offset\/50:focus-visible{--tw-ring-offset-color:var(--color-vs-ring-offset)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-offset-vs-ring-offset\/50:focus-visible{--tw-ring-offset-color:color-mix(in oklab,var(--color-vs-ring-offset)50%,transparent)}}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}}:root{--base-hue:265;--color-vs-popover:oklch(100% 0 0);--color-vs-popover-muted:oklch(.96 .002 var(--base-hue));--color-vs-foreground:oklch(.1408 .0044 var(--base-hue));--color-vs-border:oklch(.8925 .0014 var(--base-hue));--color-vs-ring:oklch(.55 .012 var(--base-hue));--color-vs-ring-offset:oklch(.96 .002 var(--base-hue));--color-vs-destructive:oklch(62% .21 25);--color-vs-warning:oklch(80% .2 75);--color-vs-success:oklch(70% .18 155);--shadow-vs-button:0px 1px 1px -.5px #00000026,0px 3px 3px -1.5px #0000000d;--shadow-vs-toast:0px 1px 1px -.5px #00000026,0px 3px 3px -1.5px #0000000d,0px 6px 6px -3px #0000000d,0px 12px 12px -6px #0000000d,0px 24px 24px -12px #0000000d,0px 48px 48px -24px #0000000d;--radius-base:.125rem;--ease-vs-button:cubic-bezier(.25,.46,.45,.94);--ease-vs-toast:cubic-bezier(.32,.72,0,1)}.dark{--color-vs-popover:oklch(.2139 .0101 var(--base-hue));--color-vs-popover-muted:oklch(.2502 .016 var(--base-hue));--color-vs-foreground:oklch(.9824 .0013 var(--base-hue));--color-vs-border:oklch(.278 .015 var(--base-hue));--color-vs-ring:oklch(.58 .012 var(--base-hue));--color-vs-ring-offset:oklch(.15 .005 var(--base-hue));--color-vs-destructive:oklch(72% .27 25);--color-vs-warning:oklch(82% .24 85);--color-vs-success:oklch(78% .25 155)}.vs-spinner{transform-origin:50%;flex-shrink:0;justify-content:center;align-items:center;width:1rem;height:1rem;display:inline-flex;position:absolute;inset:0}.vs-spinner--active{opacity:1}.vs-spinner--finish{animation:.42s cubic-bezier(.32,.72,0,1) forwards vs-spinner-finish}.vs-spinner svg{width:100%;height:100%;animation:1s linear infinite vs-spin}.vs-icon{flex-shrink:0;justify-content:center;align-items:center;width:1rem;height:1rem;display:inline-flex;position:absolute;inset:0}.vs-icon--static{opacity:1;transform:scale(1)}.vs-icon--waiting{opacity:0;transform:scale(.75)rotate(-6deg)}.vs-icon--pop{animation:.36s cubic-bezier(.18,.89,.32,1.28) forwards vs-icon-pop}.vs-icon svg{width:100%;height:100%}@keyframes vs-spin{to{transform:rotate(360deg)}}@keyframes vs-spinner-finish{0%{opacity:1;filter:blur();transform:scale(1)rotate(0)}60%{opacity:.65;filter:blur(.3px);transform:scale(.55)rotate(140deg)}to{opacity:0;filter:blur(.8px);transform:scale(0)rotate(220deg)}}@keyframes vs-icon-pop{0%{opacity:0;filter:blur(2px);transform:scale(.5)rotate(-10deg)}60%{opacity:1;filter:blur();transform:scale(1.18)rotate(2deg)}to{opacity:1;filter:blur();transform:scale(1)rotate(0)}}@media (prefers-reduced-motion:reduce){.vs-spinner svg{animation-duration:2s}.vs-spinner--finish{animation-duration:0s}.vs-icon--pop{opacity:1;animation:none;transform:scale(1)}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}
1
+ /*
2
+ * Main stylesheet for Varsel.
3
+ * Built with Tailwind CSS v4 using the @theme directive.
4
+ *
5
+ * Defines custom CSS variables for colors, shadows, and animations.
6
+ * Supports light and dark modes via the .dark class (standard Tailwind approach).
7
+ */
8
+
9
+ @import "tailwindcss";
10
+ @source "./**/*.{svelte,js,ts}";
11
+
12
+ :root {
13
+ /* Base hue used for generating the color palette (oklch) */
14
+ --base-hue: 265;
15
+
16
+ /* Semantic color tokens */
17
+ --color-vs-popover: oklch(1 0 0);
18
+ --color-vs-popover-muted: oklch(0.96 0.002 var(--base-hue));
19
+ --color-vs-foreground: oklch(0.1408 0.0044 var(--base-hue));
20
+ --color-vs-border: oklch(0.8925 0.0014 var(--base-hue));
21
+ --color-vs-ring: oklch(0.55 0.012 var(--base-hue));
22
+ --color-vs-ring-offset: oklch(0.96 0.002 var(--base-hue));
23
+ --color-vs-destructive: oklch(0.62 0.21 25);
24
+ --color-vs-warning: oklch(0.8 0.2 75);
25
+ --color-vs-success: oklch(0.7 0.18 155);
26
+
27
+ /* Shadows */
28
+ --shadow-vs-button:
29
+ 0px 1px 1px -0.5px rgba(0, 0, 0, 0.15), 0px 3px 3px -1.5px
30
+ rgba(0, 0, 0, 0.05);
31
+ --shadow-vs-toast:
32
+ 0px 1px 1px -0.5px rgba(0, 0, 0, 0.15),
33
+ 0px 3px 3px -1.5px rgba(0, 0, 0, 0.05),
34
+ 0px 6px 6px -3px rgba(0, 0, 0, 0.05),
35
+ 0px 12px 12px -6px rgba(0, 0, 0, 0.05),
36
+ 0px 24px 24px -12px rgba(0, 0, 0, 0.05),
37
+ 0px 48px 48px -24px rgba(0, 0, 0, 0.05);
38
+
39
+ /* Radius & Easing */
40
+ --radius-base: 0.125rem;
41
+ --ease-vs-button: cubic-bezier(0.25, 0.46, 0.45, 0.94);
42
+ --ease-vs-toast: cubic-bezier(0.32, 0.72, 0, 1);
43
+ --ease-vs-pop: cubic-bezier(0.18, 0.89, 0.32, 1.28);
44
+ }
45
+
46
+ .dark {
47
+ --color-vs-popover: oklch(0.2139 0.0101 var(--base-hue));
48
+ --color-vs-popover-muted: oklch(0.2502 0.016 var(--base-hue));
49
+ --color-vs-foreground: oklch(0.9824 0.0013 var(--base-hue));
50
+ --color-vs-border: oklch(0.278 0.015 var(--base-hue));
51
+ --color-vs-ring: oklch(0.58 0.012 var(--base-hue));
52
+ --color-vs-ring-offset: oklch(0.15 0.005 var(--base-hue));
53
+ --color-vs-destructive: oklch(0.72 0.27 25);
54
+ --color-vs-warning: oklch(0.82 0.24 85);
55
+ --color-vs-success: oklch(0.78 0.25 155);
56
+ }
57
+
58
+ @theme {
59
+ --color-vs-popover: var(--vs-popover);
60
+ --color-vs-popover-muted: var(--vs-popover-muted);
61
+ --color-vs-foreground: var(--vs-foreground);
62
+ --color-vs-border: var(--vs-border);
63
+ --color-vs-ring: var(--vs-ring);
64
+ --color-vs-ring-offset: var(--vs-ring-offset);
65
+ --color-vs-destructive: var(--vs-destructive);
66
+ --color-vs-warning: var(--vs-warning);
67
+ --color-vs-success: var(--vs-success);
68
+ --shadow-vs-button: var(--shadow-vs-button);
69
+ --shadow-vs-toast: var(--shadow-vs-toast);
70
+ --radius-vs-sm: calc(var(--radius-base) * 2);
71
+ --radius-vs-md: calc(var(--radius-base) * 3);
72
+ --radius-vs-lg: calc(var(--radius-base) * 4);
73
+ --ease-vs-button: var(--ease-vs-button);
74
+ --ease-vs-toast: var(--ease-vs-toast);
75
+ --ease-vs-pop: var(--ease-vs-pop);
76
+ }
77
+
78
+ /* Spinner Styles */
79
+ .vs-spinner {
80
+ display: inline-flex;
81
+ width: 1rem;
82
+ height: 1rem;
83
+ align-items: center;
84
+ justify-content: center;
85
+ flex-shrink: 0;
86
+ position: absolute;
87
+ inset: 0;
88
+ transform-origin: center;
89
+ }
90
+
91
+ .vs-spinner--active {
92
+ opacity: 1;
93
+ }
94
+
95
+ .vs-spinner--finish {
96
+ animation: vs-spinner-finish 0.42s var(--ease-vs-toast) forwards;
97
+ }
98
+
99
+ .vs-spinner svg {
100
+ width: 100%;
101
+ height: 100%;
102
+ animation: vs-spin 1s linear infinite;
103
+ }
104
+
105
+ /* Icon Styles */
106
+ .vs-icon {
107
+ display: inline-flex;
108
+ width: 1rem;
109
+ height: 1rem;
110
+ align-items: center;
111
+ justify-content: center;
112
+ flex-shrink: 0;
113
+ position: absolute;
114
+ inset: 0;
115
+ }
116
+
117
+ .vs-icon--static {
118
+ opacity: 1;
119
+ transform: scale(1);
120
+ }
121
+
122
+ .vs-icon--waiting {
123
+ opacity: 0;
124
+ transform: scale(0.75) rotate(-6deg);
125
+ }
126
+
127
+ .vs-icon--pop {
128
+ animation: vs-icon-pop 0.36s var(--ease-vs-pop) forwards;
129
+ }
130
+
131
+ .vs-icon svg {
132
+ width: 100%;
133
+ height: 100%;
134
+ }
135
+
136
+ @keyframes vs-spin {
137
+ to {
138
+ transform: rotate(360deg);
139
+ }
140
+ }
141
+
142
+ @keyframes vs-spinner-finish {
143
+ 0% {
144
+ opacity: 1;
145
+ transform: scale(1) rotate(0deg);
146
+ filter: blur(0);
147
+ }
148
+ 60% {
149
+ opacity: 0.65;
150
+ transform: scale(0.55) rotate(140deg);
151
+ filter: blur(0.3px);
152
+ }
153
+ 100% {
154
+ opacity: 0;
155
+ transform: scale(0) rotate(220deg);
156
+ filter: blur(0.8px);
157
+ }
158
+ }
159
+
160
+ @keyframes vs-icon-pop {
161
+ 0% {
162
+ opacity: 0;
163
+ transform: scale(0.5) rotate(-10deg);
164
+ filter: blur(2px);
165
+ }
166
+ 60% {
167
+ opacity: 1;
168
+ transform: scale(1.18) rotate(2deg);
169
+ filter: blur(0);
170
+ }
171
+ 100% {
172
+ opacity: 1;
173
+ transform: scale(1) rotate(0deg);
174
+ filter: blur(0);
175
+ }
176
+ }
177
+
178
+ @media (prefers-reduced-motion: reduce) {
179
+ .vs-spinner svg {
180
+ animation-duration: 2s;
181
+ }
182
+
183
+ .vs-spinner--finish {
184
+ animation-duration: 0s;
185
+ }
186
+
187
+ .vs-icon--pop {
188
+ animation: none;
189
+ opacity: 1;
190
+ transform: scale(1);
191
+ }
192
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "varsel",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "Headless yet opinionated toast notifications for Svelte apps.",
5
5
  "type": "module",
6
6
  "license": "MIT",