Skip to content

Commit 2472c76

Browse files
authored
Add index paramter to toast for proper overlap styling (#4268)
1 parent 6253ea6 commit 2472c76

File tree

7 files changed

+98
-33
lines changed

7 files changed

+98
-33
lines changed

.changeset/twelve-symbols-wave.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@skeletonlabs/skeleton-react": minor
3+
"@skeletonlabs/skeleton-svelte": minor
4+
---
5+
6+
bugfix: Support proper Toast styling when using the `overlap` option.
7+

packages/skeleton-react/src/components/toast/anatomy/group.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import type { HTMLAttributes } from '../../../internal/html-attributes.js';
22
import type { PropsWithElement } from '../../../internal/props-with-element.js';
33
import { GroupContext } from '../modules/group-context.js';
4+
import type { ToastOptions } from './root.js';
45
import { mergeProps, normalizeProps, useMachine } from '@zag-js/react';
56
import { group } from '@zag-js/toast';
67
import type { Props, Store } from '@zag-js/toast';
78
import type { JSX } from 'react';
89
import { useId } from 'react';
910

11+
export type ToastProps<T = any> = Props<T> & ToastOptions<T>;
12+
1013
export interface ToastGroupProps extends PropsWithElement<'div'>, HTMLAttributes<'div', 'id' | 'dir' | 'children'> {
1114
toaster: Store;
12-
children?: (toast: Props) => JSX.Element | null;
15+
children?: (toast: ToastProps) => JSX.Element | null;
1316
}
1417

1518
export default function Group(props: ToastGroupProps) {
@@ -25,7 +28,7 @@ export default function Group(props: ToastGroupProps) {
2528

2629
return (
2730
<GroupContext.Provider value={service}>
28-
{element ? element(attributes) : <div {...attributes}>{api.getToasts().map((toast) => children?.(toast))}</div>}
31+
{element ? element(attributes) : <div {...attributes}>{api.getToasts().map((toast, index) => children?.({ ...toast, index }))}</div>}
2932
</GroupContext.Provider>
3033
);
3134
}

packages/skeleton-react/src/components/toast/anatomy/root.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@ import { connect, machine } from '@zag-js/toast';
77
import type { Options } from '@zag-js/toast';
88
import { use } from 'react';
99

10+
export interface ToastOptions<T = any> extends Options<T> {
11+
index: number;
12+
}
13+
1014
export interface ToastRootProps extends PropsWithElement<'div'>, HTMLAttributes<'div', 'id' | 'dir'> {
11-
toast: Omit<Options, 'id' | 'parent'>;
15+
toast: Omit<ToastOptions, 'id' | 'parent'>;
16+
index?: number;
1217
}
1318

1419
export default function Root(props: ToastRootProps) {

packages/skeleton-svelte/src/components/toast/anatomy/group.svelte

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
<script lang="ts" module>
22
import type { HTMLAttributes } from '../../../internal/html-attributes.js';
33
import type { PropsWithElement } from '../../../internal/props-with-element.js';
4+
import type { ToastOptions } from './root.svelte';
45
import type { Props, Store } from '@zag-js/toast';
56
import type { Snippet } from 'svelte';
67
8+
export type ToastProps<T = any> = Props<T> & ToastOptions<T>;
9+
710
export interface ToastGroupProps extends PropsWithElement<'div'>, HTMLAttributes<'div', 'id' | 'dir' | 'children'> {
811
toaster: Store;
9-
children?: Snippet<[Props]>;
12+
children?: Snippet<[ToastProps]>;
1013
}
1114
</script>
1215

@@ -35,8 +38,8 @@
3538
{@render element(attributes)}
3639
{:else}
3740
<div {...attributes}>
38-
{#each api.getToasts() as toast (toast.id)}
39-
{@render children?.(toast)}
41+
{#each api.getToasts() as toast, index (toast.id)}
42+
{@render children?.({ ...toast, index })}
4043
{/each}
4144
</div>
4245
{/if}

packages/skeleton-svelte/src/components/toast/anatomy/root.svelte

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
import type { PropsWithElement } from '../../../internal/props-with-element.js';
44
import type { Options } from '@zag-js/toast';
55
6+
export interface ToastOptions<T = any> extends Options<T> {
7+
index: number;
8+
}
9+
610
export interface ToastRootProps extends PropsWithElement<'div'>, HTMLAttributes<'div', 'id' | 'dir'> {
7-
toast: Options;
11+
toast: ToastOptions;
812
}
913
</script>
1014

playgrounds/skeleton-react/src/routes/components/toast/index.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,22 @@
22

33
import { Toast, createToaster } from '@skeletonlabs/skeleton-react';
44
import { createFileRoute } from '@tanstack/react-router';
5+
import { useEffect, useState } from 'react';
56

67
export const Route = createFileRoute('/components/toast/')({
78
component: Page,
89
});
910

1011
function Page() {
11-
const toaster = createToaster();
12+
const [overlap, setOverlap] = useState(false);
13+
const [duration, setDuration] = useState<number>(Infinity);
14+
15+
const [toaster] = useState(createToaster({ overlap }));
16+
17+
useEffect(() => {
18+
toaster.attrs.overlap = overlap;
19+
}, [toaster.attrs.overlap, overlap]);
20+
1221
return (
1322
<>
1423
<button
@@ -18,12 +27,28 @@ function Page() {
1827
title: 'Toast',
1928
description: 'This is a toast message.',
2029
action: { label: 'Undo', onClick: () => {} },
21-
duration: Infinity,
30+
duration,
2231
})
2332
}
2433
>
2534
Toast
2635
</button>
36+
37+
<label className="label">
38+
<span className="label-text">Options</span>
39+
<div className="rounded-container border border-surface-200-800 p-2 flex flex-col gap-2">
40+
<label className="flex items-center space-x-2">
41+
<input className="checkbox" type="checkbox" checked={overlap} onChange={(e) => setOverlap(e.currentTarget.checked)} />
42+
<span>Overlap</span>
43+
</label>
44+
45+
<label className="label">
46+
<span className="label-text">Duration (ms)</span>
47+
<input className="input w-32" type="number" value={duration} onChange={(e) => setDuration(e.currentTarget.valueAsNumber)} />
48+
</label>
49+
</div>
50+
</label>
51+
2752
<Toast.Group toaster={toaster}>
2853
{(toast) => (
2954
<Toast toast={toast} key={toast.id}>
Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,51 @@
11
<script lang="ts">
22
import { Toast, createToaster } from '@skeletonlabs/skeleton-svelte';
33
4-
const toaster = createToaster();
5-
</script>
4+
let overlap = $state(false);
5+
let duration: number = $state(Infinity);
6+
7+
let toaster = $derived(createToaster({ overlap }));
68
7-
<button
8-
class="btn preset-filled"
9-
onclick={() =>
9+
const createToast = () => {
1010
toaster.info({
1111
title: 'Toast',
1212
description: 'This is a toast message.',
13-
duration: Infinity,
13+
duration,
1414
action: { label: 'Undo', onClick: () => toaster.success({ title: 'Undone' }) },
15-
})}
16-
>
17-
Toast
18-
</button>
15+
});
16+
};
17+
</script>
18+
19+
<button class="btn preset-filled" onclick={createToast}> Toast </button>
20+
21+
<label class="label">
22+
<span class="label-text">Options</span>
23+
<div class="rounded-container border border-surface-200-800 p-2 flex flex-col gap-2">
24+
<label class="flex items-center space-x-2">
25+
<input class="checkbox" type="checkbox" bind:checked={overlap} />
26+
<span>Overlap</span>
27+
</label>
28+
29+
<label class="label">
30+
<span class="label-text">Duration (ms)</span>
31+
<input class="input w-32" type="number" bind:value={duration} />
32+
</label>
33+
</div>
34+
</label>
1935

20-
<Toast.Group {toaster}>
21-
{#snippet children(toast)}
22-
<Toast {toast}>
23-
<Toast.Message>
24-
<Toast.Title>{toast.title}</Toast.Title>
25-
<Toast.Description>{toast.description}</Toast.Description>
26-
</Toast.Message>
27-
{#if toast.action}
28-
<Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>
29-
{/if}
30-
<Toast.CloseTrigger />
31-
</Toast>
32-
{/snippet}
33-
</Toast.Group>
36+
{#key toaster}
37+
<Toast.Group {toaster}>
38+
{#snippet children(toast)}
39+
<Toast {toast}>
40+
<Toast.Message>
41+
<Toast.Title>{toast.title}</Toast.Title>
42+
<Toast.Description>{toast.description}</Toast.Description>
43+
</Toast.Message>
44+
{#if toast.action}
45+
<Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>
46+
{/if}
47+
<Toast.CloseTrigger />
48+
</Toast>
49+
{/snippet}
50+
</Toast.Group>
51+
{/key}

0 commit comments

Comments
 (0)